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