]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
Replace a lot of idle and timeout calls by the new gdk_threads api.
[~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   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2748   pointer_position = get_pointer_position (notebook);
2749
2750   element = get_drop_position (notebook, notebook->cur_page->pack);
2751   reorder_tab (notebook, element, notebook->focus_tab);
2752   first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2753                                         (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2754                                         TRUE);
2755   if (first_tab)
2756     {
2757       notebook->first_tab = first_tab;
2758       gtk_notebook_pages_allocate (notebook);
2759
2760       gdk_window_move_resize (priv->drag_window,
2761                               priv->drag_window_x,
2762                               priv->drag_window_y,
2763                               notebook->cur_page->allocation.width,
2764                               notebook->cur_page->allocation.height);
2765       gdk_window_raise (priv->drag_window);
2766     }
2767
2768   return TRUE;
2769 }
2770
2771 static gboolean
2772 check_threshold (GtkNotebook *notebook,
2773                  gint         current_x,
2774                  gint         current_y)
2775 {
2776   GtkWidget *widget;
2777   gint dnd_threshold;
2778   GdkRectangle rectangle = { 0, }; /* shut up gcc */
2779   GtkSettings *settings;
2780   
2781   widget = GTK_WIDGET (notebook);
2782   settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2783   g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2784
2785   /* we want a large threshold */
2786   dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2787
2788   gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2789   gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2790
2791   rectangle.x -= dnd_threshold;
2792   rectangle.width += 2 * dnd_threshold;
2793   rectangle.y -= dnd_threshold;
2794   rectangle.height += 2 * dnd_threshold;
2795
2796   return (current_x < rectangle.x ||
2797           current_x > rectangle.x + rectangle.width ||
2798           current_y < rectangle.y ||
2799           current_y > rectangle.y + rectangle.height);
2800 }
2801
2802 static gint
2803 gtk_notebook_motion_notify (GtkWidget      *widget,
2804                             GdkEventMotion *event)
2805 {
2806   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2807   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2808   GtkNotebookPage *page;
2809   GtkNotebookArrow arrow;
2810   GtkNotebookPointerPosition pointer_position;
2811   GtkSettings *settings;
2812   guint timeout;
2813
2814   page = notebook->cur_page;
2815
2816   if (!page)
2817     return FALSE;
2818
2819   if (!(event->state & GDK_BUTTON1_MASK) &&
2820       priv->pressed_button != -1)
2821     {
2822       gtk_notebook_stop_reorder (notebook);
2823       stop_scrolling (notebook);
2824     }
2825
2826   if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2827     return FALSE;
2828
2829   priv->timestamp = event->time;
2830   gdk_window_get_pointer (widget->window,
2831                           &priv->mouse_x,
2832                           &priv->mouse_y,
2833                           NULL);
2834
2835   arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2836   if (arrow != notebook->in_child)
2837     {
2838       notebook->in_child = arrow;
2839       gtk_notebook_redraw_arrows (notebook);
2840     }
2841
2842   if (priv->pressed_button == -1)
2843     return FALSE;
2844
2845   if (page->detachable &&
2846       check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2847     {
2848       priv->detached_tab = notebook->cur_page;
2849       priv->during_detach = TRUE;
2850
2851       gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2852                       priv->pressed_button, (GdkEvent*) event);
2853       return TRUE;
2854     }
2855
2856   if (page->reorderable &&
2857       (priv->during_reorder ||
2858        gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2859     {
2860       priv->during_reorder = TRUE;
2861       pointer_position = get_pointer_position (notebook);
2862
2863       if (event->window == priv->drag_window &&
2864           pointer_position != POINTER_BETWEEN &&
2865           gtk_notebook_show_arrows (notebook))
2866         {
2867           /* scroll tabs */
2868           if (!priv->dnd_timer)
2869             {
2870               priv->has_scrolled = TRUE;
2871               settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2872               g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2873
2874               priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2875                                                scroll_notebook_timer, 
2876                                                (gpointer) notebook);
2877             }
2878         }
2879       else
2880         {
2881           if (priv->dnd_timer)
2882             {
2883               g_source_remove (priv->dnd_timer);
2884               priv->dnd_timer = 0;
2885             }
2886         }
2887
2888       if (event->window == priv->drag_window ||
2889           priv->operation != DRAG_OPERATION_REORDER)
2890         {
2891           /* the drag operation is beginning, create the window */
2892           if (priv->operation != DRAG_OPERATION_REORDER)
2893             {
2894               priv->operation = DRAG_OPERATION_REORDER;
2895               show_drag_window (notebook, priv, page);
2896             }
2897
2898           gtk_notebook_pages_allocate (notebook);
2899           gdk_window_move_resize (priv->drag_window,
2900                                   priv->drag_window_x,
2901                                   priv->drag_window_y,
2902                                   page->allocation.width,
2903                                   page->allocation.height);
2904         }
2905     }
2906
2907   return TRUE;
2908 }
2909
2910 static void
2911 gtk_notebook_grab_notify (GtkWidget *widget,
2912                           gboolean   was_grabbed)
2913 {
2914   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2915
2916   if (!was_grabbed)
2917     {
2918       gtk_notebook_stop_reorder (notebook);
2919       stop_scrolling (notebook);
2920     }
2921 }
2922
2923 static void
2924 gtk_notebook_state_changed (GtkWidget    *widget,
2925                             GtkStateType  previous_state)
2926 {
2927   if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
2928     stop_scrolling (GTK_NOTEBOOK (widget));
2929 }
2930
2931 static gint
2932 gtk_notebook_focus_in (GtkWidget     *widget,
2933                        GdkEventFocus *event)
2934 {
2935   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2936
2937   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2938   
2939   return FALSE;
2940 }
2941
2942 static gint
2943 gtk_notebook_focus_out (GtkWidget     *widget,
2944                         GdkEventFocus *event)
2945 {
2946   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2947
2948   return FALSE;
2949 }
2950
2951 static void
2952 gtk_notebook_draw_focus (GtkWidget *widget)
2953 {
2954   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2955
2956   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2957       notebook->focus_tab)
2958     {
2959       GtkNotebookPage *page;
2960       GdkRectangle area;
2961       gint focus_width;
2962       
2963       gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2964
2965       page = notebook->focus_tab->data;
2966
2967       area.x = page->tab_label->allocation.x - focus_width;
2968       area.y = page->tab_label->allocation.y - focus_width;
2969       area.width = page->tab_label->allocation.width + 2 * focus_width;
2970       area.height = page->tab_label->allocation.height + 2 * focus_width;
2971
2972       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2973     }
2974 }
2975
2976 static void
2977 gtk_notebook_style_set  (GtkWidget *widget,
2978                          GtkStyle  *previous)
2979 {
2980   GtkNotebook *notebook;
2981
2982   gboolean has_before_previous;
2983   gboolean has_before_next;
2984   gboolean has_after_previous;
2985   gboolean has_after_next;
2986
2987   notebook = GTK_NOTEBOOK (widget);
2988   
2989   gtk_widget_style_get (widget,
2990                         "has-backward-stepper", &has_before_previous,
2991                         "has-secondary-forward-stepper", &has_before_next,
2992                         "has-secondary-backward-stepper", &has_after_previous,
2993                         "has-forward-stepper", &has_after_next,
2994                         NULL);
2995   
2996   notebook->has_before_previous = has_before_previous;
2997   notebook->has_before_next = has_before_next;
2998   notebook->has_after_previous = has_after_previous;
2999   notebook->has_after_next = has_after_next;
3000   
3001   (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3002 }
3003
3004 static gboolean
3005 on_drag_icon_expose (GtkWidget      *widget,
3006                      GdkEventExpose *event,
3007                      gpointer        data)
3008 {
3009   GtkWidget *notebook, *child = GTK_WIDGET (data);
3010   GtkRequisition requisition;
3011   gint gap_pos;
3012
3013   notebook = GTK_WIDGET (data);
3014   child = GTK_BIN (widget)->child;
3015   gtk_widget_size_request (widget, &requisition);
3016   gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3017
3018   gtk_paint_extension (notebook->style, widget->window,
3019                        GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3020                        NULL, widget, "tab",
3021                        0, 0,
3022                        requisition.width, requisition.height,
3023                        gap_pos);
3024   if (child)
3025     gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3026
3027   return TRUE;
3028 }
3029
3030 static void
3031 gtk_notebook_drag_begin (GtkWidget        *widget,
3032                          GdkDragContext   *context)
3033 {
3034   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3035   GtkNotebook *notebook = (GtkNotebook*) widget;
3036   GtkWidget *tab_label;
3037
3038   if (priv->dnd_timer)
3039     {
3040       g_source_remove (priv->dnd_timer);
3041       priv->dnd_timer = 0;
3042     }
3043
3044   priv->operation = DRAG_OPERATION_DETACH;
3045   gtk_notebook_pages_allocate (notebook);
3046
3047   tab_label = priv->detached_tab->tab_label;
3048
3049   hide_drag_window (notebook, priv, notebook->cur_page);
3050   g_object_ref (tab_label);
3051   gtk_widget_unparent (tab_label);
3052
3053   priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3054   gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3055   gtk_widget_set_size_request (priv->dnd_window,
3056                                priv->detached_tab->allocation.width,
3057                                priv->detached_tab->allocation.height);
3058   g_object_unref (tab_label);
3059
3060   g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3061                     G_CALLBACK (on_drag_icon_expose), notebook);
3062
3063   gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3064 }
3065
3066 static void
3067 gtk_notebook_drag_end (GtkWidget      *widget,
3068                        GdkDragContext *context)
3069 {
3070   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3071
3072   gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3073
3074   GTK_BIN (priv->dnd_window)->child = NULL;
3075   gtk_widget_destroy (priv->dnd_window);
3076   priv->dnd_window = NULL;
3077
3078   priv->operation = DRAG_OPERATION_NONE;
3079 }
3080
3081 static gboolean
3082 gtk_notebook_switch_tab_timeout (gpointer data)
3083 {
3084   GtkNotebook *notebook;
3085   GtkNotebookPrivate *priv;
3086   GList *tab;
3087   gint x, y;
3088
3089   notebook = GTK_NOTEBOOK (data);
3090   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3091
3092   priv->switch_tab_timer = 0;
3093   x = priv->mouse_x;
3094   y = priv->mouse_y;
3095
3096   if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3097     {
3098       /* FIXME: hack, we don't want the
3099        * focus to move fom the source widget
3100        */
3101       notebook->child_has_focus = FALSE;
3102       gtk_notebook_switch_focus_tab (notebook, tab);
3103     }
3104
3105   return FALSE;
3106 }
3107
3108 static gboolean
3109 gtk_notebook_drag_motion (GtkWidget      *widget,
3110                           GdkDragContext *context,
3111                           gint            x,
3112                           gint            y,
3113                           guint           time)
3114 {
3115   GtkNotebook *notebook;
3116   GtkNotebookPrivate *priv;
3117   GdkRectangle position;
3118   GtkSettings *settings;
3119   GtkNotebookArrow arrow;
3120   guint timeout;
3121   GdkAtom target, tab_target;
3122
3123   notebook = GTK_NOTEBOOK (widget);
3124   arrow = gtk_notebook_get_arrow (notebook,
3125                                   x + widget->allocation.x,
3126                                   y + widget->allocation.y);
3127   if (arrow)
3128     {
3129       notebook->click_child = arrow;
3130       gtk_notebook_set_scroll_timer (notebook);
3131       gdk_drag_status (context, 0, time);
3132       return TRUE;
3133     }
3134
3135   stop_scrolling (notebook);
3136   target = gtk_drag_dest_find_target (widget, context, NULL);
3137   tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3138
3139   if (target == tab_target)
3140     {
3141       gint widget_group, source_widget_group;
3142       GtkWidget *source_widget;
3143
3144       source_widget = gtk_drag_get_source_widget (context);
3145       g_assert (source_widget);
3146
3147       widget_group = gtk_notebook_get_group_id (notebook);
3148       source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3149
3150       if (widget_group != -1 &&
3151           source_widget_group != -1 &&
3152           widget_group == source_widget_group &&
3153           !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child || 
3154             gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3155         {
3156           gdk_drag_status (context, GDK_ACTION_MOVE, time);
3157           return TRUE;
3158         }
3159     }
3160
3161   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3162   x += widget->allocation.x;
3163   y += widget->allocation.y;
3164
3165   if (target == tab_target)
3166     {
3167       /* it's a tab, but doesn't share
3168        * ID with this notebook */
3169       gdk_drag_status (context, 0, time);
3170     }
3171
3172   if (gtk_notebook_get_event_window_position (notebook, &position) &&
3173       x >= position.x && x <= position.x + position.width &&
3174       y >= position.y && y <= position.y + position.height)
3175     {
3176       priv->mouse_x = x;
3177       priv->mouse_y = y;
3178
3179       if (!priv->switch_tab_timer)
3180         {
3181           settings = gtk_widget_get_settings (widget);
3182
3183           g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3184           priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3185                                                   gtk_notebook_switch_tab_timeout,
3186                                                   widget);
3187         }
3188     }
3189   else
3190     {
3191       if (priv->switch_tab_timer)
3192         {
3193           g_source_remove (priv->switch_tab_timer);
3194           priv->switch_tab_timer = 0;
3195         }
3196     }
3197
3198   return TRUE;
3199 }
3200
3201 static void
3202 gtk_notebook_drag_leave (GtkWidget      *widget,
3203                          GdkDragContext *context,
3204                          guint           time)
3205 {
3206   GtkNotebookPrivate *priv;
3207
3208   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3209
3210   if (priv->switch_tab_timer)
3211     {
3212       g_source_remove (priv->switch_tab_timer);
3213       priv->switch_tab_timer = 0;
3214     }
3215
3216   stop_scrolling (GTK_NOTEBOOK (widget));
3217 }
3218
3219 static gboolean
3220 gtk_notebook_drag_drop (GtkWidget        *widget,
3221                         GdkDragContext   *context,
3222                         gint              x,
3223                         gint              y,
3224                         guint             time)
3225 {
3226   GdkAtom target;
3227
3228   target = gtk_drag_dest_find_target (widget, context, NULL);
3229
3230   if (target == GDK_NONE)
3231     gtk_drag_finish (context, FALSE, FALSE, time);
3232
3233   return TRUE;
3234 }
3235
3236 static void
3237 do_detach_tab (GtkNotebook     *from,
3238                GtkNotebook     *to,
3239                GtkWidget       *child,
3240                gint             x,
3241                gint             y)
3242 {
3243   GtkNotebookPrivate *priv;
3244   GtkWidget *tab_label, *menu_label;
3245   gboolean tab_expand, tab_fill, reorderable, detachable;
3246   GList *element;
3247   guint tab_pack;
3248   gint page_num;
3249
3250   menu_label = gtk_notebook_get_menu_label (from, child);
3251
3252   if (menu_label)
3253     g_object_ref (menu_label);
3254
3255   tab_label = gtk_notebook_get_tab_label (from, child);
3256   
3257   if (tab_label)
3258     g_object_ref (tab_label);
3259
3260   g_object_ref (child);
3261
3262   gtk_container_child_get (GTK_CONTAINER (from),
3263                            child,
3264                            "tab-expand", &tab_expand,
3265                            "tab-fill", &tab_fill,
3266                            "tab-pack", &tab_pack,
3267                            "reorderable", &reorderable,
3268                            "detachable", &detachable,
3269                            NULL);
3270
3271   gtk_container_remove (GTK_CONTAINER (from), child);
3272
3273   priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3274   priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3275   priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3276
3277   element = get_drop_position (to, tab_pack);
3278   page_num = g_list_position (to->children, element);
3279   gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3280
3281   gtk_container_child_set (GTK_CONTAINER (to), child,
3282                            "tab-pack", tab_pack,
3283                            "tab-expand", tab_expand,
3284                            "tab-fill", tab_fill,
3285                            "reorderable", reorderable,
3286                            "detachable", detachable,
3287                            NULL);
3288   if (child)
3289     g_object_unref (child);
3290
3291   if (tab_label)
3292     g_object_unref (tab_label);
3293
3294   if (menu_label)
3295     g_object_unref (menu_label);
3296
3297   gtk_notebook_set_current_page (to, page_num);
3298 }
3299
3300 static void
3301 gtk_notebook_drag_data_get (GtkWidget        *widget,
3302                             GdkDragContext   *context,
3303                             GtkSelectionData *data,
3304                             guint             info,
3305                             guint             time)
3306 {
3307   GtkNotebook *dest_notebook, *notebook;
3308   GtkNotebookPrivate *priv;
3309
3310   if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3311       (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3312        !window_creation_hook))
3313     return;
3314
3315   notebook = GTK_NOTEBOOK (widget);
3316   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3317
3318   if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3319     {
3320       gtk_selection_data_set (data,
3321                               data->target,
3322                               8,
3323                               (void*) &priv->detached_tab->child,
3324                               sizeof (gpointer));
3325     }
3326   else
3327     {
3328       GdkDisplay *display;
3329       gint x, y;
3330
3331       display = gtk_widget_get_display (widget);
3332       gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3333
3334       dest_notebook = (* window_creation_hook) (notebook,
3335                                                 priv->detached_tab->child,
3336                                                 x, y,
3337                                                 window_creation_hook_data);
3338       if (dest_notebook)
3339         do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3340     }
3341 }
3342
3343 static void
3344 gtk_notebook_drag_data_received (GtkWidget        *widget,
3345                                  GdkDragContext   *context,
3346                                  gint              x,
3347                                  gint              y,
3348                                  GtkSelectionData *data,
3349                                  guint             info,
3350                                  guint             time)
3351 {
3352   GtkNotebook *notebook;
3353   GtkWidget *source_widget;
3354   GtkWidget **child;
3355
3356   notebook = GTK_NOTEBOOK (widget);
3357   source_widget = gtk_drag_get_source_widget (context);
3358
3359   if (source_widget &&
3360       data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3361     {
3362       child = (void*) data->data;
3363
3364       do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3365       gtk_drag_finish (context, TRUE, FALSE, time);
3366     }
3367   else
3368     gtk_drag_finish (context, FALSE, FALSE, time);
3369 }
3370
3371 /* Private GtkContainer Methods :
3372  * 
3373  * gtk_notebook_set_child_arg
3374  * gtk_notebook_get_child_arg
3375  * gtk_notebook_add
3376  * gtk_notebook_remove
3377  * gtk_notebook_focus
3378  * gtk_notebook_set_focus_child
3379  * gtk_notebook_child_type
3380  * gtk_notebook_forall
3381  */
3382 static void
3383 gtk_notebook_set_child_property (GtkContainer    *container,
3384                                  GtkWidget       *child,
3385                                  guint            property_id,
3386                                  const GValue    *value,
3387                                  GParamSpec      *pspec)
3388 {
3389   gboolean expand;
3390   gboolean fill;
3391   GtkPackType pack_type;
3392
3393   /* not finding child's page is valid for menus or labels */
3394   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3395     return;
3396
3397   switch (property_id)
3398     {
3399     case CHILD_PROP_TAB_LABEL:
3400       /* a NULL pointer indicates a default_tab setting, otherwise
3401        * we need to set the associated label
3402        */
3403       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3404                                        g_value_get_string (value));
3405       break;
3406     case CHILD_PROP_MENU_LABEL:
3407       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3408                                         g_value_get_string (value));
3409       break;
3410     case CHILD_PROP_POSITION:
3411       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3412                                   g_value_get_int (value));
3413       break;
3414     case CHILD_PROP_TAB_EXPAND:
3415       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3416                                             &expand, &fill, &pack_type);
3417       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3418                                           g_value_get_boolean (value),
3419                                           fill, pack_type);
3420       break;
3421     case CHILD_PROP_TAB_FILL:
3422       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3423                                             &expand, &fill, &pack_type);
3424       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3425                                           expand,
3426                                           g_value_get_boolean (value),
3427                                           pack_type);
3428       break;
3429     case CHILD_PROP_TAB_PACK:
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, fill,
3434                                           g_value_get_enum (value));
3435       break;
3436     case CHILD_PROP_REORDERABLE:
3437       gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3438                                         g_value_get_boolean (value));
3439       break;
3440     case CHILD_PROP_DETACHABLE:
3441       gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3442                                        g_value_get_boolean (value));
3443       break;
3444     default:
3445       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3446       break;
3447     }
3448 }
3449
3450 static void
3451 gtk_notebook_get_child_property (GtkContainer    *container,
3452                                  GtkWidget       *child,
3453                                  guint            property_id,
3454                                  GValue          *value,
3455                                  GParamSpec      *pspec)
3456 {
3457   GList *list;
3458   GtkNotebook *notebook;
3459   GtkWidget *label;
3460   gboolean expand;
3461   gboolean fill;
3462   GtkPackType pack_type;
3463
3464   notebook = GTK_NOTEBOOK (container);
3465
3466   /* not finding child's page is valid for menus or labels */
3467   list = gtk_notebook_find_child (notebook, child, NULL);
3468   if (!list)
3469     {
3470       /* nothing to set on labels or menus */
3471       g_param_value_set_default (pspec, value);
3472       return;
3473     }
3474
3475   switch (property_id)
3476     {
3477     case CHILD_PROP_TAB_LABEL:
3478       label = gtk_notebook_get_tab_label (notebook, child);
3479
3480       if (label && GTK_IS_LABEL (label))
3481         g_value_set_string (value, GTK_LABEL (label)->label);
3482       else
3483         g_value_set_string (value, NULL);
3484       break;
3485     case CHILD_PROP_MENU_LABEL:
3486       label = gtk_notebook_get_menu_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_POSITION:
3494       g_value_set_int (value, g_list_position (notebook->children, list));
3495       break;
3496     case CHILD_PROP_TAB_EXPAND:
3497         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3498                                               &expand, NULL, NULL);
3499         g_value_set_boolean (value, expand);
3500       break;
3501     case CHILD_PROP_TAB_FILL:
3502         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3503                                               NULL, &fill, NULL);
3504         g_value_set_boolean (value, fill);
3505       break;
3506     case CHILD_PROP_TAB_PACK:
3507         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3508                                               NULL, NULL, &pack_type);
3509         g_value_set_enum (value, pack_type);
3510       break;
3511     case CHILD_PROP_REORDERABLE:
3512       g_value_set_boolean (value,
3513                            gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3514       break;
3515     case CHILD_PROP_DETACHABLE:
3516       g_value_set_boolean (value,
3517                            gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3518       break;
3519     default:
3520       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3521       break;
3522     }
3523 }
3524
3525 static void
3526 gtk_notebook_add (GtkContainer *container,
3527                   GtkWidget    *widget)
3528 {
3529   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3530
3531   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
3532                                  NULL, NULL, -1);
3533 }
3534
3535 static void
3536 gtk_notebook_remove (GtkContainer *container,
3537                      GtkWidget    *widget)
3538 {
3539   GtkNotebook *notebook;
3540   GtkNotebookPage *page;
3541   GList *children;
3542   gint page_num = 0;
3543
3544   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3545   g_return_if_fail (widget != NULL);
3546
3547   notebook = GTK_NOTEBOOK (container);
3548
3549   children = notebook->children;
3550   while (children)
3551     {
3552       page = children->data;
3553
3554       if (page->child == widget)
3555         break;
3556
3557       page_num++;
3558       children = children->next;
3559     }
3560  
3561   if (children == NULL)
3562     return;
3563   
3564   g_object_ref (widget);
3565
3566   gtk_notebook_real_remove (notebook, children);
3567
3568   g_signal_emit (notebook,
3569                  notebook_signals[PAGE_REMOVED],
3570                  0,
3571                  widget,
3572                  page_num);
3573   
3574   g_object_unref (widget);
3575 }
3576
3577 static gboolean
3578 focus_tabs_in (GtkNotebook *notebook)
3579 {
3580   if (notebook->show_tabs && notebook->cur_page)
3581     {
3582       gtk_widget_grab_focus (GTK_WIDGET (notebook));
3583
3584       gtk_notebook_switch_focus_tab (notebook,
3585                                      g_list_find (notebook->children,
3586                                                   notebook->cur_page));
3587
3588       return TRUE;
3589     }
3590   else
3591     return FALSE;
3592 }
3593
3594 static gboolean
3595 focus_tabs_move (GtkNotebook     *notebook,
3596                  GtkDirectionType direction,
3597                  gint             search_direction)
3598 {
3599   GList *new_page;
3600
3601   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3602                                        search_direction, TRUE);
3603   if (!new_page)
3604     {
3605       gboolean wrap_around;
3606
3607       g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3608                     "gtk-keynav-wrap-around", &wrap_around,
3609                     NULL);
3610
3611       if (wrap_around)
3612         new_page = gtk_notebook_search_page (notebook, NULL,
3613                                              search_direction, TRUE);
3614     }
3615
3616   if (new_page)
3617     gtk_notebook_switch_focus_tab (notebook, new_page);
3618   else
3619     gtk_widget_error_bell (GTK_WIDGET (notebook));
3620
3621   return TRUE;
3622 }
3623
3624 static gboolean
3625 focus_child_in (GtkNotebook     *notebook,
3626                 GtkDirectionType direction)
3627 {
3628   if (notebook->cur_page)
3629     return gtk_widget_child_focus (notebook->cur_page->child, direction);
3630   else
3631     return FALSE;
3632 }
3633
3634 /* Focus in the notebook can either be on the pages, or on
3635  * the tabs.
3636  */
3637 static gint
3638 gtk_notebook_focus (GtkWidget        *widget,
3639                     GtkDirectionType  direction)
3640 {
3641   GtkWidget *old_focus_child;
3642   GtkNotebook *notebook;
3643   GtkDirectionType effective_direction;
3644
3645   gboolean widget_is_focus;
3646   GtkContainer *container;
3647
3648   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3649
3650   container = GTK_CONTAINER (widget);
3651   notebook = GTK_NOTEBOOK (container);
3652
3653   if (notebook->focus_out)
3654     {
3655       notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3656       return FALSE;
3657     }
3658
3659   widget_is_focus = gtk_widget_is_focus (widget);
3660   old_focus_child = container->focus_child; 
3661
3662   effective_direction = get_effective_direction (notebook, direction);
3663
3664   if (old_focus_child)          /* Focus on page child */
3665     {
3666       if (gtk_widget_child_focus (old_focus_child, direction))
3667         return TRUE;
3668       
3669       switch (effective_direction)
3670         {
3671         case GTK_DIR_TAB_BACKWARD:
3672         case GTK_DIR_UP:
3673           /* Focus onto the tabs */
3674           return focus_tabs_in (notebook);
3675         case GTK_DIR_DOWN:
3676         case GTK_DIR_TAB_FORWARD:
3677         case GTK_DIR_LEFT:
3678         case GTK_DIR_RIGHT:
3679           return FALSE;
3680         }
3681     }
3682   else if (widget_is_focus)     /* Focus was on tabs */
3683     {
3684       switch (effective_direction)
3685         {
3686         case GTK_DIR_TAB_BACKWARD:
3687         case GTK_DIR_UP:
3688           return FALSE;
3689         case GTK_DIR_TAB_FORWARD:
3690         case GTK_DIR_DOWN:
3691           /* We use TAB_FORWARD rather than direction so that we focus a more
3692            * predictable widget for the user; users may be using arrow focusing
3693            * in this situation even if they don't usually use arrow focusing.
3694            */
3695           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3696         case GTK_DIR_LEFT:
3697           return focus_tabs_move (notebook, direction, STEP_PREV);
3698         case GTK_DIR_RIGHT:
3699           return focus_tabs_move (notebook, direction, STEP_NEXT);
3700         }
3701     }
3702   else /* Focus was not on widget */
3703     {
3704       switch (effective_direction)
3705         {
3706         case GTK_DIR_TAB_FORWARD:
3707         case GTK_DIR_DOWN:
3708           if (focus_tabs_in (notebook))
3709             return TRUE;
3710           if (focus_child_in (notebook, direction))
3711             return TRUE;
3712           return FALSE;
3713         case GTK_DIR_TAB_BACKWARD:
3714         case GTK_DIR_UP:
3715           if (focus_child_in (notebook, direction))
3716             return TRUE;
3717           if (focus_tabs_in (notebook))
3718             return TRUE;
3719           return FALSE;
3720         case GTK_DIR_LEFT:
3721         case GTK_DIR_RIGHT:
3722           return focus_child_in (notebook, direction);
3723         }
3724     }
3725
3726   g_assert_not_reached ();
3727   return FALSE;
3728 }  
3729
3730 static void
3731 gtk_notebook_set_focus_child (GtkContainer *container,
3732                               GtkWidget    *child)
3733 {
3734   GtkNotebook *notebook = GTK_NOTEBOOK (container);
3735   GtkWidget *page_child;
3736   GtkWidget *toplevel;
3737
3738   /* If the old focus widget was within a page of the notebook,
3739    * (child may either be NULL or not in this case), record it
3740    * for future use if we switch to the page with a mnemonic.
3741    */
3742
3743   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3744   if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3745     {
3746       page_child = GTK_WINDOW (toplevel)->focus_widget; 
3747       while (page_child)
3748         {
3749           if (page_child->parent == GTK_WIDGET (container))
3750             {
3751               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3752               if (list != NULL) 
3753                 {
3754                   GtkNotebookPage *page = list->data;
3755               
3756                   if (page->last_focus_child)
3757                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3758                   
3759                   page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3760                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3761               
3762                   break;
3763                 }
3764             }
3765
3766           page_child = page_child->parent;
3767         }
3768     }
3769   
3770   if (child)
3771     {
3772       g_return_if_fail (GTK_IS_WIDGET (child));
3773
3774       notebook->child_has_focus = TRUE;
3775       if (!notebook->focus_tab)
3776         {
3777           GList *children;
3778           GtkNotebookPage *page;
3779
3780           children = notebook->children;
3781           while (children)
3782             {
3783               page = children->data;
3784               if (page->child == child || page->tab_label == child)
3785                 gtk_notebook_switch_focus_tab (notebook, children);
3786               children = children->next;
3787             }
3788         }
3789     }
3790
3791   GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3792 }
3793
3794 static void
3795 gtk_notebook_forall (GtkContainer *container,
3796                      gboolean      include_internals,
3797                      GtkCallback   callback,
3798                      gpointer      callback_data)
3799 {
3800   GtkNotebook *notebook;
3801   GList *children;
3802
3803   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3804   g_return_if_fail (callback != NULL);
3805
3806   notebook = GTK_NOTEBOOK (container);
3807
3808   children = notebook->children;
3809   while (children)
3810     {
3811       GtkNotebookPage *page;
3812       
3813       page = children->data;
3814       children = children->next;
3815       (* callback) (page->child, callback_data);
3816
3817       if (include_internals)
3818         {
3819           if (page->tab_label)
3820             (* callback) (page->tab_label, callback_data);
3821         }
3822     }
3823 }
3824
3825 static GType
3826 gtk_notebook_child_type (GtkContainer     *container)
3827 {
3828   return GTK_TYPE_WIDGET;
3829 }
3830
3831 /* Private GtkNotebook Methods:
3832  *
3833  * gtk_notebook_real_insert_page
3834  */
3835 static void
3836 page_visible_cb (GtkWidget  *page,
3837                  GParamSpec *arg,
3838                  gpointer    data)
3839 {
3840   GtkNotebook *notebook = (GtkNotebook *) data;
3841   GList *list;
3842   GList *next = NULL;
3843
3844   if (notebook->cur_page &&
3845       notebook->cur_page->child == page &&
3846       !GTK_WIDGET_VISIBLE (page))
3847     {
3848       list = g_list_find (notebook->children, notebook->cur_page);
3849       if (list)
3850         {
3851           next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3852           if (!next)
3853             next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3854         }
3855
3856       if (next)
3857         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3858     }
3859 }
3860
3861 static gint
3862 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3863                                GtkWidget   *child,
3864                                GtkWidget   *tab_label,
3865                                GtkWidget   *menu_label,
3866                                gint         position)
3867 {
3868   GtkNotebookPage *page;
3869   gint nchildren;
3870
3871   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3872   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3873   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3874   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3875
3876   gtk_widget_freeze_child_notify (child);
3877   
3878   page = g_new (GtkNotebookPage, 1);
3879   page->child = child;
3880   page->last_focus_child = NULL;
3881   page->requisition.width = 0;
3882   page->requisition.height = 0;
3883   page->allocation.x = 0;
3884   page->allocation.y = 0;
3885   page->allocation.width = 0;
3886   page->allocation.height = 0;
3887   page->default_menu = FALSE;
3888   page->default_tab = FALSE;
3889   page->mnemonic_activate_signal = 0;
3890   page->reorderable = FALSE;
3891   page->detachable = FALSE;
3892    
3893   nchildren = g_list_length (notebook->children);
3894   if ((position < 0) || (position > nchildren))
3895     position = nchildren;
3896
3897   notebook->children = g_list_insert (notebook->children, page, position);
3898
3899   if (!tab_label)
3900     {
3901       page->default_tab = TRUE;
3902       if (notebook->show_tabs)
3903         tab_label = gtk_label_new ("");
3904     }
3905   page->tab_label = tab_label;
3906   page->menu_label = menu_label;
3907   page->expand = FALSE;
3908   page->fill = TRUE;
3909   page->pack = GTK_PACK_START; 
3910
3911   if (!menu_label)
3912     page->default_menu = TRUE;
3913   else  
3914     {
3915       g_object_ref_sink (page->menu_label);
3916     }
3917
3918   if (notebook->menu)
3919     gtk_notebook_menu_item_create (notebook,
3920                                    g_list_find (notebook->children, page));
3921
3922   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3923   if (tab_label)
3924     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3925
3926   gtk_notebook_update_labels (notebook);
3927
3928   if (!notebook->first_tab)
3929     notebook->first_tab = notebook->children;
3930
3931   /* child visible will be turned on by switch_page below */
3932   gtk_widget_set_child_visible (child, FALSE);
3933   
3934   if (tab_label)
3935     {
3936       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3937         gtk_widget_show (tab_label);
3938       else
3939         gtk_widget_hide (tab_label);
3940
3941     page->mnemonic_activate_signal =
3942       g_signal_connect (tab_label,
3943                         "mnemonic_activate",
3944                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3945                         notebook);
3946     }
3947
3948   page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3949                                                    G_CALLBACK (page_visible_cb), notebook);
3950
3951   g_signal_emit (notebook,
3952                  notebook_signals[PAGE_ADDED],
3953                  0,
3954                  child,
3955                  position);
3956
3957   if (!notebook->cur_page)
3958     {
3959       gtk_notebook_switch_page (notebook, page, 0);
3960       gtk_notebook_switch_focus_tab (notebook, NULL);
3961     }
3962
3963   gtk_notebook_update_tab_states (notebook);
3964
3965   gtk_widget_child_notify (child, "tab-expand");
3966   gtk_widget_child_notify (child, "tab-fill");
3967   gtk_widget_child_notify (child, "tab-pack");
3968   gtk_widget_child_notify (child, "tab-label");
3969   gtk_widget_child_notify (child, "menu-label");
3970   gtk_widget_child_notify (child, "position");
3971   gtk_widget_thaw_child_notify (child);
3972
3973   return position;
3974 }
3975
3976 /* Private GtkNotebook Functions:
3977  *
3978  * gtk_notebook_redraw_tabs
3979  * gtk_notebook_real_remove
3980  * gtk_notebook_update_labels
3981  * gtk_notebook_timer
3982  * gtk_notebook_set_scroll_timer
3983  * gtk_notebook_page_compare
3984  * gtk_notebook_real_page_position
3985  * gtk_notebook_search_page
3986  */
3987 static void
3988 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3989 {
3990   GtkWidget *widget;
3991   GtkNotebookPage *page;
3992   GdkRectangle redraw_rect;
3993   gint border;
3994   gint tab_pos = get_effective_tab_pos (notebook);
3995
3996   widget = GTK_WIDGET (notebook);
3997   border = GTK_CONTAINER (notebook)->border_width;
3998
3999   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4000     return;
4001
4002   page = notebook->first_tab->data;
4003
4004   redraw_rect.x = border;
4005   redraw_rect.y = border;
4006
4007   switch (tab_pos)
4008     {
4009     case GTK_POS_BOTTOM:
4010       redraw_rect.y = widget->allocation.height - border -
4011         page->allocation.height - widget->style->ythickness;
4012
4013       if (page != notebook->cur_page)
4014         redraw_rect.y -= widget->style->ythickness;
4015       /* fall through */
4016     case GTK_POS_TOP:
4017       redraw_rect.width = widget->allocation.width - 2 * border;
4018       redraw_rect.height = page->allocation.height + widget->style->ythickness;
4019
4020       if (page != notebook->cur_page)
4021         redraw_rect.height += widget->style->ythickness;
4022       break;
4023     case GTK_POS_RIGHT:
4024       redraw_rect.x = widget->allocation.width - border -
4025         page->allocation.width - widget->style->xthickness;
4026
4027       if (page != notebook->cur_page)
4028         redraw_rect.x -= widget->style->xthickness;
4029       /* fall through */
4030     case GTK_POS_LEFT:
4031       redraw_rect.width = page->allocation.width + widget->style->xthickness;
4032       redraw_rect.height = widget->allocation.height - 2 * border;
4033
4034       if (page != notebook->cur_page)
4035         redraw_rect.width += widget->style->xthickness;
4036       break;
4037     }
4038
4039   redraw_rect.x += widget->allocation.x;
4040   redraw_rect.y += widget->allocation.y;
4041
4042   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4043 }
4044
4045 static void
4046 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4047 {
4048   if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4049     {
4050       GdkRectangle rect;
4051       gint i;
4052       GtkNotebookArrow arrow[4];
4053
4054       arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4055       arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4056       arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4057       arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4058
4059       for (i = 0; i < 4; i++) 
4060         {
4061           if (arrow[i] == ARROW_NONE)
4062             continue;
4063
4064           gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4065           gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, 
4066                                       &rect, FALSE);
4067         }
4068     }
4069 }
4070
4071 static gboolean
4072 gtk_notebook_timer (GtkNotebook *notebook)
4073 {
4074   gboolean retval = FALSE;
4075
4076   if (notebook->timer)
4077     {
4078       gtk_notebook_do_arrow (notebook, notebook->click_child);
4079
4080       if (notebook->need_timer)
4081         {
4082           GtkSettings *settings;
4083           guint        timeout;
4084
4085           settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4086           g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4087
4088           notebook->need_timer = FALSE;
4089           notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4090                                            (GSourceFunc) gtk_notebook_timer,
4091                                            (gpointer) notebook);
4092         }
4093       else
4094         retval = TRUE;
4095     }
4096
4097   return retval;
4098 }
4099
4100 static void
4101 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4102 {
4103   GtkWidget *widget = GTK_WIDGET (notebook);
4104
4105   if (!notebook->timer)
4106     {
4107       GtkSettings *settings = gtk_widget_get_settings (widget);
4108       guint timeout;
4109
4110       g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4111
4112       notebook->timer = gdk_threads_add_timeout (timeout,
4113                                        (GSourceFunc) gtk_notebook_timer,
4114                                        (gpointer) notebook);
4115       notebook->need_timer = TRUE;
4116     }
4117 }
4118
4119 static gint
4120 gtk_notebook_page_compare (gconstpointer a,
4121                            gconstpointer b)
4122 {
4123   return (((GtkNotebookPage *) a)->child != b);
4124 }
4125
4126 static GList*
4127 gtk_notebook_find_child (GtkNotebook *notebook,
4128                          GtkWidget   *child,
4129                          const gchar *function)
4130 {
4131   GList *list = g_list_find_custom (notebook->children, child,
4132                                     gtk_notebook_page_compare);
4133
4134 #ifndef G_DISABLE_CHECKS
4135   if (!list && function)
4136     g_warning ("%s: unable to find child %p in notebook %p",
4137                function, child, notebook);
4138 #endif
4139
4140   return list;
4141 }
4142
4143 static void
4144 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
4145                                GtkNotebookPage *page)
4146 {
4147   if (page->tab_label)
4148     {
4149       if (page->mnemonic_activate_signal)
4150         g_signal_handler_disconnect (page->tab_label,
4151                                      page->mnemonic_activate_signal);
4152       page->mnemonic_activate_signal = 0;
4153
4154       gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4155       gtk_widget_unparent (page->tab_label);
4156       page->tab_label = NULL;
4157     }
4158 }
4159
4160 static void
4161 gtk_notebook_real_remove (GtkNotebook *notebook,
4162                           GList       *list)
4163 {
4164   GtkNotebookPrivate *priv;
4165   GtkNotebookPage *page;
4166   GList * next_list;
4167   gint need_resize = FALSE;
4168
4169   gboolean destroying;
4170
4171   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4172   destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4173   
4174   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4175   if (!next_list)
4176     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4177
4178   if (notebook->cur_page == list->data)
4179     { 
4180       notebook->cur_page = NULL;
4181       if (next_list && !destroying)
4182         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4183     }
4184
4185   if (priv->detached_tab == list->data)
4186     priv->detached_tab = NULL;
4187
4188   if (list == notebook->first_tab)
4189     notebook->first_tab = next_list;
4190   if (list == notebook->focus_tab && !destroying)
4191     gtk_notebook_switch_focus_tab (notebook, next_list);
4192
4193   page = list->data;
4194   
4195   g_signal_handler_disconnect (page->child, page->notify_visible_handler); 
4196
4197   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4198     need_resize = TRUE;
4199
4200   gtk_widget_unparent (page->child);
4201
4202   gtk_notebook_remove_tab_label (notebook, page);
4203   
4204   if (notebook->menu)
4205     {
4206       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4207                             page->menu_label->parent);
4208       gtk_widget_queue_resize (notebook->menu);
4209     }
4210   if (!page->default_menu)
4211     g_object_unref (page->menu_label);
4212   
4213   notebook->children = g_list_remove_link (notebook->children, list);
4214   g_list_free (list);
4215
4216   if (page->last_focus_child)
4217     {
4218       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4219       page->last_focus_child = NULL;
4220     }
4221   
4222   g_free (page);
4223
4224   gtk_notebook_update_labels (notebook);
4225   if (need_resize)
4226     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4227 }
4228
4229 static void
4230 gtk_notebook_update_labels (GtkNotebook *notebook)
4231 {
4232   GtkNotebookPage *page;
4233   GList *list;
4234   gchar string[32];
4235   gint page_num = 1;
4236
4237   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4238        list;
4239        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4240     {
4241       page = list->data;
4242       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4243       if (notebook->show_tabs)
4244         {
4245           if (page->default_tab)
4246             {
4247               if (!page->tab_label)
4248                 {
4249                   page->tab_label = gtk_label_new (string);
4250                   gtk_widget_set_parent (page->tab_label,
4251                                          GTK_WIDGET (notebook));
4252                 }
4253               else
4254                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4255             }
4256
4257           if (GTK_WIDGET_VISIBLE (page->child) &&
4258               !GTK_WIDGET_VISIBLE (page->tab_label))
4259             gtk_widget_show (page->tab_label);
4260           else if (!GTK_WIDGET_VISIBLE (page->child) &&
4261                    GTK_WIDGET_VISIBLE (page->tab_label))
4262             gtk_widget_hide (page->tab_label);
4263         }
4264       if (notebook->menu && page->default_menu)
4265         {
4266           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4267             gtk_label_set_text (GTK_LABEL (page->menu_label),
4268                            GTK_LABEL (page->tab_label)->label);
4269           else
4270             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4271         }
4272     }  
4273 }
4274
4275 static gint
4276 gtk_notebook_real_page_position (GtkNotebook *notebook,
4277                                  GList       *list)
4278 {
4279   GList *work;
4280   gint count_start;
4281
4282   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4283   g_return_val_if_fail (list != NULL, -1);
4284
4285   for (work = notebook->children, count_start = 0;
4286        work && work != list; work = work->next)
4287     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4288       count_start++;
4289
4290   if (!work)
4291     return -1;
4292
4293   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4294     return count_start;
4295
4296   return (count_start + g_list_length (list) - 1);
4297 }
4298
4299 static GList *
4300 gtk_notebook_search_page (GtkNotebook *notebook,
4301                           GList       *list,
4302                           gint         direction,
4303                           gboolean     find_visible)
4304 {
4305   GtkNotebookPage *page = NULL;
4306   GList *old_list = NULL;
4307   gint flag = 0;
4308
4309   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4310
4311   switch (direction)
4312     {
4313     case STEP_PREV:
4314       flag = GTK_PACK_END;
4315       break;
4316
4317     case STEP_NEXT:
4318       flag = GTK_PACK_START;
4319       break;
4320     }
4321
4322   if (list)
4323     page = list->data;
4324
4325   if (!page || page->pack == flag)
4326     {
4327       if (list)
4328         {
4329           old_list = list;
4330           list = list->next;
4331         }
4332       else
4333         list = notebook->children;
4334
4335       while (list)
4336         {
4337           page = list->data;
4338           if (page->pack == flag &&
4339               (!find_visible ||
4340                (GTK_WIDGET_VISIBLE (page->child) &&
4341                 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4342             return list;
4343           old_list = list;
4344           list = list->next;
4345         }
4346       list = old_list;
4347     }
4348   else
4349     {
4350       old_list = list;
4351       list = list->prev;
4352     }
4353   while (list)
4354     {
4355       page = list->data;
4356       if (page->pack != flag &&
4357           (!find_visible ||
4358            (GTK_WIDGET_VISIBLE (page->child) &&
4359             (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4360         return list;
4361       old_list = list;
4362       list = list->prev;
4363     }
4364   return NULL;
4365 }
4366
4367 /* Private GtkNotebook Drawing Functions:
4368  *
4369  * gtk_notebook_paint
4370  * gtk_notebook_draw_tab
4371  * gtk_notebook_draw_arrow
4372  */
4373 static void
4374 gtk_notebook_paint (GtkWidget    *widget,
4375                     GdkRectangle *area)
4376 {
4377   GtkNotebook *notebook;
4378   GtkNotebookPrivate *priv;
4379   GtkNotebookPage *page;
4380   GList *children;
4381   gboolean showarrow;
4382   gint width, height;
4383   gint x, y;
4384   gint border_width = GTK_CONTAINER (widget)->border_width;
4385   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4386   gboolean is_rtl;
4387   gint tab_pos;
4388    
4389   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4390   g_return_if_fail (area != NULL);
4391
4392   if (!GTK_WIDGET_DRAWABLE (widget))
4393     return;
4394
4395   notebook = GTK_NOTEBOOK (widget);
4396   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4397   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4398   tab_pos = get_effective_tab_pos (notebook);
4399
4400   if ((!notebook->show_tabs && !notebook->show_border) ||
4401       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4402     return;
4403
4404   x = widget->allocation.x + border_width;
4405   y = widget->allocation.y + border_width;
4406   width = widget->allocation.width - border_width * 2;
4407   height = widget->allocation.height - border_width * 2;
4408
4409   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4410     {
4411       gtk_paint_box (widget->style, widget->window,
4412                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4413                      area, widget, "notebook",
4414                      x, y, width, height);
4415       return;
4416     }
4417
4418   if (!notebook->first_tab)
4419     notebook->first_tab = notebook->children;
4420
4421   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4422       !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4423     page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4424   else
4425     page = notebook->cur_page;
4426
4427   switch (tab_pos)
4428     {
4429     case GTK_POS_TOP:
4430       y += page->allocation.height;
4431       /* fall thru */
4432     case GTK_POS_BOTTOM:
4433       height -= page->allocation.height;
4434       break;
4435     case GTK_POS_LEFT:
4436       x += page->allocation.width;
4437       /* fall thru */
4438     case GTK_POS_RIGHT:
4439       width -= page->allocation.width;
4440       break;
4441     }
4442
4443   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4444       !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4445     {
4446       gap_x = 0;
4447       gap_width = 0;
4448     }
4449   else
4450     {
4451       switch (tab_pos)
4452         {
4453         case GTK_POS_TOP:
4454         case GTK_POS_BOTTOM:
4455           if (priv->operation == DRAG_OPERATION_REORDER)
4456             gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4457           else
4458             gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4459
4460           gap_width = notebook->cur_page->allocation.width;
4461           step = is_rtl ? STEP_NEXT : STEP_PREV;
4462           break;
4463         case GTK_POS_LEFT:
4464         case GTK_POS_RIGHT:
4465           if (priv->operation == DRAG_OPERATION_REORDER)
4466             gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4467           else
4468             gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4469
4470           gap_width = notebook->cur_page->allocation.height;
4471           step = STEP_PREV;
4472           break;
4473         }
4474     }
4475   gtk_paint_box_gap (widget->style, widget->window,
4476                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4477                      area, widget, "notebook",
4478                      x, y, width, height,
4479                      tab_pos, gap_x, gap_width);
4480
4481   showarrow = FALSE;
4482   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4483   while (children)
4484     {
4485       page = children->data;
4486       children = gtk_notebook_search_page (notebook, children,
4487                                            step, TRUE);
4488       if (!GTK_WIDGET_VISIBLE (page->child))
4489         continue;
4490       if (!GTK_WIDGET_MAPPED (page->tab_label))
4491         showarrow = TRUE;
4492       else if (page != notebook->cur_page)
4493         gtk_notebook_draw_tab (notebook, page, area);
4494     }
4495
4496   if (showarrow && notebook->scrollable) 
4497     {
4498       if (notebook->has_before_previous)
4499         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4500       if (notebook->has_before_next)
4501         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4502       if (notebook->has_after_previous)
4503         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4504       if (notebook->has_after_next)
4505         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4506     }
4507   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4508 }
4509
4510 static void
4511 gtk_notebook_draw_tab (GtkNotebook     *notebook,
4512                        GtkNotebookPage *page,
4513                        GdkRectangle    *area)
4514 {
4515   GtkNotebookPrivate *priv;
4516   GdkRectangle child_area;
4517   GdkRectangle page_area;
4518   GtkStateType state_type;
4519   GtkPositionType gap_side;
4520   GdkWindow *window;
4521   GtkWidget *widget;
4522   
4523   g_return_if_fail (notebook != NULL);
4524   g_return_if_fail (page != NULL);
4525   g_return_if_fail (area != NULL);
4526
4527   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4528       !GTK_WIDGET_MAPPED (page->tab_label) ||
4529       (page->allocation.width == 0) || (page->allocation.height == 0))
4530     return;
4531
4532   widget = GTK_WIDGET (notebook);
4533   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4534
4535   if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4536     window = priv->drag_window;
4537   else
4538     window = widget->window;
4539
4540   page_area.x = page->allocation.x;
4541   page_area.y = page->allocation.y;
4542   page_area.width = page->allocation.width;
4543   page_area.height = page->allocation.height;
4544
4545   if (gdk_rectangle_intersect (&page_area, area, &child_area))
4546     {
4547       gap_side = get_tab_gap_pos (notebook);
4548
4549       if (notebook->cur_page == page)
4550         state_type = GTK_STATE_NORMAL;
4551       else 
4552         state_type = GTK_STATE_ACTIVE;
4553
4554       gtk_paint_extension (widget->style, window,
4555                            state_type, GTK_SHADOW_OUT,
4556                            area, widget, "tab",
4557                            page_area.x, page_area.y,
4558                            page_area.width, page_area.height,
4559                            gap_side);
4560
4561       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4562           notebook->focus_tab && (notebook->focus_tab->data == page))
4563         {
4564           gint focus_width;
4565
4566           gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4567
4568           gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4569                            area, widget, "tab",
4570                            page->tab_label->allocation.x - focus_width,
4571                            page->tab_label->allocation.y - focus_width,
4572                            page->tab_label->allocation.width + 2 * focus_width,
4573                            page->tab_label->allocation.height + 2 * focus_width);
4574         }
4575
4576       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4577           GTK_WIDGET_DRAWABLE (page->tab_label))
4578         {
4579           GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4580
4581           /* This is a lame hack since all this code needs rewriting anyhow */
4582           expose_event->expose.window = g_object_ref (page->tab_label->window);
4583           expose_event->expose.area = child_area;
4584           expose_event->expose.region = gdk_region_rectangle (&child_area);
4585           expose_event->expose.send_event = TRUE;
4586           expose_event->expose.count = 0;
4587
4588           gtk_widget_send_expose (page->tab_label, expose_event);
4589           gdk_event_free (expose_event);
4590         }
4591     }
4592 }
4593
4594 static void
4595 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
4596                          GtkNotebookArrow  nbarrow)
4597 {
4598   GtkStateType state_type;
4599   GtkShadowType shadow_type;
4600   GtkWidget *widget;
4601   GdkRectangle arrow_rect;
4602   GtkArrowType arrow;
4603   gboolean is_rtl, left;
4604
4605   gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4606
4607   widget = GTK_WIDGET (notebook);
4608
4609   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4610   left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4611          (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
4612
4613   if (GTK_WIDGET_DRAWABLE (notebook))
4614     {
4615       gint scroll_arrow_hlength;
4616       gint scroll_arrow_vlength;
4617       gint arrow_size;
4618
4619       gtk_widget_style_get (widget,
4620                             "scroll-arrow-hlength", &scroll_arrow_hlength,
4621                             "scroll-arrow-vlength", &scroll_arrow_vlength,
4622                             NULL);
4623
4624       if (notebook->in_child == nbarrow)
4625         {
4626           if (notebook->click_child == nbarrow)
4627             state_type = GTK_STATE_ACTIVE;
4628           else
4629             state_type = GTK_STATE_PRELIGHT;
4630         }
4631       else
4632         state_type = GTK_WIDGET_STATE (widget);
4633
4634       if (notebook->click_child == nbarrow)
4635         shadow_type = GTK_SHADOW_IN;
4636       else
4637         shadow_type = GTK_SHADOW_OUT;
4638
4639       if (notebook->focus_tab &&
4640           !gtk_notebook_search_page (notebook, notebook->focus_tab,
4641                                       left? STEP_PREV : STEP_NEXT, TRUE))
4642         {
4643           shadow_type = GTK_SHADOW_ETCHED_IN;
4644           state_type = GTK_STATE_INSENSITIVE;
4645         }
4646       
4647       if (notebook->tab_pos == GTK_POS_LEFT ||
4648           notebook->tab_pos == GTK_POS_RIGHT)
4649         {
4650           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4651           arrow_size = scroll_arrow_vlength;
4652         }
4653       else
4654         {
4655           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4656           arrow_size = scroll_arrow_hlength;
4657         }
4658      
4659       gtk_paint_arrow (widget->style, widget->window, state_type, 
4660                        shadow_type, NULL, widget, "notebook",
4661                        arrow, TRUE, arrow_rect.x, arrow_rect.y, 
4662                        arrow_size, arrow_size);
4663     }
4664 }
4665
4666 /* Private GtkNotebook Size Allocate Functions:
4667  *
4668  * gtk_notebook_tab_space
4669  * gtk_notebook_calculate_shown_tabs
4670  * gtk_notebook_calculate_tabs_allocation
4671  * gtk_notebook_pages_allocate
4672  * gtk_notebook_page_allocate
4673  * gtk_notebook_calc_tabs
4674  */
4675 static void
4676 gtk_notebook_tab_space (GtkNotebook *notebook,
4677                         gboolean    *show_arrows,
4678                         gint        *min,
4679                         gint        *max,
4680                         gint        *tab_space)
4681 {
4682   GtkNotebookPrivate *priv;
4683   GtkWidget *widget;
4684   GList *children;
4685   gint tab_pos = get_effective_tab_pos (notebook);
4686   gint tab_overlap;
4687   gint arrow_spacing;
4688   gint scroll_arrow_hlength;
4689   gint scroll_arrow_vlength;
4690
4691   widget = GTK_WIDGET (notebook);
4692   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4693   children = notebook->children;
4694
4695   gtk_widget_style_get (GTK_WIDGET (notebook),
4696                         "arrow-spacing", &arrow_spacing,
4697                         "scroll-arrow-hlength", &scroll_arrow_hlength,
4698                         "scroll-arrow-vlength", &scroll_arrow_vlength,
4699                         NULL);
4700
4701   switch (tab_pos)
4702     {
4703     case GTK_POS_TOP:
4704     case GTK_POS_BOTTOM:
4705       *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4706       *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4707
4708       while (children)
4709         {
4710           GtkNotebookPage *page;
4711
4712           page = children->data;
4713           children = children->next;
4714
4715           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4716               GTK_WIDGET_VISIBLE (page->child))
4717             *tab_space += page->requisition.width;
4718         }
4719       break;
4720     case GTK_POS_RIGHT:
4721     case GTK_POS_LEFT:
4722       *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4723       *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4724
4725       while (children)
4726         {
4727           GtkNotebookPage *page;
4728
4729           page = children->data;
4730           children = children->next;
4731
4732           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4733               GTK_WIDGET_VISIBLE (page->child))
4734             *tab_space += page->requisition.height;
4735         }
4736       break;
4737     }
4738
4739   if (!notebook->scrollable)
4740     *show_arrows = FALSE;
4741   else
4742     {
4743       gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4744
4745       switch (tab_pos)
4746         {
4747         case GTK_POS_TOP:
4748         case GTK_POS_BOTTOM:
4749           if (*tab_space > *max - *min - tab_overlap)
4750             {
4751               *show_arrows = TRUE;
4752
4753               /* take arrows into account */
4754               *tab_space = widget->allocation.width - tab_overlap -
4755                 2 * GTK_CONTAINER (notebook)->border_width;
4756
4757               if (notebook->has_after_previous)
4758                 {
4759                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4760                   *max -= arrow_spacing + scroll_arrow_hlength;
4761                 }
4762
4763               if (notebook->has_after_next)
4764                 {
4765                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4766                   *max -= arrow_spacing + scroll_arrow_hlength;
4767                 }
4768
4769               if (notebook->has_before_previous)
4770                 {
4771                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4772                   *min += arrow_spacing + scroll_arrow_hlength;
4773                 }
4774
4775               if (notebook->has_before_next)
4776                 {
4777                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4778                   *min += arrow_spacing + scroll_arrow_hlength;
4779                 }
4780             }
4781           break;
4782         case GTK_POS_LEFT:
4783         case GTK_POS_RIGHT:
4784           if (*tab_space > *max - *min - tab_overlap)
4785             {
4786               *show_arrows = TRUE;
4787
4788               /* take arrows into account */
4789               *tab_space = widget->allocation.height -
4790                 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4791
4792               if (notebook->has_after_previous || notebook->has_after_next)
4793                 {
4794                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
4795                   *max -= arrow_spacing + scroll_arrow_vlength;
4796                 }
4797
4798               if (notebook->has_before_previous || notebook->has_before_next)
4799                 {
4800                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
4801                   *min += arrow_spacing + scroll_arrow_vlength;
4802                 }
4803             }
4804           break;
4805         }
4806     }
4807 }
4808
4809 static void
4810 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4811                                    gboolean     show_arrows,
4812                                    gint         min,
4813                                    gint         max,
4814                                    gint         tab_space,
4815                                    GList      **last_child,
4816                                    gint        *n,
4817                                    gint        *remaining_space)
4818 {
4819   GtkWidget *widget;
4820   GtkContainer *container;
4821   GList *children;
4822   GtkNotebookPage *page;
4823   gint tab_pos, tab_overlap;
4824   
4825   widget = GTK_WIDGET (notebook);
4826   container = GTK_CONTAINER (notebook);
4827   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4828   tab_pos = get_effective_tab_pos (notebook);
4829
4830   if (show_arrows) /* first_tab <- focus_tab */
4831     {
4832       *remaining_space = tab_space;
4833
4834       if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4835           GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4836         {
4837           gtk_notebook_calc_tabs (notebook,
4838                                   notebook->focus_tab,
4839                                   &(notebook->focus_tab),
4840                                   remaining_space, STEP_NEXT);
4841         }
4842
4843       if (*remaining_space <= 0)
4844         {
4845           /* show 1 tab */
4846           notebook->first_tab = notebook->focus_tab;
4847           *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4848                                                   STEP_NEXT, TRUE);
4849         }
4850       else
4851         {
4852           children = NULL;
4853
4854           if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4855             {
4856               /* Is first_tab really predecessor of focus_tab? */
4857               page = notebook->first_tab->data;
4858               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4859                   GTK_WIDGET_VISIBLE (page->child))
4860                 for (children = notebook->focus_tab;
4861                      children && children != notebook->first_tab;
4862                      children = gtk_notebook_search_page (notebook,
4863                                                           children,
4864                                                           STEP_PREV,
4865                                                           TRUE));
4866             }
4867
4868           if (!children)
4869             {
4870               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4871                 notebook->first_tab = notebook->focus_tab;
4872               else
4873                 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4874                                                                 STEP_NEXT, TRUE);
4875             }
4876           else
4877             /* calculate shown tabs counting backwards from the focus tab */
4878             gtk_notebook_calc_tabs (notebook,
4879                                     gtk_notebook_search_page (notebook,
4880                                                               notebook->focus_tab,
4881                                                               STEP_PREV,
4882                                                               TRUE),
4883                                     &(notebook->first_tab), remaining_space,
4884                                     STEP_PREV);
4885
4886           if (*remaining_space < 0)
4887             {
4888               notebook->first_tab =
4889                 gtk_notebook_search_page (notebook, notebook->first_tab,
4890                                           STEP_NEXT, TRUE);
4891               if (!notebook->first_tab)
4892                 notebook->first_tab = notebook->focus_tab;
4893
4894               *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4895                                                       STEP_NEXT, TRUE); 
4896             }
4897           else /* focus_tab -> end */   
4898             {
4899               if (!notebook->first_tab)
4900                 notebook->first_tab = gtk_notebook_search_page (notebook,
4901                                                                 NULL,
4902                                                                 STEP_NEXT,
4903                                                                 TRUE);
4904               children = NULL;
4905               gtk_notebook_calc_tabs (notebook,
4906                                       gtk_notebook_search_page (notebook,
4907                                                                 notebook->focus_tab,
4908                                                                 STEP_NEXT,
4909                                                                 TRUE),
4910                                       &children, remaining_space, STEP_NEXT);
4911
4912               if (*remaining_space <= 0) 
4913                 *last_child = children;
4914               else /* start <- first_tab */
4915                 {
4916                   *last_child = NULL;
4917                   children = NULL;
4918
4919                   gtk_notebook_calc_tabs (notebook,
4920                                           gtk_notebook_search_page (notebook,
4921                                                                     notebook->first_tab,
4922                                                                     STEP_PREV,
4923                                                                     TRUE),
4924                                           &children, remaining_space, STEP_PREV);
4925
4926                   if (*remaining_space == 0)
4927                     notebook->first_tab = children;
4928                   else
4929                     notebook->first_tab = gtk_notebook_search_page(notebook,
4930                                                                    children,
4931                                                                    STEP_NEXT,
4932                                                                    TRUE);
4933                 }
4934             }
4935         }
4936
4937       if (*remaining_space < 0) 
4938         {
4939           /* calculate number of tabs */
4940           *remaining_space = - (*remaining_space);
4941           *n = 0;
4942
4943           for (children = notebook->first_tab;
4944                children && children != *last_child;
4945                children = gtk_notebook_search_page (notebook, children,
4946                                                     STEP_NEXT, TRUE))
4947             (*n)++;
4948         }
4949       else 
4950         *remaining_space = 0;
4951
4952       /* unmap all non-visible tabs */
4953       for (children = gtk_notebook_search_page (notebook, NULL,
4954                                                 STEP_NEXT, TRUE);
4955            children && children != notebook->first_tab;
4956            children = gtk_notebook_search_page (notebook, children,
4957                                                 STEP_NEXT, TRUE))
4958         {
4959           page = children->data;
4960
4961           if (page->tab_label &&
4962               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4963             gtk_widget_set_child_visible (page->tab_label, FALSE);
4964         }
4965
4966       for (children = *last_child; children;
4967            children = gtk_notebook_search_page (notebook, children,
4968                                                 STEP_NEXT, TRUE))
4969         {
4970           page = children->data;
4971
4972           if (page->tab_label &&
4973               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4974             gtk_widget_set_child_visible (page->tab_label, FALSE);
4975         }
4976     }
4977   else /* !show_arrows */
4978     {
4979       gint c = 0;
4980       *n = 0;
4981
4982       *remaining_space = max - min - tab_overlap - tab_space;
4983       children = notebook->children;
4984       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4985                                                       STEP_NEXT, TRUE);
4986       while (children)
4987         {
4988           page = children->data;
4989           children = children->next;
4990
4991           if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4992               !GTK_WIDGET_VISIBLE (page->child))
4993             continue;
4994
4995           c++;
4996
4997           if (page->expand)
4998             (*n)++;
4999         }
5000
5001       /* if notebook is homogeneous, all tabs are expanded */
5002       if (notebook->homogeneous && *n)
5003         *n = c;
5004     }
5005 }
5006
5007 static gboolean
5008 get_allocate_at_bottom (GtkWidget *widget,
5009                         gint       search_direction)
5010 {
5011   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5012   gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5013
5014   switch (tab_pos)
5015     {
5016     case GTK_POS_TOP:
5017     case GTK_POS_BOTTOM:
5018       if (!is_rtl)
5019         return (search_direction == STEP_PREV);
5020       else
5021         return (search_direction == STEP_NEXT);
5022
5023       break;
5024     case GTK_POS_RIGHT:
5025     case GTK_POS_LEFT:
5026       return (search_direction == STEP_PREV);
5027       break;
5028     }
5029
5030   return FALSE;
5031 }
5032
5033 static gboolean
5034 gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
5035                                         GList       **children,
5036                                         GList        *last_child,
5037                                         gboolean      showarrow,
5038                                         gint          direction,
5039                                         gint         *remaining_space,
5040                                         gint         *expanded_tabs,
5041                                         gint          min,
5042                                         gint          max)
5043 {
5044   GtkWidget *widget;
5045   GtkContainer *container;
5046   GtkNotebookPrivate *priv;
5047   GtkNotebookPage *page;
5048   gboolean allocate_at_bottom;
5049   gint tab_overlap, tab_pos, tab_extra_space;
5050   gint left_x, right_x, top_y, bottom_y, anchor;
5051   gint xthickness, ythickness;
5052   gboolean gap_left, packing_changed;
5053   GtkAllocation child_allocation = { 0, };
5054   gboolean allocation_changed = FALSE;
5055
5056   widget = GTK_WIDGET (notebook);
5057   container = GTK_CONTAINER (notebook);
5058   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5059   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5060   tab_pos = get_effective_tab_pos (notebook);
5061   allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5062   anchor = 0;
5063
5064   child_allocation.x = widget->allocation.x + container->border_width;
5065   child_allocation.y = widget->allocation.y + container->border_width;
5066
5067   xthickness = widget->style->xthickness;
5068   ythickness = widget->style->ythickness;
5069
5070   switch (tab_pos)
5071     {
5072     case GTK_POS_BOTTOM:
5073       child_allocation.y = widget->allocation.y + widget->allocation.height -
5074         notebook->cur_page->requisition.height - container->border_width;
5075       /* fall through */
5076     case GTK_POS_TOP:
5077       child_allocation.x = (allocate_at_bottom) ? max : min;
5078       child_allocation.height = notebook->cur_page->requisition.height;
5079       anchor = child_allocation.x;
5080       break;
5081       
5082     case GTK_POS_RIGHT:
5083       child_allocation.x = widget->allocation.x + widget->allocation.width -
5084         notebook->cur_page->requisition.width - container->border_width;
5085       /* fall through */
5086     case GTK_POS_LEFT:
5087       child_allocation.y = (allocate_at_bottom) ? max : min;
5088       child_allocation.width = notebook->cur_page->requisition.width;
5089       anchor = child_allocation.y;
5090       break;
5091     }
5092
5093   left_x   = CLAMP (priv->mouse_x - priv->drag_offset_x,
5094                     min, max - notebook->cur_page->allocation.width);
5095   top_y    = CLAMP (priv->mouse_y - priv->drag_offset_y,
5096                     min, max - notebook->cur_page->allocation.height);
5097   right_x  = left_x + notebook->cur_page->allocation.width;
5098   bottom_y = top_y + notebook->cur_page->allocation.height;
5099   gap_left = packing_changed = FALSE;
5100
5101   while (*children && *children != last_child)
5102     {
5103       page = (*children)->data;
5104
5105       if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5106         {
5107           if (!showarrow)
5108             break;
5109           else if (priv->operation == DRAG_OPERATION_REORDER)
5110             packing_changed = TRUE;
5111         }
5112
5113       if (direction == STEP_NEXT)
5114         *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5115       else
5116         {
5117           *children = (*children)->next;
5118
5119           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5120             continue;
5121         }
5122
5123       if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5124         continue;
5125
5126       tab_extra_space = 0;
5127       if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5128         {
5129           tab_extra_space = *remaining_space / *expanded_tabs;
5130           *remaining_space -= tab_extra_space;
5131           (*expanded_tabs)--;
5132         }
5133
5134       switch (tab_pos)
5135         {
5136         case GTK_POS_TOP:
5137         case GTK_POS_BOTTOM:
5138           child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5139
5140           /* make sure that the reordered tab doesn't go past the last position */
5141           if (priv->operation == DRAG_OPERATION_REORDER &&
5142               !gap_left && packing_changed)
5143             {
5144               if (!allocate_at_bottom)
5145                 {
5146                   if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5147                       (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5148                     {
5149                       left_x = priv->drag_window_x = anchor;
5150                       anchor += notebook->cur_page->allocation.width - tab_overlap;
5151                     }
5152                 }
5153               else
5154                 {
5155                   if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5156                       (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5157                     {
5158                       anchor -= notebook->cur_page->allocation.width;
5159                       left_x = priv->drag_window_x = anchor;
5160                       anchor += tab_overlap;
5161                     }
5162                 }
5163
5164               gap_left = TRUE;
5165             }
5166
5167           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5168             {
5169               priv->drag_window_x = left_x;
5170               priv->drag_window_y = child_allocation.y;
5171             }
5172           else
5173             {
5174               if (allocate_at_bottom)
5175                 anchor -= child_allocation.width;
5176  
5177               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5178                 {
5179                   if (!allocate_at_bottom &&
5180                       left_x >= anchor &&
5181                       left_x <= anchor + child_allocation.width / 2)
5182                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5183                   else if (allocate_at_bottom &&
5184                            right_x >= anchor + child_allocation.width / 2 &&
5185                            right_x <= anchor + child_allocation.width)
5186                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5187                 }
5188
5189               child_allocation.x = anchor;
5190             }
5191
5192           break;
5193         case GTK_POS_LEFT:
5194         case GTK_POS_RIGHT:
5195           child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5196
5197           /* make sure that the reordered tab doesn't go past the last position */
5198           if (priv->operation == DRAG_OPERATION_REORDER &&
5199               !gap_left && packing_changed)
5200             {
5201               if (!allocate_at_bottom &&
5202                   ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5203                    (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5204                 {
5205                   top_y = priv->drag_window_y = anchor;
5206                   anchor += notebook->cur_page->allocation.height - tab_overlap;
5207                 }
5208  
5209               gap_left = TRUE;
5210             }
5211
5212           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5213             {
5214               priv->drag_window_x = child_allocation.x;
5215               priv->drag_window_y = top_y;
5216             }
5217           else
5218             {
5219               if (allocate_at_bottom)
5220                 anchor -= child_allocation.height;
5221
5222               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5223                 {
5224                   if (!allocate_at_bottom &&
5225                       top_y >= anchor &&
5226                       top_y <= anchor + child_allocation.height / 2)
5227                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5228                   else if (allocate_at_bottom &&
5229                            bottom_y >= anchor + child_allocation.height / 2 &&
5230                            bottom_y <= anchor + child_allocation.height)
5231                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5232                 }
5233
5234               child_allocation.y = anchor;
5235             }
5236
5237           break;
5238         }
5239
5240       if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5241           (page->allocation.x != child_allocation.x ||
5242            page->allocation.y != child_allocation.y ||
5243            page->allocation.width != child_allocation.width ||
5244            page->allocation.height != child_allocation.height))
5245         allocation_changed = TRUE;
5246
5247       page->allocation = child_allocation;
5248
5249       if (page == notebook->cur_page)
5250         {
5251           if (priv->operation == DRAG_OPERATION_REORDER ||
5252               priv->operation == DRAG_OPERATION_DETACH)
5253             {
5254               /* needs to be allocated at 0,0
5255                * to be shown in the drag window */
5256               page->allocation.x = 0;
5257               page->allocation.y = 0;
5258             }
5259         }
5260       else
5261         {
5262           switch (tab_pos)
5263             {
5264             case GTK_POS_TOP:
5265               page->allocation.y += ythickness;
5266               /* fall through */
5267             case GTK_POS_BOTTOM:
5268               page->allocation.height = MAX (1, page->allocation.height - ythickness);
5269               break;
5270             case GTK_POS_LEFT:
5271               page->allocation.x += xthickness;
5272               /* fall through */
5273             case GTK_POS_RIGHT:
5274               page->allocation.width = MAX (1, page->allocation.width - xthickness);
5275               break;
5276             }
5277         }
5278
5279       /* calculate whether to leave a gap based on reorder operation or not */
5280       switch (tab_pos)
5281         {
5282         case GTK_POS_TOP:
5283         case GTK_POS_BOTTOM:
5284           if (priv->operation != DRAG_OPERATION_REORDER ||
5285               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5286             {
5287               if (priv->operation == DRAG_OPERATION_REORDER)
5288                 {
5289                   if (page->pack == notebook->cur_page->pack &&
5290                       !allocate_at_bottom &&
5291                       left_x >  anchor + child_allocation.width / 2 &&
5292                       left_x <= anchor + child_allocation.width)
5293                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5294                   else if (page->pack == notebook->cur_page->pack &&
5295                            allocate_at_bottom &&
5296                            right_x >= anchor &&
5297                            right_x <= anchor + child_allocation.width / 2)
5298                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5299                 }
5300  
5301               if (!allocate_at_bottom)
5302                 anchor += child_allocation.width - tab_overlap;
5303               else
5304                 anchor += tab_overlap;
5305             }
5306
5307           break;
5308         case GTK_POS_LEFT:
5309         case GTK_POS_RIGHT:
5310           if (priv->operation != DRAG_OPERATION_REORDER  ||
5311               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5312             {
5313               if (priv->operation == DRAG_OPERATION_REORDER)
5314                 {
5315                   if (page->pack == notebook->cur_page->pack &&
5316                       !allocate_at_bottom &&
5317                       top_y >= anchor + child_allocation.height / 2 &&
5318                       top_y <= anchor + child_allocation.height)
5319                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5320                   else if (page->pack == notebook->cur_page->pack &&
5321                            allocate_at_bottom &&
5322                            bottom_y >= anchor &&
5323                            bottom_y <= anchor + child_allocation.height / 2)
5324                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5325                 }
5326
5327               if (!allocate_at_bottom)
5328                 anchor += child_allocation.height - tab_overlap;
5329               else
5330                 anchor += tab_overlap;
5331             }
5332
5333           break;
5334         }
5335
5336       /* set child visible */
5337       if (page->tab_label)
5338         gtk_widget_set_child_visible (page->tab_label, TRUE);
5339     }
5340
5341   /* Don't move the current tab past the last position during tabs reordering */
5342   if (children &&
5343       priv->operation == DRAG_OPERATION_REORDER &&
5344       ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5345        ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5346     {
5347       switch (tab_pos)
5348         {
5349         case GTK_POS_TOP:
5350         case GTK_POS_BOTTOM:
5351           if (allocate_at_bottom)
5352             anchor -= notebook->cur_page->allocation.width;
5353
5354           if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5355               (allocate_at_bottom && priv->drag_window_x < anchor))
5356             priv->drag_window_x = anchor;
5357           break;
5358         case GTK_POS_LEFT:
5359         case GTK_POS_RIGHT:
5360           if (allocate_at_bottom)
5361             anchor -= notebook->cur_page->allocation.height;
5362
5363           if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5364               (allocate_at_bottom && priv->drag_window_y < anchor))
5365             priv->drag_window_y = anchor;
5366           break;
5367         }
5368     }
5369
5370   return allocation_changed;
5371 }
5372
5373 static void
5374 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5375 {
5376   GList *children = NULL;
5377   GList *last_child = NULL;
5378   gboolean showarrow = FALSE;
5379   gint tab_space, min, max, remaining_space;
5380   gint expanded_tabs, operation;
5381
5382   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5383     return;
5384
5385   min = max = tab_space = remaining_space = 0;
5386   expanded_tabs = 1;
5387
5388   gtk_notebook_tab_space (notebook, &showarrow,
5389                           &min, &max, &tab_space);
5390
5391   gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5392                                      min, max, tab_space, &last_child,
5393                                      &expanded_tabs, &remaining_space);
5394
5395   children = notebook->first_tab;
5396   gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5397                                           showarrow, STEP_NEXT,
5398                                           &remaining_space, &expanded_tabs, min, max);
5399   if (children && children != last_child)
5400     {
5401       children = notebook->children;
5402       gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5403                                               showarrow, STEP_PREV,
5404                                               &remaining_space, &expanded_tabs, min, max);
5405     }
5406
5407   children = notebook->children;
5408
5409   while (children)
5410     {
5411       gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5412       children = children->next;
5413     }
5414
5415   operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5416
5417   if (!notebook->first_tab)
5418     notebook->first_tab = notebook->children;
5419
5420   gtk_notebook_redraw_tabs (notebook);
5421 }
5422
5423 static void
5424 gtk_notebook_page_allocate (GtkNotebook     *notebook,
5425                             GtkNotebookPage *page)
5426 {
5427   GtkWidget *widget = GTK_WIDGET (notebook);
5428   GtkAllocation child_allocation;
5429   GtkRequisition tab_requisition;
5430   gint xthickness;
5431   gint ythickness;
5432   gint padding;
5433   gint focus_width;
5434   gint tab_curvature;
5435   gint tab_pos = get_effective_tab_pos (notebook);
5436
5437   if (!page->tab_label)
5438     return;
5439
5440   xthickness = widget->style->xthickness;
5441   ythickness = widget->style->ythickness;
5442
5443   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5444   gtk_widget_style_get (widget,
5445                         "focus-line-width", &focus_width,
5446                         "tab-curvature", &tab_curvature,
5447                         NULL);
5448   switch (tab_pos)
5449     {
5450     case GTK_POS_TOP:
5451     case GTK_POS_BOTTOM:
5452       padding = tab_curvature + focus_width + notebook->tab_hborder;
5453       if (page->fill)
5454         {
5455           child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5456           child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5457           child_allocation.x += page->allocation.x;
5458         }
5459       else
5460         {
5461           child_allocation.x = page->allocation.x +
5462             (page->allocation.width - tab_requisition.width) / 2;
5463
5464           child_allocation.width = tab_requisition.width;
5465         }
5466
5467       child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5468
5469       if (tab_pos == GTK_POS_TOP)
5470         child_allocation.y += ythickness;
5471
5472       child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5473                                          2 * (notebook->tab_vborder + focus_width)));
5474       break;
5475     case GTK_POS_LEFT:
5476     case GTK_POS_RIGHT:
5477       padding = tab_curvature + focus_width + notebook->tab_vborder;
5478       if (page->fill)
5479         {
5480           child_allocation.y = ythickness + padding;
5481           child_allocation.height = MAX (1, (page->allocation.height -
5482                                              2 * child_allocation.y));
5483           child_allocation.y += page->allocation.y;
5484         }
5485       else
5486         {
5487           child_allocation.y = page->allocation.y +
5488             (page->allocation.height - tab_requisition.height) / 2;
5489
5490           child_allocation.height = tab_requisition.height;
5491         }
5492
5493       child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5494
5495       if (tab_pos == GTK_POS_LEFT)
5496         child_allocation.x += xthickness;
5497
5498       child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5499                                         2 * (notebook->tab_hborder + focus_width)));
5500       break;
5501     }
5502
5503   gtk_widget_size_allocate (page->tab_label, &child_allocation);
5504 }
5505
5506 static void 
5507 gtk_notebook_calc_tabs (GtkNotebook  *notebook,
5508                         GList        *start,
5509                         GList       **end,
5510                         gint         *tab_space,
5511                         guint         direction)
5512 {
5513   GtkNotebookPage *page = NULL;
5514   GList *children;
5515   GList *last_list = NULL;
5516   GList *last_calculated_child = NULL;
5517   gboolean pack;
5518   gint tab_pos = get_effective_tab_pos (notebook);
5519   guint real_direction;
5520
5521   if (!start)
5522     return;
5523
5524   children = start;
5525   pack = GTK_NOTEBOOK_PAGE (start)->pack;
5526   if (pack == GTK_PACK_END)
5527     real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5528   else
5529     real_direction = direction;
5530
5531   while (1)
5532     {
5533       switch (tab_pos)
5534         {
5535         case GTK_POS_TOP:
5536         case GTK_POS_BOTTOM:
5537           while (children)
5538             {
5539               page = children->data;
5540               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5541                   GTK_WIDGET_VISIBLE (page->child))
5542                 {
5543                   if (page->pack == pack)
5544                     {
5545                       *tab_space -= page->requisition.width;
5546                       if (*tab_space < 0 || children == *end)
5547                         {
5548                           if (*tab_space < 0) 
5549                             {
5550                               *tab_space = - (*tab_space +
5551                                               page->requisition.width);
5552
5553                               if (*tab_space == 0 && direction == STEP_PREV)
5554                                 children = last_calculated_child;
5555
5556                               *end = children;
5557                             }
5558                           return;
5559                         }
5560
5561                       last_calculated_child = children;
5562                     }
5563                   last_list = children;
5564                 }
5565               if (real_direction == STEP_NEXT)
5566                 children = children->next;
5567               else
5568                 children = children->prev;
5569             }
5570           break;
5571         case GTK_POS_LEFT:
5572         case GTK_POS_RIGHT:
5573           while (children)
5574             {
5575               page = children->data;
5576               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5577                   GTK_WIDGET_VISIBLE (page->child))
5578                 {
5579                   if (page->pack == pack)
5580                     {
5581                       *tab_space -= page->requisition.height;
5582                       if (*tab_space < 0 || children == *end)
5583                         {
5584                           if (*tab_space < 0)
5585                             {
5586                               *tab_space = - (*tab_space +
5587                                               page->requisition.height);
5588
5589                               if (*tab_space == 0 && direction == STEP_PREV)
5590                                 children = last_calculated_child;
5591
5592                               *end = children;
5593                             }
5594                           return;
5595                         }
5596
5597                       last_calculated_child = children;
5598                     }
5599                   last_list = children;
5600                 }
5601               if (real_direction == STEP_NEXT)
5602                 children = children->next;
5603               else
5604                 children = children->prev;
5605             }
5606           break;
5607         }
5608       if (real_direction == STEP_PREV)
5609         return;
5610       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5611       real_direction = STEP_PREV;
5612       children = last_list;
5613     }
5614 }
5615
5616 static void
5617 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5618 {
5619   GList *list;
5620
5621   for (list = notebook->children; list != NULL; list = list->next)
5622     {
5623       GtkNotebookPage *page = list->data;
5624       
5625       if (page->tab_label)
5626         {
5627           if (page == notebook->cur_page)
5628             gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5629           else
5630             gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5631         }
5632     }
5633 }
5634
5635 /* Private GtkNotebook Page Switch Methods:
5636  *
5637  * gtk_notebook_real_switch_page
5638  */
5639 static void
5640 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
5641                                GtkNotebookPage *page,
5642                                guint            page_num)
5643 {
5644   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5645   g_return_if_fail (page != NULL);
5646
5647   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5648     return;
5649
5650   if (notebook->cur_page)
5651     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5652   
5653   notebook->cur_page = page;
5654
5655   if (!notebook->focus_tab ||
5656       notebook->focus_tab->data != (gpointer) notebook->cur_page)
5657     notebook->focus_tab = 
5658       g_list_find (notebook->children, notebook->cur_page);
5659
5660   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5661
5662   /* If the focus was on the previous page, move it to the first
5663    * element on the new page, if possible, or if not, to the
5664    * notebook itself.
5665    */
5666   if (notebook->child_has_focus)
5667     {
5668       if (notebook->cur_page->last_focus_child &&
5669           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5670         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5671       else
5672         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5673           gtk_widget_grab_focus (GTK_WIDGET (notebook));
5674     }
5675   
5676   gtk_notebook_update_tab_states (notebook);
5677   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5678   g_object_notify (G_OBJECT (notebook), "page");
5679 }
5680
5681 /* Private GtkNotebook Page Switch Functions:
5682  *
5683  * gtk_notebook_switch_page
5684  * gtk_notebook_page_select
5685  * gtk_notebook_switch_focus_tab
5686  * gtk_notebook_menu_switch_page
5687  */
5688 static void
5689 gtk_notebook_switch_page (GtkNotebook     *notebook,
5690                           GtkNotebookPage *page,
5691                           gint             page_num)
5692
5693   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5694   g_return_if_fail (page != NULL);
5695  
5696   if (notebook->cur_page == page)
5697     return;
5698
5699   if (page_num < 0)
5700     page_num = g_list_index (notebook->children, page);
5701
5702   g_signal_emit (notebook,
5703                  notebook_signals[SWITCH_PAGE],
5704                  0,
5705                  page,
5706                  page_num);
5707 }
5708
5709 static gint
5710 gtk_notebook_page_select (GtkNotebook *notebook,
5711                           gboolean     move_focus)
5712 {
5713   GtkNotebookPage *page;
5714   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5715   gint tab_pos = get_effective_tab_pos (notebook);
5716
5717   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5718
5719   if (!notebook->focus_tab)
5720     return FALSE;
5721
5722   page = notebook->focus_tab->data;
5723   gtk_notebook_switch_page (notebook, page, -1);
5724
5725   if (move_focus)
5726     {
5727       switch (tab_pos)
5728         {
5729         case GTK_POS_TOP:
5730           dir = GTK_DIR_DOWN;
5731           break;
5732         case GTK_POS_BOTTOM:
5733           dir = GTK_DIR_UP;
5734           break;
5735         case GTK_POS_LEFT:
5736           dir = GTK_DIR_RIGHT;
5737           break;
5738         case GTK_POS_RIGHT:
5739           dir = GTK_DIR_LEFT;
5740           break;
5741         }
5742
5743       if (gtk_widget_child_focus (page->child, dir))
5744         return TRUE;
5745     }
5746   return FALSE;
5747 }
5748
5749 static void
5750 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
5751                                GList       *new_child)
5752 {
5753   GList *old_child;
5754   GtkNotebookPage *page;
5755
5756   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5757
5758   if (notebook->focus_tab == new_child)
5759     return;
5760
5761   old_child = notebook->focus_tab;
5762   notebook->focus_tab = new_child;
5763
5764   if (notebook->scrollable)
5765     gtk_notebook_redraw_arrows (notebook);
5766
5767   if (!notebook->show_tabs || !notebook->focus_tab)
5768     return;
5769
5770   page = notebook->focus_tab->data;
5771   if (GTK_WIDGET_MAPPED (page->tab_label))
5772     gtk_notebook_redraw_tabs (notebook);
5773   else
5774     gtk_notebook_pages_allocate (notebook);
5775   
5776   gtk_notebook_switch_page (notebook, page,
5777                             g_list_index (notebook->children, page));
5778 }
5779
5780 static void
5781 gtk_notebook_menu_switch_page (GtkWidget       *widget,
5782                                GtkNotebookPage *page)
5783 {
5784   GtkNotebook *notebook;
5785   GList *children;
5786   guint page_num;
5787
5788   g_return_if_fail (widget != NULL);
5789   g_return_if_fail (page != NULL);
5790
5791   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5792                            (GTK_MENU (widget->parent)));
5793
5794   if (notebook->cur_page == page)
5795     return;
5796
5797   page_num = 0;
5798   children = notebook->children;
5799   while (children && children->data != page)
5800     {
5801       children = children->next;
5802       page_num++;
5803     }
5804
5805   g_signal_emit (notebook,
5806                  notebook_signals[SWITCH_PAGE],
5807                  0,
5808                  page,
5809                  page_num);
5810 }
5811
5812 /* Private GtkNotebook Menu Functions:
5813  *
5814  * gtk_notebook_menu_item_create
5815  * gtk_notebook_menu_label_unparent
5816  * gtk_notebook_menu_detacher
5817  */
5818 static void
5819 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
5820                                GList       *list)
5821 {       
5822   GtkNotebookPage *page;
5823   GtkWidget *menu_item;
5824
5825   page = list->data;
5826   if (page->default_menu)
5827     {
5828       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5829         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5830       else
5831         page->menu_label = gtk_label_new ("");
5832       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5833     }
5834
5835   gtk_widget_show (page->menu_label);
5836   menu_item = gtk_menu_item_new ();
5837   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5838   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5839                          gtk_notebook_real_page_position (notebook, list));
5840   g_signal_connect (menu_item, "activate",
5841                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
5842   if (GTK_WIDGET_VISIBLE (page->child))
5843     gtk_widget_show (menu_item);
5844 }
5845
5846 static void
5847 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
5848                                   gpointer  data)
5849 {
5850   gtk_widget_unparent (GTK_BIN (widget)->child);
5851   GTK_BIN (widget)->child = NULL;
5852 }
5853
5854 static void
5855 gtk_notebook_menu_detacher (GtkWidget *widget,
5856                             GtkMenu   *menu)
5857 {
5858   GtkNotebook *notebook;
5859
5860   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5861
5862   notebook = GTK_NOTEBOOK (widget);
5863   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5864
5865   notebook->menu = NULL;
5866 }
5867
5868 /* Private GtkNotebook Setter Functions:
5869  *
5870  * gtk_notebook_set_homogeneous_tabs_internal
5871  * gtk_notebook_set_tab_border_internal
5872  * gtk_notebook_set_tab_hborder_internal
5873  * gtk_notebook_set_tab_vborder_internal
5874  */
5875 static void
5876 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5877                                             gboolean     homogeneous)
5878 {
5879   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5880
5881   if (homogeneous == notebook->homogeneous)
5882     return;
5883
5884   notebook->homogeneous = homogeneous;
5885   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5886
5887   g_object_notify (G_OBJECT (notebook), "homogeneous");
5888 }
5889
5890 static void
5891 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5892                                       guint        border_width)
5893 {
5894   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5895
5896   notebook->tab_hborder = border_width;
5897   notebook->tab_vborder = border_width;
5898
5899   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5900     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5901
5902   g_object_freeze_notify (G_OBJECT (notebook));
5903   g_object_notify (G_OBJECT (notebook), "tab-hborder");
5904   g_object_notify (G_OBJECT (notebook), "tab-vborder");
5905   g_object_thaw_notify (G_OBJECT (notebook));
5906 }
5907
5908 static void
5909 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5910                                        guint        tab_hborder)
5911 {
5912   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5913
5914   if (notebook->tab_hborder == tab_hborder)
5915     return;
5916
5917   notebook->tab_hborder = tab_hborder;
5918
5919   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5920     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5921
5922   g_object_notify (G_OBJECT (notebook), "tab-hborder");
5923 }
5924
5925 static void
5926 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5927                                        guint        tab_vborder)
5928 {
5929   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5930
5931   if (notebook->tab_vborder == tab_vborder)
5932     return;
5933
5934   notebook->tab_vborder = tab_vborder;
5935
5936   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5937     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5938
5939   g_object_notify (G_OBJECT (notebook), "tab-vborder");
5940 }
5941
5942 /* Public GtkNotebook Page Insert/Remove Methods :
5943  *
5944  * gtk_notebook_append_page
5945  * gtk_notebook_append_page_menu
5946  * gtk_notebook_prepend_page
5947  * gtk_notebook_prepend_page_menu
5948  * gtk_notebook_insert_page
5949  * gtk_notebook_insert_page_menu
5950  * gtk_notebook_remove_page
5951  */
5952 /**
5953  * gtk_notebook_append_page:
5954  * @notebook: a #GtkNotebook
5955  * @child: the #GtkWidget to use as the contents of the page.
5956  * @tab_label: the #GtkWidget to be used as the label for the page,
5957  *             or %NULL to use the default label, 'page N'.
5958  * 
5959  * Appends a page to @notebook.
5960  *
5961  * Return value: the index (starting from 0) of the appended
5962  * page in the notebook, or -1 if function fails
5963  **/
5964 gint
5965 gtk_notebook_append_page (GtkNotebook *notebook,
5966                           GtkWidget   *child,
5967                           GtkWidget   *tab_label)
5968 {
5969   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5970   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5971   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5972   
5973   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5974 }
5975
5976 /**
5977  * gtk_notebook_append_page_menu:
5978  * @notebook: a #GtkNotebook
5979  * @child: the #GtkWidget to use as the contents of the page.
5980  * @tab_label: the #GtkWidget to be used as the label for the page,
5981  *             or %NULL to use the default label, 'page N'.
5982  * @menu_label: the widget to use as a label for the page-switch
5983  *              menu, if that is enabled. If %NULL, and @tab_label
5984  *              is a #GtkLabel or %NULL, then the menu label will be
5985  *              a newly created label with the same text as @tab_label;
5986  *              If @tab_label is not a #GtkLabel, @menu_label must be
5987  *              specified if the page-switch menu is to be used.
5988  * 
5989  * Appends a page to @notebook, specifying the widget to use as the
5990  * label in the popup menu.
5991  *
5992  * Return value: the index (starting from 0) of the appended
5993  * page in the notebook, or -1 if function fails
5994  **/
5995 gint
5996 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5997                                GtkWidget   *child,
5998                                GtkWidget   *tab_label,
5999                                GtkWidget   *menu_label)
6000 {
6001   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6002   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6003   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6004   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6005   
6006   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6007 }
6008
6009 /**
6010  * gtk_notebook_prepend_page:
6011  * @notebook: a #GtkNotebook
6012  * @child: the #GtkWidget to use as the contents of the page.
6013  * @tab_label: the #GtkWidget to be used as the label for the page,
6014  *             or %NULL to use the default label, 'page N'.
6015  *
6016  * Prepends a page to @notebook.
6017  *
6018  * Return value: the index (starting from 0) of the prepended
6019  * page in the notebook, or -1 if function fails
6020  **/
6021 gint
6022 gtk_notebook_prepend_page (GtkNotebook *notebook,
6023                            GtkWidget   *child,
6024                            GtkWidget   *tab_label)
6025 {
6026   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6027   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6028   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6029   
6030   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6031 }
6032
6033 /**
6034  * gtk_notebook_prepend_page_menu:
6035  * @notebook: a #GtkNotebook
6036  * @child: the #GtkWidget to use as the contents of the page.
6037  * @tab_label: the #GtkWidget to be used as the label for the page,
6038  *             or %NULL to use the default label, 'page N'.
6039  * @menu_label: the widget to use as a label for the page-switch
6040  *              menu, if that is enabled. If %NULL, and @tab_label
6041  *              is a #GtkLabel or %NULL, then the menu label will be
6042  *              a newly created label with the same text as @tab_label;
6043  *              If @tab_label is not a #GtkLabel, @menu_label must be
6044  *              specified if the page-switch menu is to be used.
6045  * 
6046  * Prepends a page to @notebook, specifying the widget to use as the
6047  * label in the popup menu.
6048  *
6049  * Return value: the index (starting from 0) of the prepended
6050  * page in the notebook, or -1 if function fails
6051  **/
6052 gint
6053 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6054                                 GtkWidget   *child,
6055                                 GtkWidget   *tab_label,
6056                                 GtkWidget   *menu_label)
6057 {
6058   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6059   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6060   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6061   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6062   
6063   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6064 }
6065
6066 /**
6067  * gtk_notebook_insert_page:
6068  * @notebook: a #GtkNotebook
6069  * @child: the #GtkWidget to use as the contents of the page.
6070  * @tab_label: the #GtkWidget to be used as the label for the page,
6071  *             or %NULL to use the default label, 'page N'.
6072  * @position: the index (starting at 0) at which to insert the page,
6073  *            or -1 to append the page after all other pages.
6074  * 
6075  * Insert a page into @notebook at the given position.
6076  *
6077  * Return value: the index (starting from 0) of the inserted
6078  * page in the notebook, or -1 if function fails
6079  **/
6080 gint
6081 gtk_notebook_insert_page (GtkNotebook *notebook,
6082                           GtkWidget   *child,
6083                           GtkWidget   *tab_label,
6084                           gint         position)
6085 {
6086   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6087   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6088   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6089   
6090   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6091 }
6092
6093
6094 static gint
6095 gtk_notebook_page_compare_tab (gconstpointer a,
6096                                gconstpointer b)
6097 {
6098   return (((GtkNotebookPage *) a)->tab_label != b);
6099 }
6100
6101 static gboolean
6102 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6103                                             gboolean overload,
6104                                             gpointer data)
6105 {
6106   GtkNotebook *notebook = GTK_NOTEBOOK (data);
6107   GList *list;
6108   
6109   list = g_list_find_custom (notebook->children, child,
6110                              gtk_notebook_page_compare_tab);
6111   if (list)
6112     {
6113       GtkNotebookPage *page = list->data;
6114
6115       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
6116       gtk_notebook_switch_page (notebook, page,  -1);
6117       focus_tabs_in (notebook);
6118     }
6119
6120   return TRUE;
6121 }
6122
6123 /**
6124  * gtk_notebook_insert_page_menu:
6125  * @notebook: a #GtkNotebook
6126  * @child: the #GtkWidget to use as the contents of the page.
6127  * @tab_label: the #GtkWidget to be used as the label for the page,
6128  *             or %NULL to use the default label, 'page N'.
6129  * @menu_label: the widget to use as a label for the page-switch
6130  *              menu, if that is enabled. If %NULL, and @tab_label
6131  *              is a #GtkLabel or %NULL, then the menu label will be
6132  *              a newly created label with the same text as @tab_label;
6133  *              If @tab_label is not a #GtkLabel, @menu_label must be
6134  *              specified if the page-switch menu is to be used.
6135  * @position: the index (starting at 0) at which to insert the page,
6136  *            or -1 to append the page after all other pages.
6137  * 
6138  * Insert a page into @notebook at the given position, specifying
6139  * the widget to use as the label in the popup menu.
6140  *
6141  * Return value: the index (starting from 0) of the inserted
6142  * page in the notebook
6143  **/
6144 gint
6145 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6146                                GtkWidget   *child,
6147                                GtkWidget   *tab_label,
6148                                GtkWidget   *menu_label,
6149                                gint         position)
6150 {
6151   GtkNotebookClass *class;
6152
6153   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6154   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6155   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6156   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6157
6158   class = GTK_NOTEBOOK_GET_CLASS (notebook);
6159
6160   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6161 }
6162
6163 /**
6164  * gtk_notebook_remove_page:
6165  * @notebook: a #GtkNotebook.
6166  * @page_num: the index of a notebook page, starting
6167  *            from 0. If -1, the last page will
6168  *            be removed.
6169  * 
6170  * Removes a page from the notebook given its index
6171  * in the notebook.
6172  **/
6173 void
6174 gtk_notebook_remove_page (GtkNotebook *notebook,
6175                           gint         page_num)
6176 {
6177   GList *list = NULL;
6178
6179   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6180
6181   if (page_num >= 0)
6182     list = g_list_nth (notebook->children, page_num);
6183   else
6184     list = g_list_last (notebook->children);
6185
6186   if (list)
6187     gtk_container_remove (GTK_CONTAINER (notebook),
6188                           ((GtkNotebookPage *) list->data)->child);
6189 }
6190
6191 /* Public GtkNotebook Page Switch Methods :
6192  * gtk_notebook_get_current_page
6193  * gtk_notebook_page_num
6194  * gtk_notebook_set_current_page
6195  * gtk_notebook_next_page
6196  * gtk_notebook_prev_page
6197  */
6198 /**
6199  * gtk_notebook_get_current_page:
6200  * @notebook: a #GtkNotebook
6201  * 
6202  * Returns the page number of the current page.
6203  * 
6204  * Return value: the index (starting from 0) of the current
6205  * page in the notebook. If the notebook has no pages, then
6206  * -1 will be returned.
6207  **/
6208 gint
6209 gtk_notebook_get_current_page (GtkNotebook *notebook)
6210 {
6211   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6212
6213   if (!notebook->cur_page)
6214     return -1;
6215
6216   return g_list_index (notebook->children, notebook->cur_page);
6217 }
6218
6219 /**
6220  * gtk_notebook_get_nth_page:
6221  * @notebook: a #GtkNotebook
6222  * @page_num: the index of a page in the noteobok, or -1
6223  *            to get the last page.
6224  * 
6225  * Returns the child widget contained in page number @page_num.
6226  * 
6227  * Return value: the child widget, or %NULL if @page_num is
6228  * out of bounds.
6229  **/
6230 GtkWidget*
6231 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6232                            gint         page_num)
6233 {
6234   GtkNotebookPage *page;
6235   GList *list;
6236
6237   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6238
6239   if (page_num >= 0)
6240     list = g_list_nth (notebook->children, page_num);
6241   else
6242     list = g_list_last (notebook->children);
6243
6244   if (list)
6245     {
6246       page = list->data;
6247       return page->child;
6248     }
6249
6250   return NULL;
6251 }
6252
6253 /**
6254  * gtk_notebook_get_n_pages:
6255  * @notebook: a #GtkNotebook
6256  * 
6257  * Gets the number of pages in a notebook.
6258  * 
6259  * Return value: the number of pages in the notebook.
6260  *
6261  * Since: 2.2
6262  **/
6263 gint
6264 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6265 {
6266   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6267
6268   return g_list_length (notebook->children);
6269 }
6270
6271 /**
6272  * gtk_notebook_page_num:
6273  * @notebook: a #GtkNotebook
6274  * @child: a #GtkWidget
6275  * 
6276  * Finds the index of the page which contains the given child
6277  * widget.
6278  * 
6279  * Return value: the index of the page containing @child, or
6280  *   -1 if @child is not in the notebook.
6281  **/
6282 gint
6283 gtk_notebook_page_num (GtkNotebook      *notebook,
6284                        GtkWidget        *child)
6285 {
6286   GList *children;
6287   gint num;
6288
6289   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6290
6291   num = 0;
6292   children = notebook->children;
6293   while (children)
6294     {
6295       GtkNotebookPage *page =  children->data;
6296       
6297       if (page->child == child)
6298         return num;
6299
6300       children = children->next;
6301       num++;
6302     }
6303
6304   return -1;
6305 }
6306
6307 /**
6308  * gtk_notebook_set_current_page:
6309  * @notebook: a #GtkNotebook
6310  * @page_num: index of the page to switch to, starting from 0.
6311  *            If negative, the last page will be used. If greater
6312  *            than the number of pages in the notebook, nothing
6313  *            will be done.
6314  *                
6315  * Switches to the page number @page_num. 
6316  *
6317  * Note that due to historical reasons, GtkNotebook refuses
6318  * to switch to a page unless the child widget is visible. 
6319  * Therefore, it is recommended to show child widgets before
6320  * adding them to a notebook. 
6321  */
6322 void
6323 gtk_notebook_set_current_page (GtkNotebook *notebook,
6324                                gint         page_num)
6325 {
6326   GList *list;
6327
6328   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6329
6330   if (page_num >= 0)
6331     list = g_list_nth (notebook->children, page_num);
6332   else
6333     list = g_list_last (notebook->children);
6334
6335   page_num = g_list_index (notebook->children, list);
6336
6337   if (list)
6338     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6339 }
6340
6341 /**
6342  * gtk_notebook_next_page:
6343  * @notebook: a #GtkNotebook
6344  * 
6345  * Switches to the next page. Nothing happens if the current page is
6346  * the last page.
6347  **/
6348 void
6349 gtk_notebook_next_page (GtkNotebook *notebook)
6350 {
6351   GList *list;
6352
6353   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6354
6355   list = g_list_find (notebook->children, notebook->cur_page);
6356   if (!list)
6357     return;
6358
6359   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6360   if (!list)
6361     return;
6362
6363   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6364 }
6365
6366 /**
6367  * gtk_notebook_prev_page:
6368  * @notebook: a #GtkNotebook
6369  * 
6370  * Switches to the previous page. Nothing happens if the current page
6371  * is the first page.
6372  **/
6373 void
6374 gtk_notebook_prev_page (GtkNotebook *notebook)
6375 {
6376   GList *list;
6377
6378   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6379
6380   list = g_list_find (notebook->children, notebook->cur_page);
6381   if (!list)
6382     return;
6383
6384   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6385   if (!list)
6386     return;
6387
6388   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6389 }
6390
6391 /* Public GtkNotebook/Tab Style Functions
6392  *
6393  * gtk_notebook_set_show_border
6394  * gtk_notebook_set_show_tabs
6395  * gtk_notebook_set_tab_pos
6396  * gtk_notebook_set_homogeneous_tabs
6397  * gtk_notebook_set_tab_border
6398  * gtk_notebook_set_tab_hborder
6399  * gtk_notebook_set_tab_vborder
6400  * gtk_notebook_set_scrollable
6401  */
6402 /**
6403  * gtk_notebook_set_show_border:
6404  * @notebook: a #GtkNotebook
6405  * @show_border: %TRUE if a bevel should be drawn around the notebook.
6406  * 
6407  * Sets whether a bevel will be drawn around the notebook pages.
6408  * This only has a visual effect when the tabs are not shown.
6409  * See gtk_notebook_set_show_tabs().
6410  **/
6411 void
6412 gtk_notebook_set_show_border (GtkNotebook *notebook,
6413                               gboolean     show_border)
6414 {
6415   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6416
6417   if (notebook->show_border != show_border)
6418     {
6419       notebook->show_border = show_border;
6420
6421       if (GTK_WIDGET_VISIBLE (notebook))
6422         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6423       
6424       g_object_notify (G_OBJECT (notebook), "show-border");
6425     }
6426 }
6427
6428 /**
6429  * gtk_notebook_get_show_border:
6430  * @notebook: a #GtkNotebook
6431  *
6432  * Returns whether a bevel will be drawn around the notebook pages. See
6433  * gtk_notebook_set_show_border().
6434  *
6435  * Return value: %TRUE if the bevel is drawn
6436  **/
6437 gboolean
6438 gtk_notebook_get_show_border (GtkNotebook *notebook)
6439 {
6440   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6441
6442   return notebook->show_border;
6443 }
6444
6445 /**
6446  * gtk_notebook_set_show_tabs:
6447  * @notebook: a #GtkNotebook
6448  * @show_tabs: %TRUE if the tabs should be shown.
6449  * 
6450  * Sets whether to show the tabs for the notebook or not.
6451  **/
6452 void
6453 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6454                             gboolean     show_tabs)
6455 {
6456   GtkNotebookPage *page;
6457   GList *children;
6458
6459   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6460
6461   show_tabs = show_tabs != FALSE;
6462
6463   if (notebook->show_tabs == show_tabs)
6464     return;
6465
6466   notebook->show_tabs = show_tabs;
6467   children = notebook->children;
6468
6469   if (!show_tabs)
6470     {
6471       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6472       
6473       while (children)
6474         {
6475           page = children->data;
6476           children = children->next;
6477           if (page->default_tab)
6478             {
6479               gtk_widget_destroy (page->tab_label);
6480               page->tab_label = NULL;
6481             }
6482           else
6483             gtk_widget_hide (page->tab_label);
6484         }
6485     }
6486   else
6487     {
6488       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6489       gtk_notebook_update_labels (notebook);
6490     }
6491   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6492
6493   g_object_notify (G_OBJECT (notebook), "show-tabs");
6494 }
6495
6496 /**
6497  * gtk_notebook_get_show_tabs:
6498  * @notebook: a #GtkNotebook
6499  *
6500  * Returns whether the tabs of the notebook are shown. See
6501  * gtk_notebook_set_show_tabs().
6502  *
6503  * Return value: %TRUE if the tabs are shown
6504  **/
6505 gboolean
6506 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6507 {
6508   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6509
6510   return notebook->show_tabs;
6511 }
6512
6513 /**
6514  * gtk_notebook_set_tab_pos:
6515  * @notebook: a #GtkNotebook.
6516  * @pos: the edge to draw the tabs at.
6517  * 
6518  * Sets the edge at which the tabs for switching pages in the
6519  * notebook are drawn.
6520  **/
6521 void
6522 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6523                           GtkPositionType  pos)
6524 {
6525   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6526
6527   if (notebook->tab_pos != pos)
6528     {
6529       notebook->tab_pos = pos;
6530       if (GTK_WIDGET_VISIBLE (notebook))
6531         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6532     }
6533
6534   g_object_notify (G_OBJECT (notebook), "tab-pos");
6535 }
6536
6537 /**
6538  * gtk_notebook_get_tab_pos:
6539  * @notebook: a #GtkNotebook
6540  *
6541  * Gets the edge at which the tabs for switching pages in the
6542  * notebook are drawn.
6543  *
6544  * Return value: the edge at which the tabs are drawn
6545  **/
6546 GtkPositionType
6547 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6548 {
6549   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6550
6551   return notebook->tab_pos;
6552 }
6553
6554 /**
6555  * gtk_notebook_set_homogeneous_tabs:
6556  * @notebook: a #GtkNotebook
6557  * @homogeneous: %TRUE if all tabs should be the same size.
6558  * 
6559  * Sets whether the tabs must have all the same size or not.
6560  **/
6561 void
6562 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6563                                    gboolean     homogeneous)
6564 {
6565   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6566
6567   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6568 }
6569
6570 /**
6571  * gtk_notebook_set_tab_border:
6572  * @notebook: a #GtkNotebook
6573  * @border_width: width of the border around the tab labels.
6574  * 
6575  * Sets the width the border around the tab labels
6576  * in a notebook. This is equivalent to calling
6577  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6578  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6579  **/
6580 void
6581 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6582                              guint        border_width)
6583 {
6584   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6585
6586   gtk_notebook_set_tab_border_internal (notebook, border_width);
6587 }
6588
6589 /**
6590  * gtk_notebook_set_tab_hborder:
6591  * @notebook: a #GtkNotebook
6592  * @tab_hborder: width of the horizontal border of tab labels.
6593  * 
6594  * Sets the width of the horizontal border of tab labels.
6595  **/
6596 void
6597 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6598                               guint        tab_hborder)
6599 {
6600   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6601
6602   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6603 }
6604
6605 /**
6606  * gtk_notebook_set_tab_vborder:
6607  * @notebook: a #GtkNotebook
6608  * @tab_vborder: width of the vertical border of tab labels.
6609  * 
6610  * Sets the width of the vertical border of tab labels.
6611  **/
6612 void
6613 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6614                               guint        tab_vborder)
6615 {
6616   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6617
6618   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6619 }
6620
6621 /**
6622  * gtk_notebook_set_scrollable:
6623  * @notebook: a #GtkNotebook
6624  * @scrollable: %TRUE if scroll arrows should be added
6625  * 
6626  * Sets whether the tab label area will have arrows for scrolling if
6627  * there are too many tabs to fit in the area.
6628  **/
6629 void
6630 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6631                              gboolean     scrollable)
6632 {
6633   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6634
6635   scrollable = (scrollable != FALSE);
6636
6637   if (scrollable != notebook->scrollable)
6638     {
6639       notebook->scrollable = scrollable;
6640
6641       if (GTK_WIDGET_VISIBLE (notebook))
6642         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6643
6644       g_object_notify (G_OBJECT (notebook), "scrollable");
6645     }
6646 }
6647
6648 /**
6649  * gtk_notebook_get_scrollable:
6650  * @notebook: a #GtkNotebook
6651  *
6652  * Returns whether the tab label area has arrows for scrolling. See
6653  * gtk_notebook_set_scrollable().
6654  *
6655  * Return value: %TRUE if arrows for scrolling are present
6656  **/
6657 gboolean
6658 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6659 {
6660   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6661
6662   return notebook->scrollable;
6663 }
6664
6665 /* Public GtkNotebook Popup Menu Methods:
6666  *
6667  * gtk_notebook_popup_enable
6668  * gtk_notebook_popup_disable
6669  */
6670
6671
6672 /**
6673  * gtk_notebook_popup_enable:
6674  * @notebook: a #GtkNotebook
6675  * 
6676  * Enables the popup menu: if the user clicks with the right mouse button on
6677  * the bookmarks, a menu with all the pages will be popped up.
6678  **/
6679 void
6680 gtk_notebook_popup_enable (GtkNotebook *notebook)
6681 {
6682   GList *list;
6683
6684   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6685
6686   if (notebook->menu)
6687     return;
6688
6689   notebook->menu = gtk_menu_new ();
6690   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6691        list;
6692        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6693     gtk_notebook_menu_item_create (notebook, list);
6694
6695   gtk_notebook_update_labels (notebook);
6696   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6697                              GTK_WIDGET (notebook),
6698                              gtk_notebook_menu_detacher);
6699
6700   g_object_notify (G_OBJECT (notebook), "enable-popup");
6701 }
6702
6703 /**
6704  * gtk_notebook_popup_disable:
6705  * @notebook: a #GtkNotebook
6706  * 
6707  * Disables the popup menu.
6708  **/
6709 void       
6710 gtk_notebook_popup_disable  (GtkNotebook *notebook)
6711 {
6712   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6713
6714   if (!notebook->menu)
6715     return;
6716
6717   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6718                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6719   gtk_widget_destroy (notebook->menu);
6720
6721   g_object_notify (G_OBJECT (notebook), "enable-popup");
6722 }
6723
6724 /* Public GtkNotebook Page Properties Functions:
6725  *
6726  * gtk_notebook_get_tab_label
6727  * gtk_notebook_set_tab_label
6728  * gtk_notebook_set_tab_label_text
6729  * gtk_notebook_get_menu_label
6730  * gtk_notebook_set_menu_label
6731  * gtk_notebook_set_menu_label_text
6732  * gtk_notebook_set_tab_label_packing
6733  * gtk_notebook_query_tab_label_packing
6734  * gtk_notebook_get_tab_reorderable
6735  * gtk_notebook_set_tab_reorderable
6736  * gtk_notebook_get_tab_detachable
6737  * gtk_notebook_set_tab_detachable
6738  */
6739
6740 /**
6741  * gtk_notebook_get_tab_label:
6742  * @notebook: a #GtkNotebook
6743  * @child: the page
6744  * 
6745  * Returns the tab label widget for the page @child. %NULL is returned
6746  * if @child is not in @notebook or if no tab label has specifically
6747  * been set for @child.
6748  * 
6749  * Return value: the tab label
6750  **/
6751 GtkWidget *
6752 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6753                             GtkWidget   *child)
6754 {
6755   GList *list;
6756
6757   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6758   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6759
6760   list = CHECK_FIND_CHILD (notebook, child);
6761   if (!list)  
6762     return NULL;
6763
6764   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6765     return NULL;
6766
6767   return GTK_NOTEBOOK_PAGE (list)->tab_label;
6768 }  
6769
6770 /**
6771  * gtk_notebook_set_tab_label:
6772  * @notebook: a #GtkNotebook
6773  * @child: the page
6774  * @tab_label: the tab label widget to use, or %NULL for default tab
6775  *             label.
6776  * 
6777  * Changes the tab label for @child. If %NULL is specified
6778  * for @tab_label, then the page will have the label 'page N'.
6779  **/
6780 void
6781 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6782                             GtkWidget   *child,
6783                             GtkWidget   *tab_label)
6784 {
6785   GtkNotebookPage *page;
6786   GList *list;
6787
6788   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6789   g_return_if_fail (GTK_IS_WIDGET (child));
6790
6791   list = CHECK_FIND_CHILD (notebook, child);
6792   if (!list)  
6793     return;
6794
6795   /* a NULL pointer indicates a default_tab setting, otherwise
6796    * we need to set the associated label
6797    */
6798   page = list->data;
6799   
6800   if (page->tab_label == tab_label)
6801     return;
6802   
6803
6804   gtk_notebook_remove_tab_label (notebook, page);
6805   
6806   if (tab_label)
6807     {
6808       page->default_tab = FALSE;
6809       page->tab_label = tab_label;
6810       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6811     }
6812   else
6813     {
6814       page->default_tab = TRUE;
6815       page->tab_label = NULL;
6816
6817       if (notebook->show_tabs)
6818         {
6819           gchar string[32];
6820
6821           g_snprintf (string, sizeof(string), _("Page %u"), 
6822                       gtk_notebook_real_page_position (notebook, list));
6823           page->tab_label = gtk_label_new (string);
6824           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6825         }
6826     }
6827
6828   if (page->tab_label)
6829     page->mnemonic_activate_signal =
6830       g_signal_connect (page->tab_label,
6831                         "mnemonic_activate",
6832                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6833                         notebook);
6834
6835   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6836     {
6837       gtk_widget_show (page->tab_label);
6838       gtk_widget_queue_resize (GTK_WIDGET (notebook));
6839     }
6840
6841   gtk_notebook_update_tab_states (notebook);
6842   gtk_widget_child_notify (child, "tab-label");
6843 }
6844
6845 /**
6846  * gtk_notebook_set_tab_label_text:
6847  * @notebook: a #GtkNotebook
6848  * @child: the page
6849  * @tab_text: the label text
6850  * 
6851  * Creates a new label and sets it as the tab label for the page
6852  * containing @child.
6853  **/
6854 void
6855 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6856                                  GtkWidget   *child,
6857                                  const gchar *tab_text)
6858 {
6859   GtkWidget *tab_label = NULL;
6860
6861   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6862
6863   if (tab_text)
6864     tab_label = gtk_label_new (tab_text);
6865   gtk_notebook_set_tab_label (notebook, child, tab_label);
6866   gtk_widget_child_notify (child, "tab-label");
6867 }
6868
6869 /**
6870  * gtk_notebook_get_tab_label_text:
6871  * @notebook: a #GtkNotebook
6872  * @child: a widget contained in a page of @notebook
6873  *
6874  * Retrieves the text of the tab label for the page containing
6875  *    @child.
6876  *
6877  * Returns value: the text of the tab label, or %NULL if the
6878  *                tab label widget is not a #GtkLabel. The
6879  *                string is owned by the widget and must not
6880  *                be freed.
6881  **/
6882 G_CONST_RETURN gchar *
6883 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6884                                  GtkWidget   *child)
6885 {
6886   GtkWidget *tab_label;
6887
6888   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6889   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6890
6891   tab_label = gtk_notebook_get_tab_label (notebook, child);
6892
6893   if (tab_label && GTK_IS_LABEL (tab_label))
6894     return gtk_label_get_text (GTK_LABEL (tab_label));
6895   else
6896     return NULL;
6897 }
6898
6899 /**
6900  * gtk_notebook_get_menu_label:
6901  * @notebook: a #GtkNotebook
6902  * @child: a widget contained in a page of @notebook
6903  * 
6904  * Retrieves the menu label widget of the page containing @child.
6905  * 
6906  * Return value: the menu label, or %NULL if the
6907  *               notebook page does not have a menu label other
6908  *               than the default (the tab label).
6909  **/
6910 GtkWidget*
6911 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6912                              GtkWidget   *child)
6913 {
6914   GList *list;
6915
6916   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6917   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6918
6919   list = CHECK_FIND_CHILD (notebook, child);
6920   if (!list)  
6921     return NULL;
6922
6923   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6924     return NULL;
6925
6926   return GTK_NOTEBOOK_PAGE (list)->menu_label;
6927 }  
6928
6929 /**
6930  * gtk_notebook_set_menu_label:
6931  * @notebook: a #GtkNotebook
6932  * @child: the child widget
6933  * @menu_label: the menu label, or NULL for default
6934  * 
6935  * Changes the menu label for the page containing @child. 
6936  **/
6937 void
6938 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6939                              GtkWidget   *child,
6940                              GtkWidget   *menu_label)
6941 {
6942   GtkNotebookPage *page;
6943   GList *list;
6944
6945   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6946   g_return_if_fail (GTK_IS_WIDGET (child));
6947
6948   list = CHECK_FIND_CHILD (notebook, child);
6949   if (!list)  
6950     return;
6951
6952   page = list->data;
6953   if (page->menu_label)
6954     {
6955       if (notebook->menu)
6956         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
6957                               page->menu_label->parent);
6958
6959       if (!page->default_menu)
6960         g_object_unref (page->menu_label);
6961     }
6962
6963   if (menu_label)
6964     {
6965       page->menu_label = menu_label;
6966       g_object_ref_sink (page->menu_label);
6967       page->default_menu = FALSE;
6968     }
6969   else
6970     page->default_menu = TRUE;
6971
6972   if (notebook->menu)
6973     gtk_notebook_menu_item_create (notebook, list);
6974   gtk_widget_child_notify (child, "menu-label");
6975 }
6976
6977 /**
6978  * gtk_notebook_set_menu_label_text:
6979  * @notebook: a #GtkNotebook
6980  * @child: the child widget
6981  * @menu_text: the label text
6982  * 
6983  * Creates a new label and sets it as the menu label of @child.
6984  **/
6985 void
6986 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6987                                   GtkWidget   *child,
6988                                   const gchar *menu_text)
6989 {
6990   GtkWidget *menu_label = NULL;
6991
6992   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6993
6994   if (menu_text)
6995     menu_label = gtk_label_new (menu_text);
6996   gtk_notebook_set_menu_label (notebook, child, menu_label);
6997   gtk_widget_child_notify (child, "menu-label");
6998 }
6999
7000 /**
7001  * gtk_notebook_get_menu_label_text:
7002  * @notebook: a #GtkNotebook
7003  * @child: the child widget of a page of the notebook.
7004  *
7005  * Retrieves the text of the menu label for the page containing
7006  *    @child.
7007  *
7008  * Returns value: the text of the tab label, or %NULL if the
7009  *                widget does not have a menu label other than
7010  *                the default menu label, or the menu label widget
7011  *                is not a #GtkLabel. The string is owned by
7012  *                the widget and must not be freed.
7013  **/
7014 G_CONST_RETURN gchar *
7015 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7016                                   GtkWidget *child)
7017 {
7018   GtkWidget *menu_label;
7019
7020   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7021   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7022  
7023   menu_label = gtk_notebook_get_menu_label (notebook, child);
7024
7025   if (menu_label && GTK_IS_LABEL (menu_label))
7026     return gtk_label_get_text (GTK_LABEL (menu_label));
7027   else
7028     return NULL;
7029 }
7030   
7031 /* Helper function called when pages are reordered
7032  */
7033 static void
7034 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7035                               GtkNotebookPage *page)
7036 {
7037   if (notebook->menu)
7038     {
7039       GtkWidget *menu_item;
7040       
7041       menu_item = page->menu_label->parent;
7042       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7043       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7044       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7045     }
7046
7047   gtk_notebook_update_tab_states (notebook);
7048   gtk_notebook_update_labels (notebook);
7049 }
7050
7051 /**
7052  * gtk_notebook_set_tab_label_packing:
7053  * @notebook: a #GtkNotebook
7054  * @child: the child widget
7055  * @expand: whether to expand the bookmark or not
7056  * @fill: whether the bookmark should fill the allocated area or not
7057  * @pack_type: the position of the bookmark
7058  * 
7059  * Sets the packing parameters for the tab label of the page
7060  * containing @child. See gtk_box_pack_start() for the exact meaning
7061  * of the parameters.
7062  **/
7063 void
7064 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7065                                     GtkWidget   *child,
7066                                     gboolean     expand,
7067                                     gboolean     fill,
7068                                     GtkPackType  pack_type)
7069 {
7070   GtkNotebookPage *page;
7071   GList *list;
7072
7073   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7074   g_return_if_fail (GTK_IS_WIDGET (child));
7075
7076   list = CHECK_FIND_CHILD (notebook, child);
7077   if (!list)  
7078     return;
7079
7080   page = list->data;
7081   expand = expand != FALSE;
7082   fill = fill != FALSE;
7083   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7084     return;
7085
7086   gtk_widget_freeze_child_notify (child);
7087   page->expand = expand;
7088   gtk_widget_child_notify (child, "tab-expand");
7089   page->fill = fill;
7090   gtk_widget_child_notify (child, "tab-fill");
7091   if (page->pack != pack_type)
7092     {
7093       page->pack = pack_type;
7094       gtk_notebook_child_reordered (notebook, page);
7095     }
7096   gtk_widget_child_notify (child, "tab-pack");
7097   gtk_widget_child_notify (child, "position");
7098   if (notebook->show_tabs)
7099     gtk_notebook_pages_allocate (notebook);
7100   gtk_widget_thaw_child_notify (child);
7101 }  
7102
7103 /**
7104  * gtk_notebook_query_tab_label_packing:
7105  * @notebook: a #GtkNotebook
7106  * @child: the page
7107  * @expand: location to store the expand value (or NULL)
7108  * @fill: location to store the fill value (or NULL)
7109  * @pack_type: location to store the pack_type (or NULL)
7110  * 
7111  * Query the packing attributes for the tab label of the page
7112  * containing @child.
7113  **/
7114 void
7115 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7116                                       GtkWidget   *child,
7117                                       gboolean    *expand,
7118                                       gboolean    *fill,
7119                                       GtkPackType *pack_type)
7120 {
7121   GList *list;
7122
7123   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7124   g_return_if_fail (GTK_IS_WIDGET (child));
7125
7126   list = CHECK_FIND_CHILD (notebook, child);
7127   if (!list)
7128     return;
7129
7130   if (expand)
7131     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7132   if (fill)
7133     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7134   if (pack_type)
7135     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7136 }
7137
7138 /**
7139  * gtk_notebook_reorder_child:
7140  * @notebook: a #GtkNotebook
7141  * @child: the child to move
7142  * @position: the new position, or -1 to move to the end
7143  * 
7144  * Reorders the page containing @child, so that it appears in position
7145  * @position. If @position is greater than or equal to the number of
7146  * children in the list or negative, @child will be moved to the end
7147  * of the list.
7148  **/
7149 void
7150 gtk_notebook_reorder_child (GtkNotebook *notebook,
7151                             GtkWidget   *child,
7152                             gint         position)
7153 {
7154   GList *list, *new_list;
7155   GtkNotebookPage *page;
7156   gint old_pos;
7157   gint max_pos;
7158
7159   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7160   g_return_if_fail (GTK_IS_WIDGET (child));
7161
7162   list = CHECK_FIND_CHILD (notebook, child);
7163   if (!list)
7164     return;
7165
7166   max_pos = g_list_length (notebook->children) - 1;
7167   if (position < 0 || position > max_pos)
7168     position = max_pos;
7169
7170   old_pos = g_list_position (notebook->children, list);
7171
7172   if (old_pos == position)
7173     return;
7174
7175   page = list->data;
7176   notebook->children = g_list_delete_link (notebook->children, list);
7177
7178   notebook->children = g_list_insert (notebook->children, page, position);
7179   new_list = g_list_nth (notebook->children, position);
7180
7181   /* Fix up GList references in GtkNotebook structure */
7182   if (notebook->first_tab == list)
7183     notebook->first_tab = new_list;
7184   if (notebook->focus_tab == list)
7185     notebook->focus_tab = new_list;
7186
7187   gtk_widget_freeze_child_notify (child);
7188
7189   /* Move around the menu items if necessary */
7190   gtk_notebook_child_reordered (notebook, page);
7191   gtk_widget_child_notify (child, "tab-pack");
7192   gtk_widget_child_notify (child, "position");
7193
7194   if (notebook->show_tabs)
7195     gtk_notebook_pages_allocate (notebook);
7196
7197   gtk_widget_thaw_child_notify (child);
7198
7199   g_signal_emit (notebook,
7200                  notebook_signals[PAGE_REORDERED],
7201                  0,
7202                  child,
7203                  position);
7204 }
7205
7206 /**
7207  * gtk_notebook_set_window_creation_hook:
7208  * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7209  * @data: user data for @func
7210  * @destroy: Destroy notifier for @data, or %NULL
7211  *
7212  * Installs a global function used to create a window
7213  * when a detached tab is dropped in an empty area.
7214  * 
7215  * Since: 2.10
7216  **/
7217 void
7218 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
7219                                        gpointer                       data,
7220                                        GDestroyNotify                 destroy)
7221 {
7222   if (window_creation_hook_destroy)
7223     window_creation_hook_destroy (window_creation_hook_data);
7224
7225   window_creation_hook = func;
7226   window_creation_hook_data = data;
7227   window_creation_hook_destroy = destroy;
7228 }
7229
7230 /**
7231  * gtk_notebook_set_group_id:
7232  * @notebook: a #GtkNotebook
7233  * @group_id: a group identificator, or -1 to unset it
7234  *
7235  * Sets an group identificator for @notebook, notebooks sharing
7236  * the same group identificator will be able to exchange tabs
7237  * via drag and drop. A notebook with group identificator -1 will
7238  * not be able to exchange tabs with any other notebook.
7239  * 
7240  * Since: 2.10
7241  **/
7242 void
7243 gtk_notebook_set_group_id (GtkNotebook *notebook,
7244                            gint         group_id)
7245 {
7246   GtkNotebookPrivate *priv;
7247
7248   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7249
7250   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7251
7252   if (priv->group_id != group_id)
7253     {
7254       priv->group_id = group_id;
7255       g_object_notify (G_OBJECT (notebook), "group-id");
7256     }
7257 }
7258
7259 /**
7260  * gtk_notebook_get_group_id:
7261  * @notebook: a #GtkNotebook
7262  * 
7263  * Gets the current group identificator for @notebook.
7264  * 
7265  * Return Value: the group identificator, or -1 if none is set.
7266  *
7267  * Since: 2.10
7268  **/
7269 gint
7270 gtk_notebook_get_group_id (GtkNotebook *notebook)
7271 {
7272   GtkNotebookPrivate *priv;
7273
7274   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7275
7276   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7277   return priv->group_id;
7278 }
7279
7280 /**
7281  * gtk_notebook_get_tab_reorderable:
7282  * @notebook: a #GtkNotebook
7283  * @child: a child #GtkWidget
7284  * 
7285  * Gets whether the tab can be reordered via drag and drop or not.
7286  * 
7287  * Return Value: %TRUE if the tab is reorderable.
7288  * 
7289  * Since: 2.10
7290  **/
7291 gboolean
7292 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7293                                   GtkWidget   *child)
7294 {
7295   GList *list;
7296
7297   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7298   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7299
7300   list = CHECK_FIND_CHILD (notebook, child);
7301   if (!list)  
7302     return FALSE;
7303
7304   return GTK_NOTEBOOK_PAGE (list)->reorderable;
7305 }
7306
7307 /**
7308  * gtk_notebook_set_tab_reorderable:
7309  * @notebook: a #GtkNotebook
7310  * @child: a child #GtkWidget
7311  * @reorderable: whether the tab is reorderable or not.
7312  *
7313  * Sets whether the notebook tab can be reordered
7314  * via drag and drop or not.
7315  * 
7316  * Since: 2.10
7317  **/
7318 void
7319 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7320                                   GtkWidget   *child,
7321                                   gboolean     reorderable)
7322 {
7323   GList *list;
7324
7325   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7326   g_return_if_fail (GTK_IS_WIDGET (child));
7327
7328   list = CHECK_FIND_CHILD (notebook, child);
7329   if (!list)  
7330     return;
7331
7332   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7333     {
7334       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7335       gtk_widget_child_notify (child, "reorderable");
7336     }
7337 }
7338
7339 /**
7340  * gtk_notebook_get_tab_detachable:
7341  * @notebook: a #GtkNotebook
7342  * @child: a child #GtkWidget
7343  * 
7344  * Returns whether the tab contents can be detached from @notebook.
7345  * 
7346  * Return Value: TRUE if the tab is detachable.
7347  *
7348  * Since: 2.10
7349  **/
7350 gboolean
7351 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7352                                  GtkWidget   *child)
7353 {
7354   GList *list;
7355
7356   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7357   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7358
7359   list = CHECK_FIND_CHILD (notebook, child);
7360   if (!list)  
7361     return FALSE;
7362
7363   return GTK_NOTEBOOK_PAGE (list)->detachable;
7364 }
7365
7366 /**
7367  * gtk_notebook_set_tab_detachable:
7368  * @notebook: a #GtkNotebook
7369  * @child: a child #GtkWidget
7370  * @detachable: whether the tab is detachable or not
7371  *
7372  * Sets whether the tab can be detached from @notebook to another
7373  * notebook or widget.
7374  *
7375  * Note that 2 notebooks must share a common group identificator
7376  * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7377  * interchange between them.
7378  *
7379  * If you want a widget to interact with a notebook through DnD
7380  * (i.e.: accept dragged tabs from it) it must be set as a drop
7381  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7382  * will fill the selection with a GtkWidget** pointing to the child
7383  * widget that corresponds to the dropped tab.
7384  *
7385  * <informalexample><programlisting>
7386  *  static void
7387  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
7388  *                                   GdkDragContext   *context,
7389  *                                   gint              x,
7390  *                                   gint              y,
7391  *                                   GtkSelectionData *selection_data,
7392  *                                   guint             info,
7393  *                                   guint             time,
7394  *                                   gpointer          user_data)
7395  *  {
7396  *    GtkWidget *notebook;
7397  *    GtkWidget **child;
7398  *    
7399  *    notebook = gtk_drag_get_source_widget (context);
7400  *    child = (void*) selection_data->data;
7401  *    
7402  *    process_widget (*child);
7403  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
7404  *  }
7405  * </programlisting></informalexample>
7406  *
7407  * If you want a notebook to accept drags from other widgets,
7408  * you will have to set your own DnD code to do it.
7409  *
7410  * Since: 2.10
7411  **/
7412 void
7413 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7414                                  GtkWidget  *child,
7415                                  gboolean    detachable)
7416 {
7417   GList *list;
7418
7419   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7420   g_return_if_fail (GTK_IS_WIDGET (child));
7421
7422   list = CHECK_FIND_CHILD (notebook, child);
7423   if (!list)  
7424     return;
7425
7426   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7427     {
7428       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7429       gtk_widget_child_notify (child, "detachable");
7430     }
7431 }
7432
7433 #define __GTK_NOTEBOOK_C__
7434 #include "gtkaliasdef.c"