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