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