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