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