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