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