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