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