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