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