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