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