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