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