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