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