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