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