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