]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
2d902ee7bdbbf0750e7cca431e405c6a8cf3849d
[~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_STATE_FLAG_NORMAL;
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       GtkStyleContext *context;
2629
2630       cairo_save (cr);
2631       gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2632
2633       gtk_notebook_draw_tab (notebook,
2634                              priv->cur_page,
2635                              cr, FALSE);
2636
2637       cairo_restore (cr);
2638
2639       gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2640                                     priv->cur_page->tab_label, cr);
2641     }
2642
2643   return FALSE;
2644 }
2645
2646 static gboolean
2647 gtk_notebook_show_arrows (GtkNotebook *notebook)
2648 {
2649   GtkNotebookPrivate *priv = notebook->priv;
2650   gboolean show_arrow = FALSE;
2651   GList *children;
2652
2653   if (!priv->scrollable)
2654     return FALSE;
2655
2656   children = priv->children;
2657   while (children)
2658     {
2659       GtkNotebookPage *page = children->data;
2660
2661       if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2662         show_arrow = TRUE;
2663
2664       children = children->next;
2665     }
2666
2667   return show_arrow;
2668 }
2669
2670 static void
2671 gtk_notebook_get_arrow_rect (GtkNotebook     *notebook,
2672                              GdkRectangle    *rectangle,
2673                              GtkNotebookArrow arrow)
2674 {
2675   GtkNotebookPrivate *priv = notebook->priv;
2676   GdkRectangle event_window_pos;
2677   gboolean before = ARROW_IS_BEFORE (arrow);
2678   gboolean left = ARROW_IS_LEFT (arrow);
2679
2680   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2681     {
2682       gint scroll_arrow_hlength;
2683       gint scroll_arrow_vlength;
2684
2685       gtk_widget_style_get (GTK_WIDGET (notebook),
2686                             "scroll-arrow-hlength", &scroll_arrow_hlength,
2687                             "scroll-arrow-vlength", &scroll_arrow_vlength,
2688                             NULL);
2689
2690       switch (priv->tab_pos)
2691         {
2692         case GTK_POS_LEFT:
2693         case GTK_POS_RIGHT:
2694           rectangle->width = scroll_arrow_vlength;
2695           rectangle->height = scroll_arrow_vlength;
2696
2697           if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2698               (!before && (priv->has_after_previous != priv->has_after_next)))
2699           rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2700           else if (left)
2701             rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2702           else
2703             rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2704           rectangle->y = event_window_pos.y;
2705           if (!before)
2706             rectangle->y += event_window_pos.height - rectangle->height;
2707           break;
2708
2709         case GTK_POS_TOP:
2710         case GTK_POS_BOTTOM:
2711           rectangle->width = scroll_arrow_hlength;
2712           rectangle->height = scroll_arrow_hlength;
2713
2714           if (before)
2715             {
2716               if (left || !priv->has_before_previous)
2717                 rectangle->x = event_window_pos.x;
2718               else
2719                 rectangle->x = event_window_pos.x + rectangle->width;
2720             }
2721           else
2722             {
2723               if (!left || !priv->has_after_next)
2724                 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2725               else
2726                 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2727             }
2728           rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2729           break;
2730         }
2731     }
2732 }
2733
2734 static GtkNotebookArrow
2735 gtk_notebook_get_arrow (GtkNotebook *notebook,
2736                         gint         x,
2737                         gint         y)
2738 {
2739   GtkNotebookPrivate *priv = notebook->priv;
2740   GdkRectangle arrow_rect;
2741   GdkRectangle event_window_pos;
2742   gint i;
2743   gint x0, y0;
2744   GtkNotebookArrow arrow[4];
2745
2746   arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2747   arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2748   arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2749   arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2750
2751   if (gtk_notebook_show_arrows (notebook))
2752     {
2753       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2754       for (i = 0; i < 4; i++)
2755         {
2756           if (arrow[i] == ARROW_NONE)
2757             continue;
2758
2759           gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2760
2761           x0 = x - arrow_rect.x;
2762           y0 = y - arrow_rect.y;
2763
2764           if (y0 >= 0 && y0 < arrow_rect.height &&
2765               x0 >= 0 && x0 < arrow_rect.width)
2766             return arrow[i];
2767         }
2768     }
2769
2770   return ARROW_NONE;
2771 }
2772
2773 static void
2774 gtk_notebook_do_arrow (GtkNotebook     *notebook,
2775                        GtkNotebookArrow arrow)
2776 {
2777   GtkNotebookPrivate *priv = notebook->priv;
2778   GtkWidget *widget = GTK_WIDGET (notebook);
2779   gboolean is_rtl, left;
2780
2781   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2782   left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2783          (!ARROW_IS_LEFT (arrow) && is_rtl);
2784
2785   if (!priv->focus_tab ||
2786       gtk_notebook_search_page (notebook, priv->focus_tab,
2787                                 left ? STEP_PREV : STEP_NEXT,
2788                                 TRUE))
2789     {
2790       gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2791       gtk_widget_grab_focus (widget);
2792     }
2793 }
2794
2795 static gboolean
2796 gtk_notebook_arrow_button_press (GtkNotebook      *notebook,
2797                                  GtkNotebookArrow  arrow,
2798                                  gint              button)
2799 {
2800   GtkNotebookPrivate *priv = notebook->priv;
2801   GtkWidget *widget = GTK_WIDGET (notebook);
2802   gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2803   gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2804                   (!ARROW_IS_LEFT (arrow) && is_rtl);
2805
2806   if (!gtk_widget_has_focus (widget))
2807     gtk_widget_grab_focus (widget);
2808
2809   priv->button = button;
2810   priv->click_child = arrow;
2811
2812   if (button == 1)
2813     {
2814       gtk_notebook_do_arrow (notebook, arrow);
2815       gtk_notebook_set_scroll_timer (notebook);
2816     }
2817   else if (button == 2)
2818     gtk_notebook_page_select (notebook, TRUE);
2819   else if (button == 3)
2820     gtk_notebook_switch_focus_tab (notebook,
2821                                    gtk_notebook_search_page (notebook,
2822                                                              NULL,
2823                                                              left ? STEP_NEXT : STEP_PREV,
2824                                                              TRUE));
2825   gtk_notebook_redraw_arrows (notebook);
2826
2827   return TRUE;
2828 }
2829
2830 static gboolean
2831 get_widget_coordinates (GtkWidget *widget,
2832                         GdkEvent  *event,
2833                         gint      *x,
2834                         gint      *y)
2835 {
2836   GdkWindow *window = ((GdkEventAny *)event)->window;
2837   gdouble tx, ty;
2838
2839   if (!gdk_event_get_coords (event, &tx, &ty))
2840     return FALSE;
2841
2842   while (window && window != gtk_widget_get_window (widget))
2843     {
2844       gint window_x, window_y;
2845
2846       gdk_window_get_position (window, &window_x, &window_y);
2847       tx += window_x;
2848       ty += window_y;
2849
2850       window = gdk_window_get_parent (window);
2851     }
2852
2853   if (window)
2854     {
2855       *x = tx;
2856       *y = ty;
2857
2858       return TRUE;
2859     }
2860   else
2861     return FALSE;
2862 }
2863
2864 static GList*
2865 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2866 {
2867    GtkNotebookPrivate *priv = notebook->priv;
2868   GtkNotebookPage *page;
2869   GList *children;
2870
2871   children = priv->children;
2872   while (children)
2873     {
2874       page = children->data;
2875
2876       if (gtk_widget_get_visible (page->child) &&
2877           page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2878           (x >= page->allocation.x) &&
2879           (y >= page->allocation.y) &&
2880           (x <= (page->allocation.x + page->allocation.width)) &&
2881           (y <= (page->allocation.y + page->allocation.height)))
2882         return children;
2883
2884       children = children->next;
2885     }
2886
2887   return NULL;
2888 }
2889
2890 static gboolean
2891 gtk_notebook_button_press (GtkWidget      *widget,
2892                            GdkEventButton *event)
2893 {
2894   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2895   GtkNotebookPrivate *priv = notebook->priv;
2896   GtkNotebookPage *page;
2897   GList *tab;
2898   GtkNotebookArrow arrow;
2899   gint x, y;
2900
2901   if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2902       priv->button)
2903     return FALSE;
2904
2905   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2906     return FALSE;
2907
2908   arrow = gtk_notebook_get_arrow (notebook, x, y);
2909   if (arrow)
2910     return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2911
2912   if (priv->menu && gdk_event_triggers_context_menu ((GdkEvent *) event))
2913     {
2914       gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2915                       NULL, NULL, 3, event->time);
2916       return TRUE;
2917     }
2918
2919   if (event->button != 1)
2920     return FALSE;
2921
2922   priv->button = event->button;
2923
2924   if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2925     {
2926       gboolean page_changed, was_focus;
2927
2928       page = tab->data;
2929       page_changed = page != priv->cur_page;
2930       was_focus = gtk_widget_is_focus (widget);
2931
2932       gtk_notebook_switch_focus_tab (notebook, tab);
2933       gtk_widget_grab_focus (widget);
2934
2935       if (page_changed && !was_focus)
2936         gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2937
2938       /* save press to possibly begin a drag */
2939       if (page->reorderable || page->detachable)
2940         {
2941           priv->during_detach = FALSE;
2942           priv->during_reorder = FALSE;
2943           priv->pressed_button = event->button;
2944
2945           priv->mouse_x = x;
2946           priv->mouse_y = y;
2947
2948           priv->drag_begin_x = priv->mouse_x;
2949           priv->drag_begin_y = priv->mouse_y;
2950           priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2951           priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2952         }
2953     }
2954
2955   return TRUE;
2956 }
2957
2958 static void
2959 popup_position_func (GtkMenu  *menu,
2960                      gint     *x,
2961                      gint     *y,
2962                      gboolean *push_in,
2963                      gpointer  data)
2964 {
2965   GtkNotebook *notebook = data;
2966   GtkNotebookPrivate *priv = notebook->priv;
2967   GtkAllocation allocation;
2968   GtkWidget *w;
2969   GtkRequisition requisition;
2970
2971   if (priv->focus_tab)
2972     {
2973       GtkNotebookPage *page;
2974
2975       page = priv->focus_tab->data;
2976       w = page->tab_label;
2977     }
2978   else
2979    {
2980      w = GTK_WIDGET (notebook);
2981    }
2982
2983   gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2984
2985   gtk_widget_get_allocation (w, &allocation);
2986   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2987                                  &requisition, NULL);
2988
2989   if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2990     *x += allocation.x + allocation.width - requisition.width;
2991   else
2992     *x += allocation.x;
2993
2994   *y += allocation.y + allocation.height;
2995
2996   *push_in = FALSE;
2997 }
2998
2999 static gboolean
3000 gtk_notebook_popup_menu (GtkWidget *widget)
3001 {
3002   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3003   GtkNotebookPrivate *priv = notebook->priv;
3004
3005   if (priv->menu)
3006     {
3007       gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
3008                       popup_position_func, notebook,
3009                       0, gtk_get_current_event_time ());
3010       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
3011       return TRUE;
3012     }
3013
3014   return FALSE;
3015 }
3016
3017 static void
3018 stop_scrolling (GtkNotebook *notebook)
3019 {
3020   GtkNotebookPrivate *priv = notebook->priv;
3021
3022   if (priv->timer)
3023     {
3024       g_source_remove (priv->timer);
3025       priv->timer = 0;
3026       priv->need_timer = FALSE;
3027     }
3028   priv->click_child = 0;
3029   priv->button = 0;
3030   gtk_notebook_redraw_arrows (notebook);
3031 }
3032
3033 static GList*
3034 get_drop_position (GtkNotebook *notebook)
3035 {
3036   GtkNotebookPrivate *priv = notebook->priv;
3037   GList *children, *last_child;
3038   GtkNotebookPage *page;
3039   gboolean is_rtl;
3040   gint x, y;
3041
3042   x = priv->mouse_x;
3043   y = priv->mouse_y;
3044
3045   is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
3046   children = priv->children;
3047   last_child = NULL;
3048
3049   while (children)
3050     {
3051       page = children->data;
3052
3053       if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
3054           gtk_widget_get_visible (page->child) &&
3055           page->tab_label &&
3056           gtk_widget_get_mapped (page->tab_label))
3057         {
3058           switch (priv->tab_pos)
3059             {
3060             case GTK_POS_TOP:
3061             case GTK_POS_BOTTOM:
3062               if (!is_rtl)
3063                 {
3064                   if (PAGE_MIDDLE_X (page) > x)
3065                     return children;
3066                 }
3067               else
3068                 {
3069                   if (PAGE_MIDDLE_X (page) < x)
3070                     return children;
3071                 }
3072
3073               break;
3074             case GTK_POS_LEFT:
3075             case GTK_POS_RIGHT:
3076               if (PAGE_MIDDLE_Y (page) > y)
3077                 return children;
3078
3079               break;
3080             }
3081
3082           last_child = children->next;
3083         }
3084
3085       children = children->next;
3086     }
3087
3088   return last_child;
3089 }
3090
3091 static void
3092 show_drag_window (GtkNotebook        *notebook,
3093                   GtkNotebookPrivate    *priv,
3094                   GtkNotebookPage    *page,
3095                   GdkDevice          *device)
3096 {
3097   GtkWidget *widget = GTK_WIDGET (notebook);
3098
3099   if (!priv->drag_window)
3100     {
3101       GdkWindowAttr attributes;
3102       guint attributes_mask;
3103       GdkRGBA transparent = {0, 0, 0, 0};
3104
3105       attributes.x = page->allocation.x;
3106       attributes.y = page->allocation.y;
3107       attributes.width = page->allocation.width;
3108       attributes.height = page->allocation.height;
3109       attributes.window_type = GDK_WINDOW_CHILD;
3110       attributes.wclass = GDK_INPUT_OUTPUT;
3111       attributes.visual = gtk_widget_get_visual (widget);
3112       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3113       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3114
3115       priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
3116                                           &attributes,
3117                                           attributes_mask);
3118       gdk_window_set_user_data (priv->drag_window, widget);
3119       gdk_window_set_background_rgba (priv->drag_window, &transparent);
3120     }
3121
3122   g_object_ref (page->tab_label);
3123   gtk_widget_unparent (page->tab_label);
3124   gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
3125   gtk_widget_set_parent (page->tab_label, widget);
3126   g_object_unref (page->tab_label);
3127
3128   gdk_window_show (priv->drag_window);
3129
3130   /* the grab will dissapear when the window is hidden */
3131   gdk_device_grab (device, priv->drag_window,
3132                    GDK_OWNERSHIP_WINDOW, FALSE,
3133                    GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
3134                    NULL, GDK_CURRENT_TIME);
3135 }
3136
3137 /* This function undoes the reparenting that happens both when drag_window
3138  * is shown for reordering and when the DnD icon is shown for detaching
3139  */
3140 static void
3141 hide_drag_window (GtkNotebook        *notebook,
3142                   GtkNotebookPrivate    *priv,
3143                   GtkNotebookPage    *page)
3144 {
3145   GtkWidget *widget = GTK_WIDGET (notebook);
3146   GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3147
3148   if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3149       !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3150     {
3151       g_object_ref (page->tab_label);
3152
3153       if (GTK_IS_WINDOW (parent))
3154         {
3155           /* parent widget is the drag window */
3156           gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3157         }
3158       else
3159         gtk_widget_unparent (page->tab_label);
3160
3161       gtk_widget_set_parent (page->tab_label, widget);
3162       g_object_unref (page->tab_label);
3163     }
3164
3165   if (priv->drag_window &&
3166       gdk_window_is_visible (priv->drag_window))
3167     gdk_window_hide (priv->drag_window);
3168 }
3169
3170 static void
3171 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3172 {
3173   GtkNotebookPrivate *priv = notebook->priv;
3174   GtkNotebookPage *page;
3175
3176   if (priv->operation == DRAG_OPERATION_DETACH)
3177     page = priv->detached_tab;
3178   else
3179     page = priv->cur_page;
3180
3181   if (!page || !page->tab_label)
3182     return;
3183
3184   priv->pressed_button = -1;
3185
3186   if (page->reorderable || page->detachable)
3187     {
3188       if (priv->during_reorder)
3189         {
3190           gint old_page_num, page_num;
3191           GList *element;
3192
3193           element = get_drop_position (notebook);
3194           old_page_num = g_list_position (priv->children, priv->focus_tab);
3195           page_num = reorder_tab (notebook, element, priv->focus_tab);
3196           gtk_notebook_child_reordered (notebook, page);
3197
3198           if (priv->has_scrolled || old_page_num != page_num)
3199             g_signal_emit (notebook,
3200                            notebook_signals[PAGE_REORDERED], 0,
3201                            page->child, page_num);
3202
3203           priv->has_scrolled = FALSE;
3204           priv->during_reorder = FALSE;
3205         }
3206
3207       hide_drag_window (notebook, priv, page);
3208
3209       priv->operation = DRAG_OPERATION_NONE;
3210       gtk_notebook_pages_allocate (notebook);
3211
3212       if (priv->dnd_timer)
3213         {
3214           g_source_remove (priv->dnd_timer);
3215           priv->dnd_timer = 0;
3216         }
3217     }
3218 }
3219
3220 static gint
3221 gtk_notebook_button_release (GtkWidget      *widget,
3222                              GdkEventButton *event)
3223 {
3224   GtkNotebook *notebook;
3225   GtkNotebookPrivate *priv;
3226   GtkNotebookPage *page;
3227
3228   if (event->type != GDK_BUTTON_RELEASE)
3229     return FALSE;
3230
3231   notebook = GTK_NOTEBOOK (widget);
3232   priv = notebook->priv;
3233
3234   page = priv->cur_page;
3235
3236   if (!priv->during_detach &&
3237       page->reorderable &&
3238       event->button == priv->pressed_button)
3239     gtk_notebook_stop_reorder (notebook);
3240
3241   if (event->button == priv->button)
3242     {
3243       stop_scrolling (notebook);
3244       return TRUE;
3245     }
3246   else
3247     return FALSE;
3248 }
3249
3250 static gint
3251 gtk_notebook_leave_notify (GtkWidget        *widget,
3252                            GdkEventCrossing *event)
3253 {
3254   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3255   GtkNotebookPrivate *priv = notebook->priv;
3256   gint x, y;
3257
3258   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3259     return FALSE;
3260
3261   if (priv->in_child)
3262     {
3263       priv->in_child = 0;
3264       gtk_notebook_redraw_arrows (notebook);
3265     }
3266
3267   return TRUE;
3268 }
3269
3270 static GtkNotebookPointerPosition
3271 get_pointer_position (GtkNotebook *notebook)
3272 {
3273   GtkNotebookPrivate *priv = notebook->priv;
3274   GtkWidget *widget = GTK_WIDGET (notebook);
3275   gint wx, wy, width, height;
3276   gboolean is_rtl;
3277
3278   if (!priv->scrollable)
3279     return POINTER_BETWEEN;
3280
3281   gdk_window_get_position (priv->event_window, &wx, &wy);
3282   width = gdk_window_get_width (priv->event_window);
3283   height = gdk_window_get_height (priv->event_window);
3284
3285   if (priv->tab_pos == GTK_POS_TOP ||
3286       priv->tab_pos == GTK_POS_BOTTOM)
3287     {
3288       gint x;
3289
3290       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3291       x = priv->mouse_x - wx;
3292
3293       if (x > width - SCROLL_THRESHOLD)
3294         return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3295       else if (x < SCROLL_THRESHOLD)
3296         return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3297       else
3298         return POINTER_BETWEEN;
3299     }
3300   else
3301     {
3302       gint y;
3303
3304       y = priv->mouse_y - wy;
3305       if (y > height - SCROLL_THRESHOLD)
3306         return POINTER_AFTER;
3307       else if (y < SCROLL_THRESHOLD)
3308         return POINTER_BEFORE;
3309       else
3310         return POINTER_BETWEEN;
3311     }
3312 }
3313
3314 static gboolean
3315 scroll_notebook_timer (gpointer data)
3316 {
3317   GtkNotebook *notebook = GTK_NOTEBOOK (data);
3318   GtkNotebookPrivate *priv = notebook->priv;
3319   GtkNotebookPointerPosition pointer_position;
3320   GList *element, *first_tab;
3321
3322   pointer_position = get_pointer_position (notebook);
3323
3324   element = get_drop_position (notebook);
3325   reorder_tab (notebook, element, priv->focus_tab);
3326   first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3327                                         (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3328                                         TRUE);
3329   if (first_tab)
3330     {
3331       priv->first_tab = first_tab;
3332       gtk_notebook_pages_allocate (notebook);
3333
3334       gdk_window_move_resize (priv->drag_window,
3335                               priv->drag_window_x,
3336                               priv->drag_window_y,
3337                               priv->cur_page->allocation.width,
3338                               priv->cur_page->allocation.height);
3339       gdk_window_raise (priv->drag_window);
3340     }
3341
3342   return TRUE;
3343 }
3344
3345 static gboolean
3346 check_threshold (GtkNotebook *notebook,
3347                  gint         current_x,
3348                  gint         current_y)
3349 {
3350   GtkNotebookPrivate *priv = notebook->priv;
3351   gint dnd_threshold;
3352   GdkRectangle rectangle = { 0, }; /* shut up gcc */
3353   GtkSettings *settings;
3354
3355   settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3356   g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3357
3358   /* we want a large threshold */
3359   dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3360
3361   gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3362   rectangle.width = gdk_window_get_width (priv->event_window);
3363   rectangle.height = gdk_window_get_height (priv->event_window);
3364
3365   rectangle.x -= dnd_threshold;
3366   rectangle.width += 2 * dnd_threshold;
3367   rectangle.y -= dnd_threshold;
3368   rectangle.height += 2 * dnd_threshold;
3369
3370   return (current_x < rectangle.x ||
3371           current_x > rectangle.x + rectangle.width ||
3372           current_y < rectangle.y ||
3373           current_y > rectangle.y + rectangle.height);
3374 }
3375
3376 static gint
3377 gtk_notebook_motion_notify (GtkWidget      *widget,
3378                             GdkEventMotion *event)
3379 {
3380   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3381   GtkNotebookPrivate *priv = notebook->priv;
3382   GtkNotebookPage *page;
3383   GtkNotebookArrow arrow;
3384   GtkNotebookPointerPosition pointer_position;
3385   GtkSettings *settings;
3386   guint timeout;
3387   gint x_win, y_win;
3388
3389   page = priv->cur_page;
3390
3391   if (!page)
3392     return FALSE;
3393
3394   if (!(event->state & GDK_BUTTON1_MASK) &&
3395       priv->pressed_button != -1)
3396     {
3397       gtk_notebook_stop_reorder (notebook);
3398       stop_scrolling (notebook);
3399     }
3400
3401   if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3402     return FALSE;
3403
3404   priv->timestamp = event->time;
3405
3406   /* While animating the move, event->x is relative to the flying tab
3407    * (priv->drag_window has a pointer grab), but we need coordinates relative to
3408    * the notebook widget.
3409    */
3410   gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3411   priv->mouse_x = event->x_root - x_win;
3412   priv->mouse_y = event->y_root - y_win;
3413
3414   arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3415   if (arrow != priv->in_child)
3416     {
3417       priv->in_child = arrow;
3418       gtk_notebook_redraw_arrows (notebook);
3419     }
3420
3421   if (priv->pressed_button == -1)
3422     return FALSE;
3423
3424   if (page->detachable &&
3425       check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3426     {
3427       priv->detached_tab = priv->cur_page;
3428       priv->during_detach = TRUE;
3429
3430       gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3431                       priv->pressed_button, (GdkEvent*) event);
3432       return TRUE;
3433     }
3434
3435   if (page->reorderable &&
3436       (priv->during_reorder ||
3437        gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3438     {
3439       priv->during_reorder = TRUE;
3440       pointer_position = get_pointer_position (notebook);
3441
3442       if (event->window == priv->drag_window &&
3443           pointer_position != POINTER_BETWEEN &&
3444           gtk_notebook_show_arrows (notebook))
3445         {
3446           /* scroll tabs */
3447           if (!priv->dnd_timer)
3448             {
3449               priv->has_scrolled = TRUE;
3450               settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3451               g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3452
3453               priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3454                                                scroll_notebook_timer,
3455                                                (gpointer) notebook);
3456             }
3457         }
3458       else
3459         {
3460           if (priv->dnd_timer)
3461             {
3462               g_source_remove (priv->dnd_timer);
3463               priv->dnd_timer = 0;
3464             }
3465         }
3466
3467       if (event->window == priv->drag_window ||
3468           priv->operation != DRAG_OPERATION_REORDER)
3469         {
3470           /* the drag operation is beginning, create the window */
3471           if (priv->operation != DRAG_OPERATION_REORDER)
3472             {
3473               priv->operation = DRAG_OPERATION_REORDER;
3474               show_drag_window (notebook, priv, page, event->device);
3475             }
3476
3477           gtk_notebook_pages_allocate (notebook);
3478           gdk_window_move_resize (priv->drag_window,
3479                                   priv->drag_window_x,
3480                                   priv->drag_window_y,
3481                                   page->allocation.width,
3482                                   page->allocation.height);
3483
3484           gtk_notebook_redraw_tabs_junction (notebook);
3485         }
3486     }
3487
3488   return TRUE;
3489 }
3490
3491 static void
3492 gtk_notebook_grab_notify (GtkWidget *widget,
3493                           gboolean   was_grabbed)
3494 {
3495   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3496
3497   if (!was_grabbed)
3498     {
3499       gtk_notebook_stop_reorder (notebook);
3500       stop_scrolling (notebook);
3501     }
3502 }
3503
3504 static void
3505 gtk_notebook_state_flags_changed (GtkWidget     *widget,
3506                                   GtkStateFlags  previous_state)
3507 {
3508   if (!gtk_widget_is_sensitive (widget))
3509     stop_scrolling (GTK_NOTEBOOK (widget));
3510 }
3511
3512 static gint
3513 gtk_notebook_focus_in (GtkWidget     *widget,
3514                        GdkEventFocus *event)
3515 {
3516   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3517
3518   return FALSE;
3519 }
3520
3521 static gint
3522 gtk_notebook_focus_out (GtkWidget     *widget,
3523                         GdkEventFocus *event)
3524 {
3525   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3526
3527   return FALSE;
3528 }
3529
3530 static void
3531 gtk_notebook_style_updated (GtkWidget *widget)
3532 {
3533   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3534   GtkNotebookPrivate *priv = notebook->priv;
3535
3536   gboolean has_before_previous;
3537   gboolean has_before_next;
3538   gboolean has_after_previous;
3539   gboolean has_after_next;
3540
3541   gtk_widget_style_get (widget,
3542                         "has-backward-stepper", &has_before_previous,
3543                         "has-secondary-forward-stepper", &has_before_next,
3544                         "has-secondary-backward-stepper", &has_after_previous,
3545                         "has-forward-stepper", &has_after_next,
3546                         NULL);
3547
3548   priv->has_before_previous = has_before_previous;
3549   priv->has_before_next = has_before_next;
3550   priv->has_after_previous = has_after_previous;
3551   priv->has_after_next = has_after_next;
3552
3553   GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3554 }
3555
3556 static gboolean
3557 on_drag_icon_draw (GtkWidget *widget,
3558                    cairo_t   *cr,
3559                    gpointer   data)
3560 {
3561   GtkWidget *notebook, *child;
3562   GtkRequisition requisition;
3563   GtkStyleContext *context;
3564   gint gap_pos;
3565
3566   notebook = GTK_WIDGET (data);
3567   child = gtk_bin_get_child (GTK_BIN (widget));
3568   context = gtk_widget_get_style_context (widget);
3569
3570   gtk_style_context_save (context);
3571   notebook_tab_prepare_style_context (GTK_NOTEBOOK (notebook), NULL, context, FALSE);
3572
3573   gtk_widget_get_preferred_size (widget,
3574                                  &requisition, NULL);
3575   gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3576
3577   gtk_render_extension (context, cr, 0, 0,
3578                         requisition.width, requisition.height,
3579                         gap_pos);
3580
3581   if (child)
3582     gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3583
3584   gtk_style_context_restore (context);
3585
3586   return TRUE;
3587 }
3588
3589 static void
3590 gtk_notebook_drag_begin (GtkWidget        *widget,
3591                          GdkDragContext   *context)
3592 {
3593   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3594   GtkNotebookPrivate *priv = notebook->priv;
3595   GtkWidget *tab_label;
3596
3597   if (priv->dnd_timer)
3598     {
3599       g_source_remove (priv->dnd_timer);
3600       priv->dnd_timer = 0;
3601     }
3602
3603   priv->operation = DRAG_OPERATION_DETACH;
3604   gtk_notebook_pages_allocate (notebook);
3605
3606   tab_label = priv->detached_tab->tab_label;
3607
3608   hide_drag_window (notebook, priv, priv->cur_page);
3609   g_object_ref (tab_label);
3610   gtk_widget_unparent (tab_label);
3611
3612   priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3613   gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3614                          gtk_widget_get_screen (widget));
3615   gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3616   gtk_widget_set_size_request (priv->dnd_window,
3617                                priv->detached_tab->allocation.width,
3618                                priv->detached_tab->allocation.height);
3619   g_object_unref (tab_label);
3620
3621   g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3622                     G_CALLBACK (on_drag_icon_draw), notebook);
3623
3624   gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3625 }
3626
3627 static void
3628 gtk_notebook_drag_end (GtkWidget      *widget,
3629                        GdkDragContext *context)
3630 {
3631   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3632   GtkNotebookPrivate *priv = notebook->priv;
3633
3634   gtk_notebook_stop_reorder (notebook);
3635
3636   if (priv->detached_tab)
3637     gtk_notebook_switch_page (notebook, priv->detached_tab);
3638
3639   _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3640   gtk_widget_destroy (priv->dnd_window);
3641   priv->dnd_window = NULL;
3642
3643   priv->operation = DRAG_OPERATION_NONE;
3644 }
3645
3646 static GtkNotebook *
3647 gtk_notebook_create_window (GtkNotebook *notebook,
3648                             GtkWidget   *page,
3649                             gint         x,
3650                             gint         y)
3651 {
3652   return NULL;
3653 }
3654
3655 static gboolean
3656 gtk_notebook_drag_failed (GtkWidget      *widget,
3657                           GdkDragContext *context,
3658                           GtkDragResult   result)
3659 {
3660   if (result == GTK_DRAG_RESULT_NO_TARGET)
3661     {
3662       GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3663       GtkNotebookPrivate *priv = notebook->priv;
3664       GtkNotebook *dest_notebook = NULL;
3665       gint x, y;
3666
3667       gdk_device_get_position (gdk_drag_context_get_device (context),
3668                                NULL, &x, &y);
3669
3670       g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3671                      priv->detached_tab->child, x, y, &dest_notebook);
3672
3673       if (dest_notebook)
3674         do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3675
3676       return TRUE;
3677     }
3678
3679   return FALSE;
3680 }
3681
3682 static gboolean
3683 gtk_notebook_switch_tab_timeout (gpointer data)
3684 {
3685   GtkNotebook *notebook = GTK_NOTEBOOK (data);
3686   GtkNotebookPrivate *priv = notebook->priv;
3687   GList *tab;
3688   gint x, y;
3689
3690   priv->switch_tab_timer = 0;
3691   x = priv->mouse_x;
3692   y = priv->mouse_y;
3693
3694   if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3695     {
3696       /* FIXME: hack, we don't want the
3697        * focus to move fom the source widget
3698        */
3699       priv->child_has_focus = FALSE;
3700       gtk_notebook_switch_focus_tab (notebook, tab);
3701     }
3702
3703   return FALSE;
3704 }
3705
3706 static gboolean
3707 gtk_notebook_drag_motion (GtkWidget      *widget,
3708                           GdkDragContext *context,
3709                           gint            x,
3710                           gint            y,
3711                           guint           time)
3712 {
3713   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3714   GtkNotebookPrivate *priv = notebook->priv;
3715   GtkAllocation allocation;
3716   GdkRectangle position;
3717   GtkSettings *settings;
3718   GtkNotebookArrow arrow;
3719   guint timeout;
3720   GdkAtom target, tab_target;
3721
3722   gtk_widget_get_allocation (widget, &allocation);
3723
3724   arrow = gtk_notebook_get_arrow (notebook,
3725                                   x + allocation.x,
3726                                   y + allocation.y);
3727   if (arrow)
3728     {
3729       priv->click_child = arrow;
3730       gtk_notebook_set_scroll_timer (notebook);
3731       gdk_drag_status (context, 0, time);
3732       return TRUE;
3733     }
3734
3735   stop_scrolling (notebook);
3736   target = gtk_drag_dest_find_target (widget, context, NULL);
3737   tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3738
3739   if (target == tab_target)
3740     {
3741       GQuark group, source_group;
3742       GtkNotebook *source;
3743       GtkWidget *source_child;
3744
3745       source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3746       source_child = source->priv->cur_page->child;
3747
3748       group = notebook->priv->group;
3749       source_group = source->priv->group;
3750
3751       if (group != 0 && group == source_group &&
3752           !(widget == source_child ||
3753             gtk_widget_is_ancestor (widget, source_child)))
3754         {
3755           gdk_drag_status (context, GDK_ACTION_MOVE, time);
3756           return TRUE;
3757         }
3758       else
3759         {
3760           /* it's a tab, but doesn't share
3761            * ID with this notebook */
3762           gdk_drag_status (context, 0, time);
3763         }
3764     }
3765
3766   x += allocation.x;
3767   y += allocation.y;
3768
3769   if (gtk_notebook_get_event_window_position (notebook, &position) &&
3770       x >= position.x && x <= position.x + position.width &&
3771       y >= position.y && y <= position.y + position.height)
3772     {
3773       priv->mouse_x = x;
3774       priv->mouse_y = y;
3775
3776       if (!priv->switch_tab_timer)
3777         {
3778           settings = gtk_widget_get_settings (widget);
3779
3780           g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3781           priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3782                                                   gtk_notebook_switch_tab_timeout,
3783                                                   widget);
3784         }
3785     }
3786   else
3787     {
3788       if (priv->switch_tab_timer)
3789         {
3790           g_source_remove (priv->switch_tab_timer);
3791           priv->switch_tab_timer = 0;
3792         }
3793     }
3794
3795   return (target == tab_target) ? TRUE : FALSE;
3796 }
3797
3798 static void
3799 gtk_notebook_drag_leave (GtkWidget      *widget,
3800                          GdkDragContext *context,
3801                          guint           time)
3802 {
3803   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3804   GtkNotebookPrivate *priv = notebook->priv;
3805
3806   if (priv->switch_tab_timer)
3807     {
3808       g_source_remove (priv->switch_tab_timer);
3809       priv->switch_tab_timer = 0;
3810     }
3811
3812   stop_scrolling (GTK_NOTEBOOK (widget));
3813 }
3814
3815 static gboolean
3816 gtk_notebook_drag_drop (GtkWidget        *widget,
3817                         GdkDragContext   *context,
3818                         gint              x,
3819                         gint              y,
3820                         guint             time)
3821 {
3822   GdkAtom target, tab_target;
3823
3824   target = gtk_drag_dest_find_target (widget, context, NULL);
3825   tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3826
3827   if (target == tab_target)
3828     {
3829       gtk_drag_get_data (widget, context, target, time);
3830       return TRUE;
3831     }
3832
3833   return FALSE;
3834 }
3835
3836 static void
3837 do_detach_tab (GtkNotebook     *from,
3838                GtkNotebook     *to,
3839                GtkWidget       *child,
3840                gint             x,
3841                gint             y)
3842 {
3843   GtkNotebookPrivate *to_priv = to->priv;
3844   GtkAllocation to_allocation;
3845   GtkWidget *tab_label, *menu_label;
3846   gboolean tab_expand, tab_fill, reorderable, detachable;
3847   GList *element;
3848   gint page_num;
3849
3850   menu_label = gtk_notebook_get_menu_label (from, child);
3851
3852   if (menu_label)
3853     g_object_ref (menu_label);
3854
3855   tab_label = gtk_notebook_get_tab_label (from, child);
3856
3857   if (tab_label)
3858     g_object_ref (tab_label);
3859
3860   g_object_ref (child);
3861
3862   gtk_container_child_get (GTK_CONTAINER (from),
3863                            child,
3864                            "tab-expand", &tab_expand,
3865                            "tab-fill", &tab_fill,
3866                            "reorderable", &reorderable,
3867                            "detachable", &detachable,
3868                            NULL);
3869
3870   gtk_container_remove (GTK_CONTAINER (from), child);
3871
3872   gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3873   to_priv->mouse_x = x + to_allocation.x;
3874   to_priv->mouse_y = y + to_allocation.y;
3875
3876   element = get_drop_position (to);
3877   page_num = g_list_position (to_priv->children, element);
3878   gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3879
3880   gtk_container_child_set (GTK_CONTAINER (to), child,
3881                            "tab-expand", tab_expand,
3882                            "tab-fill", tab_fill,
3883                            "reorderable", reorderable,
3884                            "detachable", detachable,
3885                            NULL);
3886   if (child)
3887     g_object_unref (child);
3888
3889   if (tab_label)
3890     g_object_unref (tab_label);
3891
3892   if (menu_label)
3893     g_object_unref (menu_label);
3894
3895   gtk_notebook_set_current_page (to, page_num);
3896 }
3897
3898 static void
3899 gtk_notebook_drag_data_get (GtkWidget        *widget,
3900                             GdkDragContext   *context,
3901                             GtkSelectionData *data,
3902                             guint             info,
3903                             guint             time)
3904 {
3905   GdkAtom target;
3906
3907   target = gtk_selection_data_get_target (data);
3908   if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3909     {
3910       GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3911       GtkNotebookPrivate *priv = notebook->priv;
3912
3913       gtk_selection_data_set (data,
3914                               target,
3915                               8,
3916                               (void*) &priv->detached_tab->child,
3917                               sizeof (gpointer));
3918     }
3919 }
3920
3921 static void
3922 gtk_notebook_drag_data_received (GtkWidget        *widget,
3923                                  GdkDragContext   *context,
3924                                  gint              x,
3925                                  gint              y,
3926                                  GtkSelectionData *data,
3927                                  guint             info,
3928                                  guint             time)
3929 {
3930   GtkNotebook *notebook;
3931   GtkWidget *source_widget;
3932   GtkWidget **child;
3933
3934   notebook = GTK_NOTEBOOK (widget);
3935   source_widget = gtk_drag_get_source_widget (context);
3936
3937   if (source_widget &&
3938       gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3939     {
3940       child = (void*) gtk_selection_data_get_data (data);
3941
3942       do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3943       gtk_drag_finish (context, TRUE, FALSE, time);
3944     }
3945   else
3946     gtk_drag_finish (context, FALSE, FALSE, time);
3947 }
3948
3949 /* Private GtkContainer Methods :
3950  *
3951  * gtk_notebook_set_child_arg
3952  * gtk_notebook_get_child_arg
3953  * gtk_notebook_add
3954  * gtk_notebook_remove
3955  * gtk_notebook_focus
3956  * gtk_notebook_set_focus_child
3957  * gtk_notebook_child_type
3958  * gtk_notebook_forall
3959  */
3960 static void
3961 gtk_notebook_set_child_property (GtkContainer    *container,
3962                                  GtkWidget       *child,
3963                                  guint            property_id,
3964                                  const GValue    *value,
3965                                  GParamSpec      *pspec)
3966 {
3967   gboolean expand;
3968   gboolean fill;
3969
3970   /* not finding child's page is valid for menus or labels */
3971   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3972     return;
3973
3974   switch (property_id)
3975     {
3976     case CHILD_PROP_TAB_LABEL:
3977       /* a NULL pointer indicates a default_tab setting, otherwise
3978        * we need to set the associated label
3979        */
3980       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3981                                        g_value_get_string (value));
3982       break;
3983     case CHILD_PROP_MENU_LABEL:
3984       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3985                                         g_value_get_string (value));
3986       break;
3987     case CHILD_PROP_POSITION:
3988       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3989                                   g_value_get_int (value));
3990       break;
3991     case CHILD_PROP_TAB_EXPAND:
3992       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3993                                             &expand, &fill);
3994       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3995                                           g_value_get_boolean (value),
3996                                           fill);
3997       break;
3998     case CHILD_PROP_TAB_FILL:
3999       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4000                                             &expand, &fill);
4001       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
4002                                           expand,
4003                                           g_value_get_boolean (value));
4004       break;
4005     case CHILD_PROP_REORDERABLE:
4006       gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
4007                                         g_value_get_boolean (value));
4008       break;
4009     case CHILD_PROP_DETACHABLE:
4010       gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
4011                                        g_value_get_boolean (value));
4012       break;
4013     default:
4014       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4015       break;
4016     }
4017 }
4018
4019 static void
4020 gtk_notebook_get_child_property (GtkContainer    *container,
4021                                  GtkWidget       *child,
4022                                  guint            property_id,
4023                                  GValue          *value,
4024                                  GParamSpec      *pspec)
4025 {
4026   GtkNotebook *notebook = GTK_NOTEBOOK (container);
4027   GtkNotebookPrivate *priv = notebook->priv;
4028   GList *list;
4029   GtkWidget *label;
4030   gboolean expand;
4031   gboolean fill;
4032
4033   /* not finding child's page is valid for menus or labels */
4034   list = gtk_notebook_find_child (notebook, child, NULL);
4035   if (!list)
4036     {
4037       /* nothing to set on labels or menus */
4038       g_param_value_set_default (pspec, value);
4039       return;
4040     }
4041
4042   switch (property_id)
4043     {
4044     case CHILD_PROP_TAB_LABEL:
4045       label = gtk_notebook_get_tab_label (notebook, child);
4046
4047       if (GTK_IS_LABEL (label))
4048         g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4049       else
4050         g_value_set_string (value, NULL);
4051       break;
4052     case CHILD_PROP_MENU_LABEL:
4053       label = gtk_notebook_get_menu_label (notebook, child);
4054
4055       if (GTK_IS_LABEL (label))
4056         g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4057       else
4058         g_value_set_string (value, NULL);
4059       break;
4060     case CHILD_PROP_POSITION:
4061       g_value_set_int (value, g_list_position (priv->children, list));
4062       break;
4063     case CHILD_PROP_TAB_EXPAND:
4064         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4065                                               &expand, NULL);
4066         g_value_set_boolean (value, expand);
4067       break;
4068     case CHILD_PROP_TAB_FILL:
4069         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4070                                               NULL, &fill);
4071         g_value_set_boolean (value, fill);
4072       break;
4073     case CHILD_PROP_REORDERABLE:
4074       g_value_set_boolean (value,
4075                            gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
4076       break;
4077     case CHILD_PROP_DETACHABLE:
4078       g_value_set_boolean (value,
4079                            gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
4080       break;
4081     default:
4082       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4083       break;
4084     }
4085 }
4086
4087 static void
4088 gtk_notebook_add (GtkContainer *container,
4089                   GtkWidget    *widget)
4090 {
4091   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
4092                                  NULL, NULL, -1);
4093 }
4094
4095 static void
4096 gtk_notebook_remove (GtkContainer *container,
4097                      GtkWidget    *widget)
4098 {
4099   GtkNotebook *notebook = GTK_NOTEBOOK (container);
4100   GtkNotebookPrivate *priv = notebook->priv;
4101   GtkNotebookPage *page;
4102   GList *children;
4103   gint page_num = 0;
4104
4105   children = priv->children;
4106   while (children)
4107     {
4108       page = children->data;
4109
4110       if (page->child == widget)
4111         break;
4112
4113       page_num++;
4114       children = children->next;
4115     }
4116
4117   if (children == NULL)
4118     return;
4119
4120   g_object_ref (widget);
4121
4122   gtk_notebook_real_remove (notebook, children);
4123
4124   g_signal_emit (notebook,
4125                  notebook_signals[PAGE_REMOVED],
4126                  0,
4127                  widget,
4128                  page_num);
4129
4130   g_object_unref (widget);
4131 }
4132
4133 static gboolean
4134 focus_tabs_in (GtkNotebook *notebook)
4135 {
4136   GtkNotebookPrivate *priv = notebook->priv;
4137
4138   if (priv->show_tabs && priv->cur_page)
4139     {
4140       gtk_widget_grab_focus (GTK_WIDGET (notebook));
4141
4142       gtk_notebook_switch_focus_tab (notebook,
4143                                      g_list_find (priv->children,
4144                                                   priv->cur_page));
4145
4146       return TRUE;
4147     }
4148   else
4149     return FALSE;
4150 }
4151
4152 static gboolean
4153 focus_tabs_move (GtkNotebook     *notebook,
4154                  GtkDirectionType direction,
4155                  gint             search_direction)
4156 {
4157   GtkNotebookPrivate *priv = notebook->priv;
4158   GList *new_page;
4159
4160   new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4161                                        search_direction, TRUE);
4162   if (!new_page)
4163     {
4164       gboolean wrap_around;
4165
4166       g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4167                     "gtk-keynav-wrap-around", &wrap_around,
4168                     NULL);
4169
4170       if (wrap_around)
4171         new_page = gtk_notebook_search_page (notebook, NULL,
4172                                              search_direction, TRUE);
4173     }
4174
4175   if (new_page)
4176     gtk_notebook_switch_focus_tab (notebook, new_page);
4177   else
4178     gtk_widget_error_bell (GTK_WIDGET (notebook));
4179
4180   return TRUE;
4181 }
4182
4183 static gboolean
4184 focus_child_in (GtkNotebook      *notebook,
4185                 GtkDirectionType  direction)
4186 {
4187   GtkNotebookPrivate *priv = notebook->priv;
4188
4189   if (priv->cur_page)
4190     return gtk_widget_child_focus (priv->cur_page->child, direction);
4191   else
4192     return FALSE;
4193 }
4194
4195 static gboolean
4196 focus_action_in (GtkNotebook      *notebook,
4197                  gint              action,
4198                  GtkDirectionType  direction)
4199 {
4200   GtkNotebookPrivate *priv = notebook->priv;
4201
4202   if (priv->action_widget[action] &&
4203       gtk_widget_get_visible (priv->action_widget[action]))
4204     return gtk_widget_child_focus (priv->action_widget[action], direction);
4205   else
4206     return FALSE;
4207 }
4208
4209 /* Focus in the notebook can either be on the pages, or on
4210  * the tabs or on the action_widgets.
4211  */
4212 static gint
4213 gtk_notebook_focus (GtkWidget        *widget,
4214                     GtkDirectionType  direction)
4215 {
4216   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4217   GtkNotebookPrivate *priv = notebook->priv;
4218   GtkWidget *old_focus_child;
4219   GtkDirectionType effective_direction;
4220   gint first_action;
4221   gint last_action;
4222
4223   gboolean widget_is_focus;
4224   GtkContainer *container;
4225
4226   container = GTK_CONTAINER (widget);
4227
4228   if (priv->tab_pos == GTK_POS_TOP ||
4229       priv->tab_pos == GTK_POS_LEFT)
4230     {
4231       first_action = ACTION_WIDGET_START;
4232       last_action = ACTION_WIDGET_END;
4233     }
4234   else
4235     {
4236       first_action = ACTION_WIDGET_END;
4237       last_action = ACTION_WIDGET_START;
4238     }
4239
4240   if (priv->focus_out)
4241     {
4242       priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4243       return FALSE;
4244     }
4245
4246   widget_is_focus = gtk_widget_is_focus (widget);
4247   old_focus_child = gtk_container_get_focus_child (container);
4248
4249   effective_direction = get_effective_direction (notebook, direction);
4250
4251   if (old_focus_child)          /* Focus on page child or action widget */
4252     {
4253       if (gtk_widget_child_focus (old_focus_child, direction))
4254         return TRUE;
4255
4256       if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4257         {
4258           switch (effective_direction)
4259             {
4260             case GTK_DIR_DOWN:
4261               return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4262             case GTK_DIR_RIGHT:
4263               return focus_tabs_in (notebook);
4264             case GTK_DIR_LEFT:
4265               return FALSE;
4266             case GTK_DIR_UP:
4267               return FALSE;
4268             default:
4269               switch (direction)
4270                 {
4271                 case GTK_DIR_TAB_FORWARD:
4272                   if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4273                       focus_child_in (notebook, direction))
4274                     return TRUE;
4275                   return focus_tabs_in (notebook);
4276                 case GTK_DIR_TAB_BACKWARD:
4277                   return FALSE;
4278                 default:
4279                   g_assert_not_reached ();
4280                 }
4281             }
4282         }
4283       else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4284         {
4285           switch (effective_direction)
4286             {
4287             case GTK_DIR_DOWN:
4288               return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4289             case GTK_DIR_RIGHT:
4290               return FALSE;
4291             case GTK_DIR_LEFT:
4292               return focus_tabs_in (notebook);
4293             case GTK_DIR_UP:
4294               return FALSE;
4295             default:
4296               switch (direction)
4297                 {
4298                 case GTK_DIR_TAB_FORWARD:
4299                   return FALSE;
4300                 case GTK_DIR_TAB_BACKWARD:
4301                   if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4302                       focus_child_in (notebook, direction))
4303                     return TRUE;
4304                   return focus_tabs_in (notebook);
4305                 default:
4306                   g_assert_not_reached ();
4307                 }
4308             }
4309         }
4310       else
4311         {
4312           switch (effective_direction)
4313             {
4314             case GTK_DIR_TAB_BACKWARD:
4315             case GTK_DIR_UP:
4316               /* Focus onto the tabs */
4317               return focus_tabs_in (notebook);
4318             case GTK_DIR_DOWN:
4319             case GTK_DIR_LEFT:
4320             case GTK_DIR_RIGHT:
4321               return FALSE;
4322             case GTK_DIR_TAB_FORWARD:
4323               return focus_action_in (notebook, last_action, direction);
4324             }
4325         }
4326     }
4327   else if (widget_is_focus)     /* Focus was on tabs */
4328     {
4329       switch (effective_direction)
4330         {
4331         case GTK_DIR_TAB_BACKWARD:
4332               return focus_action_in (notebook, first_action, direction);
4333         case GTK_DIR_UP:
4334           return FALSE;
4335         case GTK_DIR_TAB_FORWARD:
4336           if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4337             return TRUE;
4338           return focus_action_in (notebook, last_action, direction);
4339         case GTK_DIR_DOWN:
4340           /* We use TAB_FORWARD rather than direction so that we focus a more
4341            * predictable widget for the user; users may be using arrow focusing
4342            * in this situation even if they don't usually use arrow focusing.
4343            */
4344           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4345         case GTK_DIR_LEFT:
4346           return focus_tabs_move (notebook, direction, STEP_PREV);
4347         case GTK_DIR_RIGHT:
4348           return focus_tabs_move (notebook, direction, STEP_NEXT);
4349         }
4350     }
4351   else /* Focus was not on widget */
4352     {
4353       switch (effective_direction)
4354         {
4355         case GTK_DIR_TAB_FORWARD:
4356         case GTK_DIR_DOWN:
4357           if (focus_action_in (notebook, first_action, direction))
4358             return TRUE;
4359           if (focus_tabs_in (notebook))
4360             return TRUE;
4361           if (focus_action_in (notebook, last_action, direction))
4362             return TRUE;
4363           if (focus_child_in (notebook, direction))
4364             return TRUE;
4365           return FALSE;
4366         case GTK_DIR_TAB_BACKWARD:
4367           if (focus_action_in (notebook, last_action, direction))
4368             return TRUE;
4369           if (focus_child_in (notebook, direction))
4370             return TRUE;
4371           if (focus_tabs_in (notebook))
4372             return TRUE;
4373           if (focus_action_in (notebook, first_action, direction))
4374             return TRUE;
4375         case GTK_DIR_UP:
4376         case GTK_DIR_LEFT:
4377         case GTK_DIR_RIGHT:
4378           return focus_child_in (notebook, direction);
4379         }
4380     }
4381
4382   g_assert_not_reached ();
4383   return FALSE;
4384 }
4385
4386 static void
4387 gtk_notebook_set_focus_child (GtkContainer *container,
4388                               GtkWidget    *child)
4389 {
4390   GtkNotebook *notebook = GTK_NOTEBOOK (container);
4391   GtkNotebookPrivate *priv = notebook->priv;
4392   GtkWidget *page_child;
4393   GtkWidget *toplevel;
4394
4395   /* If the old focus widget was within a page of the notebook,
4396    * (child may either be NULL or not in this case), record it
4397    * for future use if we switch to the page with a mnemonic.
4398    */
4399
4400   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4401   if (toplevel && gtk_widget_is_toplevel (toplevel))
4402     {
4403       page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4404       while (page_child)
4405         {
4406           if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4407             {
4408               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4409               if (list != NULL)
4410                 {
4411                   GtkNotebookPage *page = list->data;
4412
4413                   if (page->last_focus_child)
4414                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4415
4416                   page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4417                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4418
4419                   break;
4420                 }
4421             }
4422
4423           page_child = gtk_widget_get_parent (page_child);
4424         }
4425     }
4426
4427   if (child)
4428     {
4429       g_return_if_fail (GTK_IS_WIDGET (child));
4430
4431       priv->child_has_focus = TRUE;
4432       if (!priv->focus_tab)
4433         {
4434           GList *children;
4435           GtkNotebookPage *page;
4436
4437           children = priv->children;
4438           while (children)
4439             {
4440               page = children->data;
4441               if (page->child == child || page->tab_label == child)
4442                 gtk_notebook_switch_focus_tab (notebook, children);
4443               children = children->next;
4444             }
4445         }
4446     }
4447   else
4448     priv->child_has_focus = FALSE;
4449
4450   GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4451 }
4452
4453 static void
4454 gtk_notebook_forall (GtkContainer *container,
4455                      gboolean      include_internals,
4456                      GtkCallback   callback,
4457                      gpointer      callback_data)
4458 {
4459   GtkNotebook *notebook = GTK_NOTEBOOK (container);
4460   GtkNotebookPrivate *priv = notebook->priv;
4461   GList *children;
4462   gint i;
4463
4464   children = priv->children;
4465   while (children)
4466     {
4467       GtkNotebookPage *page;
4468
4469       page = children->data;
4470       children = children->next;
4471       (* callback) (page->child, callback_data);
4472
4473       if (include_internals)
4474         {
4475           if (page->tab_label)
4476             (* callback) (page->tab_label, callback_data);
4477         }
4478     }
4479
4480   if (include_internals) {
4481     for (i = 0; i < N_ACTION_WIDGETS; i++)
4482       {
4483         if (priv->action_widget[i])
4484           (* callback) (priv->action_widget[i], callback_data);
4485       }
4486   }
4487 }
4488
4489 static GtkWidgetPath *
4490 gtk_notebook_get_path_for_child (GtkContainer *container,
4491                                  GtkWidget    *widget)
4492 {
4493   GtkNotebookPrivate *priv;
4494   GtkNotebook *notebook;
4495   GtkNotebookPage *page;
4496   GtkWidgetPath *path;
4497   GList *c;
4498
4499   path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4500
4501   notebook = GTK_NOTEBOOK (container);
4502   priv = notebook->priv;
4503
4504   for (c = priv->children; c; c = c->next)
4505     {
4506       page = c->data;
4507
4508       if (page->tab_label == widget)
4509         break;
4510     }
4511
4512   /* Widget is not a tab label */
4513   if (!c)
4514     return path;
4515
4516   gtk_widget_path_iter_add_region (path, 
4517                                    gtk_widget_path_length (path) - 2,
4518                                    GTK_STYLE_REGION_TAB,
4519                                    _gtk_notebook_get_tab_flags (notebook, page));
4520
4521   return path;
4522 }
4523
4524 static GType
4525 gtk_notebook_child_type (GtkContainer     *container)
4526 {
4527   return GTK_TYPE_WIDGET;
4528 }
4529
4530 /* Private GtkNotebook Methods:
4531  *
4532  * gtk_notebook_real_insert_page
4533  */
4534 static void
4535 page_visible_cb (GtkWidget  *page,
4536                  GParamSpec *arg,
4537                  gpointer    data)
4538 {
4539   GtkNotebook *notebook = GTK_NOTEBOOK (data);
4540   GtkNotebookPrivate *priv = notebook->priv;
4541   GList *list;
4542   GList *next = NULL;
4543
4544   if (priv->cur_page &&
4545       priv->cur_page->child == page &&
4546       !gtk_widget_get_visible (page))
4547     {
4548       list = g_list_find (priv->children, priv->cur_page);
4549       if (list)
4550         {
4551           next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4552           if (!next)
4553             next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4554         }
4555
4556       if (next)
4557         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4558     }
4559 }
4560
4561 static gint
4562 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4563                                GtkWidget   *child,
4564                                GtkWidget   *tab_label,
4565                                GtkWidget   *menu_label,
4566                                gint         position)
4567 {
4568   GtkNotebookPrivate *priv = notebook->priv;
4569   GtkNotebookPage *page;
4570   gint nchildren;
4571
4572   gtk_widget_freeze_child_notify (child);
4573
4574   page = g_slice_new0 (GtkNotebookPage);
4575   page->child = child;
4576
4577   nchildren = g_list_length (priv->children);
4578   if ((position < 0) || (position > nchildren))
4579     position = nchildren;
4580
4581   priv->children = g_list_insert (priv->children, page, position);
4582
4583   if (!tab_label)
4584     {
4585       page->default_tab = TRUE;
4586     }
4587   page->tab_label = tab_label;
4588   page->menu_label = menu_label;
4589   page->expand = FALSE;
4590   page->fill = TRUE;
4591
4592   if (!menu_label)
4593     page->default_menu = TRUE;
4594   else
4595     g_object_ref_sink (page->menu_label);
4596
4597   if (priv->menu)
4598     gtk_notebook_menu_item_create (notebook,
4599                                    g_list_find (priv->children, page));
4600
4601   /* child visible will be turned on by switch_page below */
4602   if (priv->cur_page != page)
4603     gtk_widget_set_child_visible (child, FALSE);
4604
4605   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4606   if (tab_label)
4607     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4608
4609   gtk_notebook_update_labels (notebook);
4610
4611   if (!priv->first_tab)
4612     priv->first_tab = priv->children;
4613
4614   if (tab_label)
4615     {
4616       if (priv->show_tabs && gtk_widget_get_visible (child))
4617         gtk_widget_show (tab_label);
4618       else
4619         gtk_widget_hide (tab_label);
4620
4621     page->mnemonic_activate_signal =
4622       g_signal_connect (tab_label,
4623                         "mnemonic-activate",
4624                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4625                         notebook);
4626     }
4627
4628   page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4629                                                    G_CALLBACK (page_visible_cb), notebook);
4630
4631   g_signal_emit (notebook,
4632                  notebook_signals[PAGE_ADDED],
4633                  0,
4634                  child,
4635                  position);
4636
4637   if (!priv->cur_page)
4638     {
4639       gtk_notebook_switch_page (notebook, page);
4640       /* focus_tab is set in the switch_page method */
4641       gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4642     }
4643
4644   gtk_notebook_update_tab_states (notebook);
4645
4646   if (priv->scrollable)
4647     gtk_notebook_redraw_arrows (notebook);
4648
4649   gtk_widget_child_notify (child, "tab-expand");
4650   gtk_widget_child_notify (child, "tab-fill");
4651   gtk_widget_child_notify (child, "tab-label");
4652   gtk_widget_child_notify (child, "menu-label");
4653   gtk_widget_child_notify (child, "position");
4654   gtk_widget_thaw_child_notify (child);
4655
4656   /* The page-added handler might have reordered the pages, re-get the position */
4657   return gtk_notebook_page_num (notebook, child);
4658 }
4659
4660 /* Private GtkNotebook Functions:
4661  *
4662  * gtk_notebook_redraw_tabs
4663  * gtk_notebook_real_remove
4664  * gtk_notebook_update_labels
4665  * gtk_notebook_timer
4666  * gtk_notebook_set_scroll_timer
4667  * gtk_notebook_page_compare
4668  * gtk_notebook_search_page
4669  */
4670 static void
4671 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4672 {
4673   GtkNotebookPrivate *priv = notebook->priv;
4674   GtkAllocation allocation;
4675   GtkWidget *widget;
4676   GtkNotebookPage *page;
4677   GdkRectangle redraw_rect;
4678   gint border;
4679   gint tab_pos = get_effective_tab_pos (notebook);
4680   GtkBorder padding;
4681
4682   widget = GTK_WIDGET (notebook);
4683   border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4684
4685   if (!gtk_widget_get_mapped (widget) || !priv->cur_page)
4686     return;
4687
4688   page = priv->cur_page;
4689
4690   redraw_rect.x = border;
4691   redraw_rect.y = border;
4692
4693   gtk_widget_get_allocation (widget, &allocation);
4694
4695   get_padding_and_border (notebook, &padding);
4696
4697   switch (tab_pos)
4698     {
4699     case GTK_POS_BOTTOM:
4700       redraw_rect.y = allocation.height - border -
4701         page->allocation.height - padding.bottom;
4702       /* fall through */
4703     case GTK_POS_TOP:
4704       redraw_rect.width = allocation.width - 2 * border;
4705       redraw_rect.height = page->allocation.height + padding.top;
4706
4707       break;
4708     case GTK_POS_RIGHT:
4709       redraw_rect.x = allocation.width - border -
4710         page->allocation.width - padding.right;
4711
4712       /* fall through */
4713     case GTK_POS_LEFT:
4714       redraw_rect.width = page->allocation.width + padding.left;
4715       redraw_rect.height = allocation.height - 2 * border;
4716
4717       break;
4718     }
4719
4720   redraw_rect.x += allocation.x;
4721   redraw_rect.y += allocation.y;
4722
4723   gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4724                               &redraw_rect, TRUE);
4725 }
4726
4727 static void
4728 gtk_notebook_redraw_tabs_junction (GtkNotebook *notebook)
4729 {
4730   GtkNotebookPrivate *priv = notebook->priv;
4731   GtkAllocation allocation;
4732   GtkWidget *widget;
4733   GtkNotebookPage *page;
4734   GdkRectangle redraw_rect;
4735   gint border;
4736   gint tab_pos = get_effective_tab_pos (notebook);
4737   GtkBorder padding;
4738
4739   widget = GTK_WIDGET (notebook);
4740   border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4741
4742   if (!gtk_widget_get_mapped (widget) || !priv->cur_page)
4743     return;
4744
4745   page = priv->cur_page;
4746
4747   redraw_rect.x = border;
4748   redraw_rect.y = border;
4749
4750   gtk_widget_get_allocation (widget, &allocation);
4751
4752   get_padding_and_border (notebook, &padding);
4753
4754   switch (tab_pos)
4755     {
4756     case GTK_POS_TOP:
4757     case GTK_POS_BOTTOM:
4758       redraw_rect.width = allocation.width - 2 * border;
4759       if (tab_pos == GTK_POS_TOP)
4760         {
4761           redraw_rect.y = border + page->allocation.y +
4762             page->allocation.height;
4763           redraw_rect.height = padding.top;
4764         }
4765       else
4766         {
4767           redraw_rect.y = allocation.height - border -
4768             page->allocation.height - padding.bottom;
4769           redraw_rect.height = padding.bottom;
4770         }
4771       break;
4772     case GTK_POS_LEFT:
4773     case GTK_POS_RIGHT:
4774       redraw_rect.height = allocation.height - 2 * border;
4775
4776       if (tab_pos == GTK_POS_LEFT)
4777         {
4778           redraw_rect.x = border + page->allocation.x + page->allocation.width;
4779           redraw_rect.width = padding.left;
4780         }
4781       else
4782         {
4783           redraw_rect.x = allocation.width - border -
4784             page->allocation.width - padding.right;
4785           redraw_rect.width = padding.right;
4786         }
4787       break;
4788     }
4789
4790   redraw_rect.x += allocation.x;
4791   redraw_rect.y += allocation.y;
4792
4793   gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4794                               &redraw_rect, TRUE);
4795 }
4796
4797 static void
4798 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4799 {
4800   GtkNotebookPrivate *priv = notebook->priv;
4801
4802   if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4803       gtk_notebook_show_arrows (notebook))
4804     {
4805       GdkRectangle rect;
4806       gint i;
4807       GtkNotebookArrow arrow[4];
4808
4809       arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4810       arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4811       arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4812       arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4813
4814       for (i = 0; i < 4; i++)
4815         {
4816           if (arrow[i] == ARROW_NONE)
4817             continue;
4818
4819           gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4820           gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4821                                       &rect, FALSE);
4822         }
4823     }
4824 }
4825
4826 static gboolean
4827 gtk_notebook_timer (GtkNotebook *notebook)
4828 {
4829   GtkNotebookPrivate *priv = notebook->priv;
4830   gboolean retval = FALSE;
4831
4832   if (priv->timer)
4833     {
4834       gtk_notebook_do_arrow (notebook, priv->click_child);
4835
4836       if (priv->need_timer)
4837         {
4838           GtkSettings *settings;
4839           guint        timeout;
4840
4841           settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4842           g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4843
4844           priv->need_timer = FALSE;
4845           priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4846                                            (GSourceFunc) gtk_notebook_timer,
4847                                            (gpointer) notebook);
4848         }
4849       else
4850         retval = TRUE;
4851     }
4852
4853   return retval;
4854 }
4855
4856 static void
4857 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4858 {
4859   GtkNotebookPrivate *priv = notebook->priv;
4860   GtkWidget *widget = GTK_WIDGET (notebook);
4861
4862   if (!priv->timer)
4863     {
4864       GtkSettings *settings = gtk_widget_get_settings (widget);
4865       guint timeout;
4866
4867       g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4868
4869       priv->timer = gdk_threads_add_timeout (timeout,
4870                                        (GSourceFunc) gtk_notebook_timer,
4871                                        (gpointer) notebook);
4872       priv->need_timer = TRUE;
4873     }
4874 }
4875
4876 static gint
4877 gtk_notebook_page_compare (gconstpointer a,
4878                            gconstpointer b)
4879 {
4880   return (((GtkNotebookPage *) a)->child != b);
4881 }
4882
4883 static GList*
4884 gtk_notebook_find_child (GtkNotebook *notebook,
4885                          GtkWidget   *child,
4886                          const gchar *function)
4887 {
4888   GtkNotebookPrivate *priv = notebook->priv;
4889   GList *list = g_list_find_custom (priv->children, child,
4890                                     gtk_notebook_page_compare);
4891
4892 #ifndef G_DISABLE_CHECKS
4893   if (!list && function)
4894     g_warning ("%s: unable to find child %p in notebook %p",
4895                function, child, notebook);
4896 #endif
4897
4898   return list;
4899 }
4900
4901 static void
4902 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
4903                                GtkNotebookPage *page)
4904 {
4905   if (page->tab_label)
4906     {
4907       if (page->mnemonic_activate_signal)
4908         g_signal_handler_disconnect (page->tab_label,
4909                                      page->mnemonic_activate_signal);
4910       page->mnemonic_activate_signal = 0;
4911
4912       gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4913       gtk_widget_unparent (page->tab_label);
4914       page->tab_label = NULL;
4915     }
4916 }
4917
4918 static void
4919 gtk_notebook_real_remove (GtkNotebook *notebook,
4920                           GList       *list)
4921 {
4922   GtkNotebookPrivate *priv = notebook->priv;
4923   GtkNotebookPage *page;
4924   GList * next_list;
4925   gint need_resize = FALSE;
4926   GtkWidget *tab_label;
4927   gboolean destroying;
4928
4929   destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4930
4931   next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4932   if (!next_list)
4933     next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4934
4935   priv->children = g_list_remove_link (priv->children, list);
4936
4937   if (priv->cur_page == list->data)
4938     {
4939       priv->cur_page = NULL;
4940       if (next_list && !destroying)
4941         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4942     }
4943
4944   if (priv->detached_tab == list->data)
4945     priv->detached_tab = NULL;
4946
4947   if (list == priv->first_tab)
4948     priv->first_tab = next_list;
4949   if (list == priv->focus_tab && !destroying)
4950     gtk_notebook_switch_focus_tab (notebook, next_list);
4951
4952   page = list->data;
4953
4954   g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4955
4956   if (gtk_widget_get_visible (page->child) &&
4957       gtk_widget_get_visible (GTK_WIDGET (notebook)))
4958     need_resize = TRUE;
4959
4960   gtk_widget_unparent (page->child);
4961
4962   tab_label = page->tab_label;
4963   if (tab_label)
4964     {
4965       g_object_ref (tab_label);
4966       gtk_notebook_remove_tab_label (notebook, page);
4967       if (destroying)
4968         gtk_widget_destroy (tab_label);
4969       g_object_unref (tab_label);
4970     }
4971
4972   if (priv->menu)
4973     {
4974       GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4975
4976       gtk_notebook_menu_label_unparent (parent, NULL);
4977       gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4978
4979       gtk_widget_queue_resize (priv->menu);
4980     }
4981   if (!page->default_menu)
4982     g_object_unref (page->menu_label);
4983
4984   g_list_free (list);
4985
4986   if (page->last_focus_child)
4987     {
4988       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4989       page->last_focus_child = NULL;
4990     }
4991
4992   g_slice_free (GtkNotebookPage, page);
4993
4994   gtk_notebook_update_labels (notebook);
4995   if (need_resize)
4996     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4997 }
4998
4999 static void
5000 gtk_notebook_update_labels (GtkNotebook *notebook)
5001 {
5002   GtkNotebookPrivate *priv = notebook->priv;
5003   GtkNotebookPage *page;
5004   GList *list;
5005   gchar string[32];
5006   gint page_num = 1;
5007
5008   if (!priv->show_tabs && !priv->menu)
5009     return;
5010
5011   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
5012        list;
5013        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
5014     {
5015       page = list->data;
5016       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
5017       if (priv->show_tabs)
5018         {
5019           if (page->default_tab)
5020             {
5021               if (!page->tab_label)
5022                 {
5023                   page->tab_label = gtk_label_new (string);
5024                   gtk_widget_set_parent (page->tab_label,
5025                                          GTK_WIDGET (notebook));
5026                 }
5027               else
5028                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
5029             }
5030
5031           if (gtk_widget_get_visible (page->child) &&
5032               !gtk_widget_get_visible (page->tab_label))
5033             gtk_widget_show (page->tab_label);
5034           else if (!gtk_widget_get_visible (page->child) &&
5035                    gtk_widget_get_visible (page->tab_label))
5036             gtk_widget_hide (page->tab_label);
5037         }
5038       if (priv->menu && page->default_menu)
5039         {
5040           if (GTK_IS_LABEL (page->tab_label))
5041             gtk_label_set_text (GTK_LABEL (page->menu_label),
5042                                 gtk_label_get_label (GTK_LABEL (page->tab_label)));
5043           else
5044             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
5045         }
5046     }
5047 }
5048
5049 static GList *
5050 gtk_notebook_search_page (GtkNotebook *notebook,
5051                           GList       *list,
5052                           gint         direction,
5053                           gboolean     find_visible)
5054 {
5055   GtkNotebookPrivate *priv = notebook->priv;
5056   GtkNotebookPage *page = NULL;
5057   GList *old_list = NULL;
5058
5059   if (list)
5060     page = list->data;
5061
5062   if (!page || direction == STEP_NEXT)
5063     {
5064       if (list)
5065         {
5066           old_list = list;
5067           list = list->next;
5068         }
5069       else
5070         list = priv->children;
5071
5072       while (list)
5073         {
5074           page = list->data;
5075           if (direction == STEP_NEXT &&
5076               (!find_visible ||
5077                (gtk_widget_get_visible (page->child) &&
5078                 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5079             return list;
5080           old_list = list;
5081           list = list->next;
5082         }
5083       list = old_list;
5084     }
5085   else
5086     {
5087       old_list = list;
5088       list = list->prev;
5089     }
5090   while (list)
5091     {
5092       page = list->data;
5093       if (direction == STEP_PREV &&
5094           (!find_visible ||
5095            (gtk_widget_get_visible (page->child) &&
5096             (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5097         return list;
5098       old_list = list;
5099       list = list->prev;
5100     }
5101   return NULL;
5102 }
5103
5104 /* Private GtkNotebook Drawing Functions:
5105  *
5106  * gtk_notebook_paint
5107  * gtk_notebook_draw_tab
5108  * gtk_notebook_draw_arrow
5109  */
5110 static void
5111 gtk_notebook_paint (GtkWidget    *widget,
5112                     cairo_t      *cr)
5113 {
5114   GtkNotebook *notebook;
5115   GtkNotebookPrivate *priv;
5116   GtkNotebookPage *page;
5117   GtkAllocation allocation;
5118   GList *children;
5119   gboolean showarrow;
5120   gint width, height;
5121   gint x, y;
5122   guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5123   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
5124   gboolean is_rtl;
5125   gint tab_pos;
5126   GtkStyleContext *context;
5127
5128   notebook = GTK_NOTEBOOK (widget);
5129   priv = notebook->priv;
5130   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5131   tab_pos = get_effective_tab_pos (notebook);
5132   context = gtk_widget_get_style_context (widget);
5133   showarrow = FALSE;
5134
5135   if ((!priv->show_tabs && !priv->show_border) ||
5136       !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
5137     return;
5138
5139   gtk_widget_get_allocation (widget, &allocation);
5140
5141   x = allocation.x + border_width;
5142   y = allocation.y + border_width;
5143   width = allocation.width - border_width * 2;
5144   height = allocation.height - border_width * 2;
5145
5146   if (priv->show_border && (!priv->show_tabs || !priv->children))
5147     {
5148       gtk_render_background (context, cr,
5149                              x, y, width, height);
5150       gtk_render_frame (context, cr,
5151                         x, y, width, height);
5152       return;
5153     }
5154
5155   if (!priv->first_tab)
5156     priv->first_tab = priv->children;
5157
5158   if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
5159     page = GTK_NOTEBOOK_PAGE (priv->first_tab);
5160   else
5161     page = priv->cur_page;
5162
5163   switch (tab_pos)
5164     {
5165     case GTK_POS_TOP:
5166       y += page->allocation.height;
5167       /* fall thru */
5168     case GTK_POS_BOTTOM:
5169       height -= page->allocation.height;
5170       break;
5171     case GTK_POS_LEFT:
5172       x += page->allocation.width;
5173       /* fall thru */
5174     case GTK_POS_RIGHT:
5175       width -= page->allocation.width;
5176       break;
5177     }
5178
5179   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
5180       !gtk_widget_get_mapped (priv->cur_page->tab_label))
5181     {
5182       gap_x = 0;
5183       gap_width = 0;
5184     }
5185   else
5186     {
5187       switch (tab_pos)
5188         {
5189         case GTK_POS_TOP:
5190         case GTK_POS_BOTTOM:
5191           if (priv->operation == DRAG_OPERATION_REORDER)
5192             gap_x = priv->drag_window_x - allocation.x - border_width;
5193           else
5194             gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5195
5196           gap_width = priv->cur_page->allocation.width;
5197           step = is_rtl ? STEP_PREV : STEP_NEXT;
5198           break;
5199         case GTK_POS_LEFT:
5200         case GTK_POS_RIGHT:
5201           if (priv->operation == DRAG_OPERATION_REORDER)
5202             gap_x = priv->drag_window_y - border_width - allocation.y;
5203           else
5204             gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5205
5206           gap_width = priv->cur_page->allocation.height;
5207           step = STEP_PREV;
5208           break;
5209         }
5210     }
5211
5212   for (children = priv->children; children; children = children->next)
5213     {
5214       page = children->data;
5215
5216       if (!gtk_widget_get_visible (page->child))
5217         continue;
5218
5219       if (!gtk_widget_get_mapped (page->tab_label))
5220         showarrow = TRUE;
5221
5222       /* No point in keeping searching */
5223       if (showarrow)
5224         break;
5225     }
5226
5227   gtk_style_context_save (context);
5228
5229   if (!showarrow || !priv->scrollable)
5230     {
5231       GtkJunctionSides junction = 0;
5232
5233       /* Apply junction sides, if no arrows are shown,
5234        * then make corners with connecting tabs square.
5235        */
5236       switch (tab_pos)
5237         {
5238         case GTK_POS_TOP:
5239           junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5240
5241           break;
5242         case GTK_POS_BOTTOM:
5243           junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5244
5245           break;
5246         case GTK_POS_LEFT:
5247           junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5248
5249           break;
5250         case GTK_POS_RIGHT:
5251           junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5252
5253           break;
5254         }
5255
5256       gtk_style_context_set_junction_sides (context, junction);
5257     }
5258
5259   gtk_render_background (context, cr,
5260                          x, y, width, height);
5261   gtk_render_frame_gap (context, cr,
5262                         x, y, width, height,
5263                         tab_pos, gap_x, gap_x + gap_width);
5264
5265   gtk_style_context_restore (context);
5266
5267   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5268
5269   while (children)
5270     {
5271       page = children->data;
5272
5273       if (page == priv->cur_page)
5274         break;
5275
5276       children = gtk_notebook_search_page (notebook, children,
5277                                            step, TRUE);
5278
5279       if (!gtk_widget_get_visible (page->child) ||
5280           !gtk_widget_get_mapped (page->tab_label))
5281         continue;
5282
5283       gtk_notebook_draw_tab (notebook, page, cr, TRUE);
5284     }
5285
5286   if (children != NULL)
5287     {
5288       GList *other_order = NULL;
5289
5290       while (children)
5291         {
5292           page = children->data;
5293           children = gtk_notebook_search_page (notebook, children,
5294                                                step, TRUE);
5295           if (!gtk_widget_get_visible (page->child) ||
5296               !gtk_widget_get_mapped (page->tab_label))
5297             continue;
5298
5299           if (children != NULL)
5300             other_order = g_list_prepend (other_order, children->data);
5301         }
5302
5303       /* draw them with the opposite order */
5304       for (children = other_order; children; children = children->next)
5305         {
5306           page = children->data;
5307           gtk_notebook_draw_tab (notebook, page, cr, TRUE);
5308         }
5309
5310       g_list_free (other_order);
5311     }
5312
5313   if (showarrow && priv->scrollable)
5314     {
5315       if (priv->has_before_previous)
5316         gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5317       if (priv->has_before_next)
5318         gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5319       if (priv->has_after_previous)
5320         gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5321       if (priv->has_after_next)
5322         gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5323     }
5324
5325   if (priv->operation != DRAG_OPERATION_REORDER)
5326     gtk_notebook_draw_tab (notebook, priv->cur_page, cr, TRUE);
5327 }
5328
5329 static void
5330 gtk_notebook_draw_tab (GtkNotebook     *notebook,
5331                        GtkNotebookPage *page,
5332                        cairo_t         *cr,
5333                        gboolean         use_flags)
5334 {
5335   GtkNotebookPrivate *priv;
5336   GtkWidget *widget;
5337   GtkStyleContext *context;
5338
5339   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5340       !gtk_widget_get_mapped (page->tab_label) ||
5341       (page->allocation.width == 0) || (page->allocation.height == 0))
5342     return;
5343
5344   widget = GTK_WIDGET (notebook);
5345   priv = notebook->priv;
5346
5347   context = gtk_widget_get_style_context (widget);
5348   gtk_style_context_save (context);
5349   notebook_tab_prepare_style_context (notebook, page, context, use_flags);
5350
5351   gtk_render_extension (context, cr,
5352                        page->allocation.x,
5353                        page->allocation.y,
5354                        page->allocation.width,
5355                        page->allocation.height,
5356                        get_tab_gap_pos (notebook));
5357
5358   if (gtk_widget_has_visible_focus (widget) &&
5359       priv->cur_page == page)
5360     {
5361       gint focus_width, focus_pad;
5362       GtkAllocation allocation;
5363
5364       gtk_widget_get_allocation (page->tab_label, &allocation);
5365       gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5366       gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5367
5368       gtk_render_focus (context, cr,
5369                         allocation.x - focus_width - focus_pad,
5370                         allocation.y - focus_width - focus_pad,
5371                         allocation.width + 2 * (focus_width + focus_pad),
5372                         allocation.height + 2 * (focus_width + focus_pad));
5373     }
5374
5375   gtk_style_context_restore (context);
5376 }
5377
5378 static void
5379 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
5380                          cairo_t          *cr,
5381                          GtkNotebookArrow  nbarrow)
5382 {
5383   GtkNotebookPrivate *priv = notebook->priv;
5384   GtkStyleContext *context;
5385   GtkStateFlags state = 0;
5386   GtkWidget *widget;
5387   GdkRectangle arrow_rect;
5388   gboolean is_rtl, left;
5389   gint scroll_arrow_hlength;
5390   gint scroll_arrow_vlength;
5391   gint arrow_size;
5392   gdouble angle;
5393
5394   widget = GTK_WIDGET (notebook);
5395   context = gtk_widget_get_style_context (widget);
5396
5397   gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5398
5399   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5400   left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5401          (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5402
5403   gtk_widget_style_get (widget,
5404                         "scroll-arrow-hlength", &scroll_arrow_hlength,
5405                         "scroll-arrow-vlength", &scroll_arrow_vlength,
5406                         NULL);
5407
5408   if (priv->in_child == nbarrow)
5409     {
5410       state |= GTK_STATE_FLAG_PRELIGHT;
5411
5412       if (priv->click_child == nbarrow)
5413         state |= GTK_STATE_FLAG_ACTIVE;
5414     }
5415   else
5416     state = gtk_widget_get_state_flags (widget);
5417
5418   if (priv->focus_tab &&
5419       !gtk_notebook_search_page (notebook, priv->focus_tab,
5420                                  left ? STEP_PREV : STEP_NEXT, TRUE))
5421     state = GTK_STATE_FLAG_INSENSITIVE;
5422
5423   if (priv->tab_pos == GTK_POS_LEFT ||
5424       priv->tab_pos == GTK_POS_RIGHT)
5425     {
5426       angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5427       arrow_size = scroll_arrow_vlength;
5428     }
5429   else
5430     {
5431       angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5432       arrow_size = scroll_arrow_hlength;
5433     }
5434
5435   gtk_style_context_save (context);
5436   gtk_style_context_set_state (context, state);
5437
5438   gtk_render_arrow (context, cr, angle,
5439                     arrow_rect.x, arrow_rect.y,
5440                     arrow_size);
5441
5442   gtk_style_context_restore (context);
5443 }
5444
5445 /* Private GtkNotebook Size Allocate Functions:
5446  *
5447  * gtk_notebook_tab_space
5448  * gtk_notebook_calculate_shown_tabs
5449  * gtk_notebook_calculate_tabs_allocation
5450  * gtk_notebook_pages_allocate
5451  * gtk_notebook_page_allocate
5452  * gtk_notebook_calc_tabs
5453  */
5454 static void
5455 gtk_notebook_tab_space (GtkNotebook *notebook,
5456                         gboolean    *show_arrows,
5457                         gint        *min,
5458                         gint        *max,
5459                         gint        *tab_space)
5460 {
5461   GtkNotebookPrivate *priv = notebook->priv;
5462   GtkAllocation allocation, action_allocation;
5463   GtkWidget *widget;
5464   GList *children;
5465   gint tab_pos = get_effective_tab_pos (notebook);
5466   gint tab_overlap;
5467   gint arrow_spacing;
5468   gint scroll_arrow_hlength;
5469   gint scroll_arrow_vlength;
5470   gboolean is_rtl;
5471   gint i;
5472   guint border_width;
5473   GtkBorder padding;
5474   gint initial_gap;
5475
5476   widget = GTK_WIDGET (notebook);
5477   children = priv->children;
5478   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5479
5480   gtk_widget_style_get (GTK_WIDGET (notebook),
5481                         "arrow-spacing", &arrow_spacing,
5482                         "scroll-arrow-hlength", &scroll_arrow_hlength,
5483                         "scroll-arrow-vlength", &scroll_arrow_vlength,
5484                         "initial-gap", &initial_gap,
5485                         NULL);
5486
5487   border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5488   get_padding_and_border (notebook, &padding);
5489
5490   gtk_widget_get_allocation (widget, &allocation);
5491
5492   switch (tab_pos)
5493     {
5494     case GTK_POS_TOP:
5495     case GTK_POS_BOTTOM:
5496       *min = allocation.x + border_width;
5497       *max = allocation.x + allocation.width - border_width;
5498
5499       for (i = 0; i < N_ACTION_WIDGETS; i++)
5500         {
5501           if (priv->action_widget[i])
5502             {
5503               gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5504
5505               if ((i == ACTION_WIDGET_START && !is_rtl) ||
5506                   (i == ACTION_WIDGET_END && is_rtl))
5507                 *min += action_allocation.width + padding.left;
5508               else
5509                 *max -= action_allocation.width + padding.right;
5510             }
5511         }
5512
5513       while (children)
5514         {
5515           GtkNotebookPage *page;
5516
5517           page = children->data;
5518           children = children->next;
5519
5520           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5521               gtk_widget_get_visible (page->child))
5522             *tab_space += page->requisition.width;
5523         }
5524       break;
5525     case GTK_POS_RIGHT:
5526     case GTK_POS_LEFT:
5527       *min = allocation.y + border_width;
5528       *max = allocation.y + allocation.height - border_width;
5529
5530       for (i = 0; i < N_ACTION_WIDGETS; i++)
5531         {
5532           if (priv->action_widget[i])
5533             {
5534               gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5535
5536               if (i == ACTION_WIDGET_START)
5537                 *min += action_allocation.height + padding.top;
5538               else
5539                 *max -= action_allocation.height + padding.bottom;
5540             }
5541         }
5542
5543       while (children)
5544         {
5545           GtkNotebookPage *page;
5546
5547           page = children->data;
5548           children = children->next;
5549
5550           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5551               gtk_widget_get_visible (page->child))
5552             *tab_space += page->requisition.height;
5553         }
5554       break;
5555     }
5556
5557   *min += initial_gap;
5558   *max -= (2 * initial_gap);
5559
5560   if (!priv->scrollable)
5561     *show_arrows = FALSE;
5562   else
5563     {
5564       gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5565
5566       switch (tab_pos)
5567         {
5568         case GTK_POS_TOP:
5569         case GTK_POS_BOTTOM:
5570           if (*tab_space > *max - *min - tab_overlap)
5571             {
5572               *show_arrows = TRUE;
5573
5574               /* take arrows into account */
5575               *tab_space = *max - *min - tab_overlap;
5576
5577               if (priv->has_after_previous)
5578                 {
5579                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5580                   *max -= arrow_spacing + scroll_arrow_hlength;
5581                 }
5582
5583               if (priv->has_after_next)
5584                 {
5585                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5586                   *max -= arrow_spacing + scroll_arrow_hlength;
5587                 }
5588
5589               if (priv->has_before_previous)
5590                 {
5591                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5592                   *min += arrow_spacing + scroll_arrow_hlength;
5593                 }
5594
5595               if (priv->has_before_next)
5596                 {
5597                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5598                   *min += arrow_spacing + scroll_arrow_hlength;
5599                 }
5600             }
5601           break;
5602         case GTK_POS_LEFT:
5603         case GTK_POS_RIGHT:
5604           if (*tab_space > *max - *min - tab_overlap)
5605             {
5606               *show_arrows = TRUE;
5607
5608               /* take arrows into account */
5609               *tab_space = *max - *min - tab_overlap;
5610
5611               if (priv->has_after_previous || priv->has_after_next)
5612                 {
5613                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
5614                   *max -= arrow_spacing + scroll_arrow_vlength;
5615                 }
5616
5617               if (priv->has_before_previous || priv->has_before_next)
5618                 {
5619                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
5620                   *min += arrow_spacing + scroll_arrow_vlength;
5621                 }
5622             }
5623           break;
5624         }
5625     }
5626 }
5627
5628 static void
5629 gtk_notebook_calculate_shown_tabs (GtkNotebook  *notebook,
5630                                    gboolean      show_arrows,
5631                                    gint          min,
5632                                    gint          max,
5633                                    gint          tab_space,
5634                                    GList       **last_child,
5635                                    gint         *n,
5636                                    gint         *remaining_space)
5637 {
5638   GtkNotebookPrivate *priv = notebook->priv;
5639   GtkWidget *widget;
5640   GList *children;
5641   GtkNotebookPage *page;
5642   gint tab_overlap;
5643
5644   widget = GTK_WIDGET (notebook);
5645   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5646
5647   if (show_arrows) /* first_tab <- focus_tab */
5648     {
5649       *remaining_space = tab_space;
5650
5651       if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5652           gtk_widget_get_visible (priv->cur_page->child))
5653         {
5654           gtk_notebook_calc_tabs (notebook,
5655                                   priv->focus_tab,
5656                                   &(priv->focus_tab),
5657                                   remaining_space, STEP_NEXT);
5658         }
5659
5660       if (tab_space <= 0 || *remaining_space <= 0)
5661         {
5662           /* show 1 tab */
5663           priv->first_tab = priv->focus_tab;
5664           *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5665                                                   STEP_NEXT, TRUE);
5666           page = priv->first_tab->data;
5667           *remaining_space = tab_space - page->requisition.width;
5668           *n = 1;
5669         }
5670       else
5671         {
5672           children = NULL;
5673
5674           if (priv->first_tab && priv->first_tab != priv->focus_tab)
5675             {
5676               /* Is first_tab really predecessor of focus_tab? */
5677               page = priv->first_tab->data;
5678               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5679                   gtk_widget_get_visible (page->child))
5680                 for (children = priv->focus_tab;
5681                      children && children != priv->first_tab;
5682                      children = gtk_notebook_search_page (notebook,
5683                                                           children,
5684                                                           STEP_PREV,
5685                                                           TRUE));
5686             }
5687
5688           if (!children)
5689             {
5690               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5691                 priv->first_tab = priv->focus_tab;
5692               else
5693                 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5694                                                             STEP_NEXT, TRUE);
5695             }
5696           else
5697             /* calculate shown tabs counting backwards from the focus tab */
5698             gtk_notebook_calc_tabs (notebook,
5699                                     gtk_notebook_search_page (notebook,
5700                                                               priv->focus_tab,
5701                                                               STEP_PREV,
5702                                                               TRUE),
5703                                     &(priv->first_tab),
5704                                     remaining_space,
5705                                     STEP_PREV);
5706
5707           if (*remaining_space < 0)
5708             {
5709               priv->first_tab =
5710                 gtk_notebook_search_page (notebook, priv->first_tab,
5711                                           STEP_NEXT, TRUE);
5712               if (!priv->first_tab)
5713                 priv->first_tab = priv->focus_tab;
5714
5715               *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5716                                                       STEP_NEXT, TRUE);
5717             }
5718           else /* focus_tab -> end */
5719             {
5720               if (!priv->first_tab)
5721                 priv->first_tab = gtk_notebook_search_page (notebook,
5722                                                             NULL,
5723                                                             STEP_NEXT,
5724                                                             TRUE);
5725               children = NULL;
5726               gtk_notebook_calc_tabs (notebook,
5727                                       gtk_notebook_search_page (notebook,
5728                                                                 priv->focus_tab,
5729                                                                 STEP_NEXT,
5730                                                                 TRUE),
5731                                       &children,
5732                                       remaining_space,
5733                                       STEP_NEXT);
5734
5735               if (*remaining_space <= 0)
5736                 *last_child = children;
5737               else /* start <- first_tab */
5738                 {
5739                   *last_child = NULL;
5740                   children = NULL;
5741
5742                   gtk_notebook_calc_tabs (notebook,
5743                                           gtk_notebook_search_page (notebook,
5744                                                                     priv->first_tab,
5745                                                                     STEP_PREV,
5746                                                                     TRUE),
5747                                           &children,
5748                                           remaining_space,
5749                                           STEP_PREV);
5750
5751                   if (*remaining_space == 0)
5752                     priv->first_tab = children;
5753                   else
5754                     priv->first_tab = gtk_notebook_search_page(notebook,
5755                                                                children,
5756                                                                STEP_NEXT,
5757                                                                TRUE);
5758                 }
5759             }
5760
5761           if (*remaining_space < 0)
5762             {
5763               /* calculate number of tabs */
5764               *remaining_space = - (*remaining_space);
5765               *n = 0;
5766
5767               for (children = priv->first_tab;
5768                    children && children != *last_child;
5769                    children = gtk_notebook_search_page (notebook, children,
5770                                                         STEP_NEXT, TRUE))
5771                 (*n)++;
5772             }
5773           else
5774             *remaining_space = 0;
5775         }
5776
5777       /* unmap all non-visible tabs */
5778       for (children = gtk_notebook_search_page (notebook, NULL,
5779                                                 STEP_NEXT, TRUE);
5780            children && children != priv->first_tab;
5781            children = gtk_notebook_search_page (notebook, children,
5782                                                 STEP_NEXT, TRUE))
5783         {
5784           page = children->data;
5785
5786           if (page->tab_label &&
5787               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5788             gtk_widget_set_child_visible (page->tab_label, FALSE);
5789         }
5790
5791       for (children = *last_child; children;
5792            children = gtk_notebook_search_page (notebook, children,
5793                                                 STEP_NEXT, TRUE))
5794         {
5795           page = children->data;
5796
5797           if (page->tab_label &&
5798               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5799             gtk_widget_set_child_visible (page->tab_label, FALSE);
5800         }
5801     }
5802   else /* !show_arrows */
5803     {
5804       GtkOrientation tab_expand_orientation;
5805       gint c = 0;
5806       *n = 0;
5807
5808       if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5809         tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5810       else
5811         tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5812       *remaining_space = max - min - tab_overlap - tab_space;
5813       children = priv->children;
5814       priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5815                                                   STEP_NEXT, TRUE);
5816       while (children)
5817         {
5818           page = children->data;
5819           children = children->next;
5820
5821           if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5822               !gtk_widget_get_visible (page->child))
5823             continue;
5824
5825           c++;
5826
5827           if (page->expand ||
5828               (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5829             (*n)++;
5830         }
5831     }
5832 }
5833
5834 static gboolean
5835 get_allocate_at_bottom (GtkWidget *widget,
5836                         gint       search_direction)
5837 {
5838   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5839   gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5840
5841   switch (tab_pos)
5842     {
5843     case GTK_POS_TOP:
5844     case GTK_POS_BOTTOM:
5845       if (!is_rtl)
5846         return (search_direction == STEP_PREV);
5847       else
5848         return (search_direction == STEP_NEXT);
5849
5850       break;
5851     case GTK_POS_RIGHT:
5852     case GTK_POS_LEFT:
5853       return (search_direction == STEP_PREV);
5854       break;
5855     }
5856
5857   return FALSE;
5858 }
5859
5860 static void
5861 gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
5862                                         GList       **children,
5863                                         GList        *last_child,
5864                                         gboolean      showarrow,
5865                                         gint          direction,
5866                                         gint         *remaining_space,
5867                                         gint         *expanded_tabs,
5868                                         gint          min,
5869                                         gint          max)
5870 {
5871   GtkNotebookPrivate *priv = notebook->priv;
5872   GtkAllocation allocation;
5873   GtkWidget *widget;
5874   GtkContainer *container;
5875   GtkNotebookPage *page;
5876   GtkStyleContext *context;
5877   gboolean allocate_at_bottom;
5878   gint tab_overlap, tab_pos, tab_extra_space;
5879   gint left_x, right_x, top_y, bottom_y, anchor;
5880   guint border_width;
5881   gboolean gap_left, packing_changed;
5882   GtkAllocation child_allocation = { 0, };
5883   GtkOrientation tab_expand_orientation;
5884
5885   widget = GTK_WIDGET (notebook);
5886   container = GTK_CONTAINER (notebook);
5887   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5888   tab_pos = get_effective_tab_pos (notebook);
5889   allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5890   anchor = 0;
5891
5892   gtk_widget_get_allocation (widget, &allocation);
5893
5894   border_width = gtk_container_get_border_width (container);
5895   child_allocation.x = allocation.x + border_width;
5896   child_allocation.y = allocation.y + border_width;
5897
5898   context = gtk_widget_get_style_context (widget);
5899
5900   switch (tab_pos)
5901     {
5902     case GTK_POS_BOTTOM:
5903       child_allocation.y = allocation.y + allocation.height -
5904         priv->cur_page->requisition.height - border_width;
5905       /* fall through */
5906     case GTK_POS_TOP:
5907       child_allocation.x = (allocate_at_bottom) ? max : min;
5908       child_allocation.height = priv->cur_page->requisition.height;
5909       anchor = child_allocation.x;
5910       break;
5911
5912     case GTK_POS_RIGHT:
5913       child_allocation.x = allocation.x + allocation.width -
5914         priv->cur_page->requisition.width - border_width;
5915       /* fall through */
5916     case GTK_POS_LEFT:
5917       child_allocation.y = (allocate_at_bottom) ? max : min;
5918       child_allocation.width = priv->cur_page->requisition.width;
5919       anchor = child_allocation.y;
5920       break;
5921     }
5922
5923   left_x   = CLAMP (priv->mouse_x - priv->drag_offset_x,
5924                     min, max - priv->cur_page->allocation.width);
5925   top_y    = CLAMP (priv->mouse_y - priv->drag_offset_y,
5926                     min, max - priv->cur_page->allocation.height);
5927   right_x  = left_x + priv->cur_page->allocation.width;
5928   bottom_y = top_y + priv->cur_page->allocation.height;
5929   gap_left = packing_changed = FALSE;
5930
5931   if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5932     tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5933   else
5934     tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5935
5936   while (*children && *children != last_child)
5937     {
5938       page = (*children)->data;
5939
5940       if (direction == STEP_NEXT)
5941         *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5942       else
5943         {
5944           *children = (*children)->next;
5945           continue;
5946         }
5947
5948       if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5949         continue;
5950
5951       tab_extra_space = 0;
5952       if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5953         {
5954           tab_extra_space = *remaining_space / *expanded_tabs;
5955           *remaining_space -= tab_extra_space;
5956           (*expanded_tabs)--;
5957         }
5958
5959       switch (tab_pos)
5960         {
5961         case GTK_POS_TOP:
5962         case GTK_POS_BOTTOM:
5963           child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5964
5965           /* make sure that the reordered tab doesn't go past the last position */
5966           if (priv->operation == DRAG_OPERATION_REORDER &&
5967               !gap_left && packing_changed)
5968             {
5969               if (!allocate_at_bottom)
5970                 {
5971                   if (left_x >= anchor)
5972                     {
5973                       left_x = priv->drag_window_x = anchor;
5974                       anchor += priv->cur_page->allocation.width - tab_overlap;
5975                     }
5976                 }
5977               else
5978                 {
5979                   if (right_x <= anchor)
5980                     {
5981                       anchor -= priv->cur_page->allocation.width;
5982                       left_x = priv->drag_window_x = anchor;
5983                       anchor += tab_overlap;
5984                     }
5985                 }
5986
5987               gap_left = TRUE;
5988             }
5989
5990           if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5991             {
5992               priv->drag_window_x = left_x;
5993               priv->drag_window_y = child_allocation.y;
5994             }
5995           else
5996             {
5997               if (allocate_at_bottom)
5998                 anchor -= child_allocation.width;
5999
6000               if (priv->operation == DRAG_OPERATION_REORDER)
6001                 {
6002                   if (!allocate_at_bottom &&
6003                       left_x >= anchor &&
6004                       left_x <= anchor + child_allocation.width / 2)
6005                     anchor += priv->cur_page->allocation.width - tab_overlap;
6006                   else if (allocate_at_bottom &&
6007                            right_x >= anchor + child_allocation.width / 2 &&
6008                            right_x <= anchor + child_allocation.width)
6009                     anchor -= priv->cur_page->allocation.width - tab_overlap;
6010                 }
6011
6012               child_allocation.x = anchor;
6013             }
6014
6015           break;
6016         case GTK_POS_LEFT:
6017         case GTK_POS_RIGHT:
6018           child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
6019
6020           /* make sure that the reordered tab doesn't go past the last position */
6021           if (priv->operation == DRAG_OPERATION_REORDER &&
6022               !gap_left && packing_changed)
6023             {
6024               if (!allocate_at_bottom && top_y >= anchor)
6025                 {
6026                   top_y = priv->drag_window_y = anchor;
6027                   anchor += priv->cur_page->allocation.height - tab_overlap;
6028                 }
6029
6030               gap_left = TRUE;
6031             }
6032
6033           if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
6034             {
6035               priv->drag_window_x = child_allocation.x;
6036               priv->drag_window_y = top_y;
6037             }
6038           else
6039             {
6040               if (allocate_at_bottom)
6041                 anchor -= child_allocation.height;
6042
6043               if (priv->operation == DRAG_OPERATION_REORDER)
6044                 {
6045                   if (!allocate_at_bottom &&
6046                       top_y >= anchor &&
6047                       top_y <= anchor + child_allocation.height / 2)
6048                     anchor += priv->cur_page->allocation.height - tab_overlap;
6049                   else if (allocate_at_bottom &&
6050                            bottom_y >= anchor + child_allocation.height / 2 &&
6051                            bottom_y <= anchor + child_allocation.height)
6052                     anchor -= priv->cur_page->allocation.height - tab_overlap;
6053                 }
6054
6055               child_allocation.y = anchor;
6056             }
6057
6058           break;
6059         }
6060
6061       page->allocation = child_allocation;
6062
6063       if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
6064           (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
6065         {
6066           /* needs to be allocated at 0,0
6067            * to be shown in the drag window */
6068           page->allocation.x = 0;
6069           page->allocation.y = 0;
6070         }
6071
6072       if (page != priv->cur_page)
6073         {
6074           GtkBorder active_padding, normal_padding, padding;
6075
6076           /* The active tab is by definition at least the same height as the inactive one.
6077            * The padding we're building is the offset between the two tab states, 
6078            * so in case the style specifies normal_padding > active_padding we
6079            * remove the offset and draw them with the same height.
6080            * Note that the padding will still be applied to the tab content though,
6081            * see gtk_notebook_page_allocate().
6082            */
6083           gtk_style_context_save (context);
6084           notebook_tab_prepare_style_context (notebook, page, context, TRUE);
6085
6086           gtk_style_context_get_padding (context, GTK_STATE_FLAG_ACTIVE, &active_padding);
6087           gtk_style_context_get_padding (context, GTK_STATE_FLAG_NORMAL, &normal_padding);
6088
6089           gtk_style_context_restore (context);
6090
6091           padding.top = MAX (0, active_padding.top - normal_padding.top);
6092           padding.right = MAX (0, active_padding.right - normal_padding.right);
6093           padding.bottom = MAX (0, active_padding.bottom - normal_padding.bottom);
6094           padding.left = MAX (0, active_padding.left - normal_padding.left);
6095
6096           switch (tab_pos)
6097             {
6098             case GTK_POS_TOP:
6099               page->allocation.y += padding.top + padding.bottom;
6100               page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom);
6101               break;
6102             case GTK_POS_BOTTOM:
6103               page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom);
6104               break;
6105             case GTK_POS_LEFT:
6106               page->allocation.x += padding.left + padding.right;
6107               page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right);
6108               break;
6109             case GTK_POS_RIGHT:
6110               page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right);
6111               break;
6112             }
6113         }
6114
6115       /* calculate whether to leave a gap based on reorder operation or not */
6116       switch (tab_pos)
6117         {
6118         case GTK_POS_TOP:
6119         case GTK_POS_BOTTOM:
6120           if (priv->operation != DRAG_OPERATION_REORDER ||
6121               (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6122             {
6123               if (priv->operation == DRAG_OPERATION_REORDER)
6124                 {
6125                   if (!allocate_at_bottom &&
6126                       left_x >  anchor + child_allocation.width / 2 &&
6127                       left_x <= anchor + child_allocation.width)
6128                     anchor += priv->cur_page->allocation.width - tab_overlap;
6129                   else if (allocate_at_bottom &&
6130                            right_x >= anchor &&
6131                            right_x <= anchor + child_allocation.width / 2)
6132                     anchor -= priv->cur_page->allocation.width - tab_overlap;
6133                 }
6134
6135               if (!allocate_at_bottom)
6136                 anchor += child_allocation.width - tab_overlap;
6137               else
6138                 anchor += tab_overlap;
6139             }
6140
6141           break;
6142         case GTK_POS_LEFT:
6143         case GTK_POS_RIGHT:
6144           if (priv->operation != DRAG_OPERATION_REORDER  ||
6145               (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6146             {
6147               if (priv->operation == DRAG_OPERATION_REORDER)
6148                 {
6149                   if (!allocate_at_bottom &&
6150                       top_y >= anchor + child_allocation.height / 2 &&
6151                       top_y <= anchor + child_allocation.height)
6152                     anchor += priv->cur_page->allocation.height - tab_overlap;
6153                   else if (allocate_at_bottom &&
6154                            bottom_y >= anchor &&
6155                            bottom_y <= anchor + child_allocation.height / 2)
6156                     anchor -= priv->cur_page->allocation.height - tab_overlap;
6157                 }
6158
6159               if (!allocate_at_bottom)
6160                 anchor += child_allocation.height - tab_overlap;
6161               else
6162                 anchor += tab_overlap;
6163             }
6164
6165           break;
6166         }
6167
6168       /* set child visible */
6169       if (page->tab_label)
6170         gtk_widget_set_child_visible (page->tab_label, TRUE);
6171     }
6172
6173   /* Don't move the current tab past the last position during tabs reordering */
6174   if (children &&
6175       priv->operation == DRAG_OPERATION_REORDER &&
6176       direction == STEP_NEXT)
6177     {
6178       switch (tab_pos)
6179         {
6180         case GTK_POS_TOP:
6181         case GTK_POS_BOTTOM:
6182           if (allocate_at_bottom)
6183             anchor -= priv->cur_page->allocation.width;
6184
6185           if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
6186               (allocate_at_bottom && priv->drag_window_x < anchor))
6187             priv->drag_window_x = anchor;
6188           break;
6189         case GTK_POS_LEFT:
6190         case GTK_POS_RIGHT:
6191           if (allocate_at_bottom)
6192             anchor -= priv->cur_page->allocation.height;
6193
6194           if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6195               (allocate_at_bottom && priv->drag_window_y < anchor))
6196             priv->drag_window_y = anchor;
6197           break;
6198         }
6199     }
6200 }
6201
6202 static void
6203 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6204 {
6205   GtkNotebookPrivate *priv = notebook->priv;
6206   GList *children = NULL;
6207   GList *last_child = NULL;
6208   gboolean showarrow = FALSE;
6209   gint tab_space, min, max, remaining_space;
6210   gint expanded_tabs;
6211   gboolean tab_allocations_changed = FALSE;
6212
6213   if (!priv->show_tabs || !priv->children || !priv->cur_page)
6214     return;
6215
6216   min = max = tab_space = remaining_space = 0;
6217   expanded_tabs = 1;
6218
6219   gtk_notebook_tab_space (notebook, &showarrow,
6220                           &min, &max, &tab_space);
6221
6222   gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6223                                      min, max, tab_space, &last_child,
6224                                      &expanded_tabs, &remaining_space);
6225
6226   children = priv->first_tab;
6227   gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6228                                           showarrow, STEP_NEXT,
6229                                           &remaining_space, &expanded_tabs, min, max);
6230   if (children && children != last_child)
6231     {
6232       children = priv->children;
6233       gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6234                                               showarrow, STEP_PREV,
6235                                               &remaining_space, &expanded_tabs, min, max);
6236     }
6237
6238   children = priv->children;
6239
6240   while (children)
6241     {
6242       if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6243         tab_allocations_changed = TRUE;
6244       children = children->next;
6245     }
6246
6247   if (!priv->first_tab)
6248     priv->first_tab = priv->children;
6249
6250   if (tab_allocations_changed)
6251     gtk_notebook_redraw_tabs (notebook);
6252 }
6253
6254 static gboolean
6255 gtk_notebook_page_allocate (GtkNotebook     *notebook,
6256                             GtkNotebookPage *page)
6257 {
6258   GtkWidget *widget = GTK_WIDGET (notebook);
6259   GtkNotebookPrivate *priv = notebook->priv;
6260   GtkAllocation child_allocation, label_allocation;
6261   GtkRequisition tab_requisition;
6262   GtkStyleContext *context;
6263   gint padding;
6264   gint focus_width, focus_padding;
6265   gint tab_curvature, tab_overlap;
6266   gint tab_pos = get_effective_tab_pos (notebook);
6267   gboolean tab_allocation_changed;
6268   gboolean was_visible = page->tab_allocated_visible;
6269   GtkBorder tab_padding;
6270   GtkStateFlags state;
6271
6272   if (!page->tab_label ||
6273       !gtk_widget_get_visible (page->tab_label) ||
6274       !gtk_widget_get_child_visible (page->tab_label))
6275     {
6276       page->tab_allocated_visible = FALSE;
6277       return was_visible;
6278     }
6279
6280   context = gtk_widget_get_style_context (widget);
6281
6282   gtk_style_context_save (context);
6283   state = notebook_tab_prepare_style_context (notebook, page, context, TRUE);
6284
6285   gtk_style_context_get_padding (context, state, &tab_padding);
6286
6287   gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6288   gtk_widget_style_get (widget,
6289                         "focus-line-width", &focus_width,
6290                         "focus-padding", &focus_padding,
6291                         "tab-curvature", &tab_curvature,
6292                         "tab-overlap", &tab_overlap,
6293                         NULL);
6294   switch (tab_pos)
6295     {
6296     case GTK_POS_TOP:
6297     case GTK_POS_BOTTOM:
6298       padding = tab_curvature + focus_width + focus_padding;
6299       if (page->fill)
6300         {
6301           child_allocation.x = tab_padding.left + padding;
6302           child_allocation.width = MAX (1, (page->allocation.width -
6303                                             tab_padding.left - tab_padding.right -
6304                                             2 * (padding)));
6305           child_allocation.x += page->allocation.x;
6306
6307           /* if we're drawing an inactive page, trim the allocation width
6308            * for the children by the difference between tab-curvature
6309            * and tab-overlap.
6310            * if we're after the active tab, we need to trim the x
6311            * coordinate of the allocation too, to position it after
6312            * the end of the overlap.
6313            */
6314           if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6315             {
6316               if (gtk_notebook_page_num (notebook, page->child) >
6317                   gtk_notebook_page_num (notebook, priv->cur_page->child))
6318                 {
6319                   child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6320                   child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6321                 }
6322               else
6323                 {
6324                   child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6325                 }
6326             }
6327         }
6328       else
6329         {
6330           child_allocation.x = page->allocation.x +
6331             (page->allocation.width - tab_requisition.width) / 2;
6332
6333           child_allocation.width = tab_requisition.width;
6334         }
6335
6336       child_allocation.y = 
6337         page->allocation.y + tab_padding.top + focus_width + focus_padding;
6338
6339       child_allocation.height = MAX (1, (page->allocation.height -
6340                                          tab_padding.top - tab_padding.bottom -
6341                                          2 * (focus_width + focus_padding)));
6342       break;
6343     case GTK_POS_LEFT:
6344     case GTK_POS_RIGHT:
6345       padding = tab_curvature + focus_width + focus_padding;
6346       if (page->fill)
6347         {
6348           child_allocation.y = tab_padding.top + padding;
6349           child_allocation.height = MAX (1, (page->allocation.height -
6350                                              tab_padding.bottom - tab_padding.top -
6351                                              2 * padding));
6352           child_allocation.y += page->allocation.y;
6353
6354           /* if we're drawing an inactive page, trim the allocation height
6355            * for the children by the difference between tab-curvature
6356            * and tab-overlap.
6357            * if we're after the active tab, we need to trim the y
6358            * coordinate of the allocation too, to position it after
6359            * the end of the overlap.
6360            */
6361           if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
6362             {
6363               if (gtk_notebook_page_num (notebook, page->child) >
6364                   gtk_notebook_page_num (notebook, priv->cur_page->child))
6365                 {
6366                   child_allocation.y += tab_overlap - tab_curvature - tab_padding.top;
6367                   child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top;
6368                 }
6369               else
6370                 {
6371                   child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom;
6372                 }
6373             }
6374         }
6375       else
6376         {
6377           child_allocation.y = page->allocation.y +
6378             (page->allocation.height - tab_requisition.height) / 2;
6379
6380           child_allocation.height = tab_requisition.height;
6381         }
6382
6383       child_allocation.x =
6384         page->allocation.x + tab_padding.left + focus_width + focus_padding;
6385
6386       child_allocation.width = MAX (1, (page->allocation.width -
6387                                          tab_padding.left - tab_padding.right -
6388                                          2 * (focus_width + focus_padding)));
6389       break;
6390     }
6391
6392   gtk_widget_get_allocation (page->tab_label, &label_allocation);
6393   tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6394                             child_allocation.y != label_allocation.y ||
6395                             child_allocation.width != label_allocation.width ||
6396                             child_allocation.height != label_allocation.height);
6397
6398   gtk_widget_size_allocate (page->tab_label, &child_allocation);
6399
6400   if (!was_visible)
6401     {
6402       page->tab_allocated_visible = TRUE;
6403       tab_allocation_changed = TRUE;
6404     }
6405
6406   gtk_style_context_restore (context);
6407
6408   return tab_allocation_changed;
6409 }
6410
6411 static void
6412 gtk_notebook_calc_tabs (GtkNotebook  *notebook,
6413                         GList        *start,
6414                         GList       **end,
6415                         gint         *tab_space,
6416                         guint         direction)
6417 {
6418   GtkNotebookPage *page = NULL;
6419   GList *children;
6420   GList *last_calculated_child = NULL;
6421   gint tab_pos = get_effective_tab_pos (notebook);
6422
6423   if (!start)
6424     return;
6425
6426   children = start;
6427
6428   switch (tab_pos)
6429     {
6430     case GTK_POS_TOP:
6431     case GTK_POS_BOTTOM:
6432       while (children)
6433         {
6434           page = children->data;
6435           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6436               gtk_widget_get_visible (page->child))
6437             {
6438               *tab_space -= page->requisition.width;
6439               if (*tab_space < 0 || children == *end)
6440                 {
6441                   if (*tab_space < 0)
6442                     {
6443                       *tab_space = - (*tab_space +
6444                                       page->requisition.width);
6445
6446                       if (*tab_space == 0 && direction == STEP_PREV)
6447                         children = last_calculated_child;
6448
6449                       *end = children;
6450                     }
6451                   return;
6452                 }
6453
6454               last_calculated_child = children;
6455             }
6456           if (direction == STEP_NEXT)
6457             children = children->next;
6458           else
6459             children = children->prev;
6460         }
6461       break;
6462     case GTK_POS_LEFT:
6463     case GTK_POS_RIGHT:
6464       while (children)
6465         {
6466           page = children->data;
6467           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6468               gtk_widget_get_visible (page->child))
6469             {
6470               *tab_space -= page->requisition.height;
6471               if (*tab_space < 0 || children == *end)
6472                 {
6473                   if (*tab_space < 0)
6474                     {
6475                       *tab_space = - (*tab_space + page->requisition.height);
6476
6477                       if (*tab_space == 0 && direction == STEP_PREV)
6478                         children = last_calculated_child;
6479
6480                       *end = children;
6481                     }
6482                   return;
6483                 }
6484
6485               last_calculated_child = children;
6486             }
6487           if (direction == STEP_NEXT)
6488             children = children->next;
6489           else
6490             children = children->prev;
6491         }
6492       break;
6493     }
6494 }
6495
6496 static void
6497 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6498 {
6499   GtkNotebookPrivate *priv = notebook->priv;
6500   GList *list;
6501   int pos;
6502
6503   pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6504
6505   for (list = priv->children; list != NULL; list = list->next)
6506     {
6507       GtkNotebookPage *page = list->data;
6508
6509       if (page->tab_label)
6510         {
6511           GtkRegionFlags current_flags;
6512
6513           if (page == priv->cur_page)
6514             gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6515           else
6516             gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6517
6518           /* FIXME: We should store these flags somewhere instead of poking
6519            * the widget's path */
6520           if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6521                                                 pos,
6522                                                 GTK_STYLE_REGION_TAB,
6523                                                 &current_flags)
6524               || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6525             gtk_widget_reset_style (page->tab_label);
6526         }
6527     }
6528 }
6529
6530 /* Private GtkNotebook Page Switch Methods:
6531  *
6532  * gtk_notebook_real_switch_page
6533  */
6534 static void
6535 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
6536                                GtkWidget*       child,
6537                                guint            page_num)
6538 {
6539   GtkNotebookPrivate *priv = notebook->priv;
6540   GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6541   GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6542   gboolean child_has_focus;
6543
6544   if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6545     return;
6546
6547   /* save the value here, changing visibility changes focus */
6548   child_has_focus = priv->child_has_focus;
6549
6550   if (priv->cur_page)
6551     gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6552
6553   priv->cur_page = page;
6554
6555   if (!priv->focus_tab ||
6556       priv->focus_tab->data != (gpointer) priv->cur_page)
6557     priv->focus_tab =
6558       g_list_find (priv->children, priv->cur_page);
6559
6560   gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6561
6562   /* If the focus was on the previous page, move it to the first
6563    * element on the new page, if possible, or if not, to the
6564    * notebook itself.
6565    */
6566   if (child_has_focus)
6567     {
6568       if (priv->cur_page->last_focus_child &&
6569           gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6570         gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6571       else
6572         if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6573           gtk_widget_grab_focus (GTK_WIDGET (notebook));
6574     }
6575
6576   gtk_notebook_update_tab_states (notebook);
6577   gtk_notebook_pages_allocate (notebook);
6578
6579   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6580   g_object_notify (G_OBJECT (notebook), "page");
6581 }
6582
6583 /* Private GtkNotebook Page Switch Functions:
6584  *
6585  * gtk_notebook_switch_page
6586  * gtk_notebook_page_select
6587  * gtk_notebook_switch_focus_tab
6588  * gtk_notebook_menu_switch_page
6589  */
6590 static void
6591 gtk_notebook_switch_page (GtkNotebook     *notebook,
6592                           GtkNotebookPage *page)
6593 {
6594   GtkNotebookPrivate *priv = notebook->priv;
6595   guint page_num;
6596
6597   if (priv->cur_page == page)
6598     return;
6599
6600   page_num = g_list_index (priv->children, page);
6601
6602   g_signal_emit (notebook,
6603                  notebook_signals[SWITCH_PAGE],
6604                  0,
6605                  page->child,
6606                  page_num);
6607 }
6608
6609 static gint
6610 gtk_notebook_page_select (GtkNotebook *notebook,
6611                           gboolean     move_focus)
6612 {
6613   GtkNotebookPrivate *priv = notebook->priv;
6614   GtkNotebookPage *page;
6615   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6616   gint tab_pos = get_effective_tab_pos (notebook);
6617
6618   if (!priv->focus_tab)
6619     return FALSE;
6620
6621   page = priv->focus_tab->data;
6622   gtk_notebook_switch_page (notebook, page);
6623
6624   if (move_focus)
6625     {
6626       switch (tab_pos)
6627         {
6628         case GTK_POS_TOP:
6629           dir = GTK_DIR_DOWN;
6630           break;
6631         case GTK_POS_BOTTOM:
6632           dir = GTK_DIR_UP;
6633           break;
6634         case GTK_POS_LEFT:
6635           dir = GTK_DIR_RIGHT;
6636           break;
6637         case GTK_POS_RIGHT:
6638           dir = GTK_DIR_LEFT;
6639           break;
6640         }
6641
6642       if (gtk_widget_child_focus (page->child, dir))
6643         return TRUE;
6644     }
6645   return FALSE;
6646 }
6647
6648 static void
6649 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6650                                GList       *new_child)
6651 {
6652   GtkNotebookPrivate *priv = notebook->priv;
6653   GtkNotebookPage *page;
6654
6655   if (priv->focus_tab == new_child)
6656     return;
6657
6658   priv->focus_tab = new_child;
6659
6660   if (priv->scrollable)
6661     gtk_notebook_redraw_arrows (notebook);
6662
6663   if (!priv->show_tabs || !priv->focus_tab)
6664     return;
6665
6666   page = priv->focus_tab->data;
6667   gtk_notebook_switch_page (notebook, page);
6668 }
6669
6670 static void
6671 gtk_notebook_menu_switch_page (GtkWidget       *widget,
6672                                GtkNotebookPage *page)
6673 {
6674   GtkNotebookPrivate *priv;
6675   GtkNotebook *notebook;
6676   GtkWidget *parent;
6677   GList *children;
6678   guint page_num;
6679
6680   parent = gtk_widget_get_parent (widget);
6681   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6682   priv = notebook->priv;
6683
6684   if (priv->cur_page == page)
6685     return;
6686
6687   page_num = 0;
6688   children = priv->children;
6689   while (children && children->data != page)
6690     {
6691       children = children->next;
6692       page_num++;
6693     }
6694
6695   g_signal_emit (notebook,
6696                  notebook_signals[SWITCH_PAGE],
6697                  0,
6698                  page->child,
6699                  page_num);
6700 }
6701
6702 /* Private GtkNotebook Menu Functions:
6703  *
6704  * gtk_notebook_menu_item_create
6705  * gtk_notebook_menu_label_unparent
6706  * gtk_notebook_menu_detacher
6707  */
6708 static void
6709 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6710                                GList       *list)
6711 {
6712   GtkNotebookPrivate *priv = notebook->priv;
6713   GtkNotebookPage *page;
6714   GtkWidget *menu_item;
6715
6716   page = list->data;
6717   if (page->default_menu)
6718     {
6719       if (GTK_IS_LABEL (page->tab_label))
6720         page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6721       else
6722         page->menu_label = gtk_label_new ("");
6723       gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START);
6724       gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER);
6725     }
6726
6727   gtk_widget_show (page->menu_label);
6728   menu_item = gtk_menu_item_new ();
6729   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6730   gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6731                          g_list_position (priv->children, list));
6732   g_signal_connect (menu_item, "activate",
6733                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
6734   if (gtk_widget_get_visible (page->child))
6735     gtk_widget_show (menu_item);
6736 }
6737
6738 static void
6739 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6740                                   gpointer  data)
6741 {
6742   gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6743   _gtk_bin_set_child (GTK_BIN (widget), NULL);
6744 }
6745
6746 static void
6747 gtk_notebook_menu_detacher (GtkWidget *widget,
6748                             GtkMenu   *menu)
6749 {
6750   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6751   GtkNotebookPrivate *priv = notebook->priv;
6752
6753   g_return_if_fail (priv->menu == (GtkWidget*) menu);
6754
6755   priv->menu = NULL;
6756 }
6757
6758 /* Public GtkNotebook Page Insert/Remove Methods :
6759  *
6760  * gtk_notebook_append_page
6761  * gtk_notebook_append_page_menu
6762  * gtk_notebook_prepend_page
6763  * gtk_notebook_prepend_page_menu
6764  * gtk_notebook_insert_page
6765  * gtk_notebook_insert_page_menu
6766  * gtk_notebook_remove_page
6767  */
6768 /**
6769  * gtk_notebook_append_page:
6770  * @notebook: a #GtkNotebook
6771  * @child: the #GtkWidget to use as the contents of the page
6772  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6773  *     for the page, or %NULL to use the default label, 'page N'
6774  *
6775  * Appends a page to @notebook.
6776  *
6777  * Return value: the index (starting from 0) of the appended
6778  *     page in the notebook, or -1 if function fails
6779  */
6780 gint
6781 gtk_notebook_append_page (GtkNotebook *notebook,
6782                           GtkWidget   *child,
6783                           GtkWidget   *tab_label)
6784 {
6785   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6786   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6787   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6788
6789   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6790 }
6791
6792 /**
6793  * gtk_notebook_append_page_menu:
6794  * @notebook: a #GtkNotebook
6795  * @child: the #GtkWidget to use as the contents of the page
6796  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6797  *     for the page, or %NULL to use the default label, 'page N'
6798  * @menu_label: (allow-none): the widget to use as a label for the
6799  *     page-switch menu, if that is enabled. If %NULL, and @tab_label
6800  *     is a #GtkLabel or %NULL, then the menu label will be a newly
6801  *     created label with the same text as @tab_label; if @tab_label
6802  *     is not a #GtkLabel, @menu_label must be specified if the
6803  *     page-switch menu is to be used.
6804  *
6805  * Appends a page to @notebook, specifying the widget to use as the
6806  * label in the popup menu.
6807  *
6808  * Return value: the index (starting from 0) of the appended
6809  *     page in the notebook, or -1 if function fails
6810  */
6811 gint
6812 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6813                                GtkWidget   *child,
6814                                GtkWidget   *tab_label,
6815                                GtkWidget   *menu_label)
6816 {
6817   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6818   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6819   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6820   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6821
6822   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6823 }
6824
6825 /**
6826  * gtk_notebook_prepend_page:
6827  * @notebook: a #GtkNotebook
6828  * @child: the #GtkWidget to use as the contents of the page
6829  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6830  *     for the page, or %NULL to use the default label, 'page N'
6831  *
6832  * Prepends a page to @notebook.
6833  *
6834  * Return value: the index (starting from 0) of the prepended
6835  *     page in the notebook, or -1 if function fails
6836  */
6837 gint
6838 gtk_notebook_prepend_page (GtkNotebook *notebook,
6839                            GtkWidget   *child,
6840                            GtkWidget   *tab_label)
6841 {
6842   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6843   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6844   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6845
6846   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6847 }
6848
6849 /**
6850  * gtk_notebook_prepend_page_menu:
6851  * @notebook: a #GtkNotebook
6852  * @child: the #GtkWidget to use as the contents of the page
6853  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6854  *     for the page, or %NULL to use the default label, 'page N'
6855  * @menu_label: (allow-none): the widget to use as a label for the
6856  *     page-switch menu, if that is enabled. If %NULL, and @tab_label
6857  *     is a #GtkLabel or %NULL, then the menu label will be a newly
6858  *     created label with the same text as @tab_label; if @tab_label
6859  *     is not a #GtkLabel, @menu_label must be specified if the
6860  *     page-switch menu is to be used.
6861  *
6862  * Prepends a page to @notebook, specifying the widget to use as the
6863  * label in the popup menu.
6864  *
6865  * Return value: the index (starting from 0) of the prepended
6866  *     page in the notebook, or -1 if function fails
6867  */
6868 gint
6869 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6870                                 GtkWidget   *child,
6871                                 GtkWidget   *tab_label,
6872                                 GtkWidget   *menu_label)
6873 {
6874   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6875   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6876   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6877   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6878
6879   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6880 }
6881
6882 /**
6883  * gtk_notebook_insert_page:
6884  * @notebook: a #GtkNotebook
6885  * @child: the #GtkWidget to use as the contents of the page
6886  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6887  *     for the page, or %NULL to use the default label, 'page N'
6888  * @position: the index (starting at 0) at which to insert the page,
6889  *     or -1 to append the page after all other pages
6890  *
6891  * Insert a page into @notebook at the given position.
6892  *
6893  * Return value: the index (starting from 0) of the inserted
6894  *     page in the notebook, or -1 if function fails
6895  */
6896 gint
6897 gtk_notebook_insert_page (GtkNotebook *notebook,
6898                           GtkWidget   *child,
6899                           GtkWidget   *tab_label,
6900                           gint         position)
6901 {
6902   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6903   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6904   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6905
6906   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6907 }
6908
6909
6910 static gint
6911 gtk_notebook_page_compare_tab (gconstpointer a,
6912                                gconstpointer b)
6913 {
6914   return (((GtkNotebookPage *) a)->tab_label != b);
6915 }
6916
6917 static gboolean
6918 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6919                                             gboolean overload,
6920                                             gpointer data)
6921 {
6922   GtkNotebook *notebook = GTK_NOTEBOOK (data);
6923   GtkNotebookPrivate *priv = notebook->priv;
6924   GList *list;
6925
6926   list = g_list_find_custom (priv->children, child,
6927                              gtk_notebook_page_compare_tab);
6928   if (list)
6929     {
6930       GtkNotebookPage *page = list->data;
6931
6932       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
6933       gtk_notebook_switch_page (notebook, page);
6934       focus_tabs_in (notebook);
6935     }
6936
6937   return TRUE;
6938 }
6939
6940 /**
6941  * gtk_notebook_insert_page_menu:
6942  * @notebook: a #GtkNotebook
6943  * @child: the #GtkWidget to use as the contents of the page
6944  * @tab_label: (allow-none): the #GtkWidget to be used as the label
6945  *     for the page, or %NULL to use the default label, 'page N'
6946  * @menu_label: (allow-none): the widget to use as a label for the
6947  *     page-switch menu, if that is enabled. If %NULL, and @tab_label
6948  *     is a #GtkLabel or %NULL, then the menu label will be a newly
6949  *     created label with the same text as @tab_label; if @tab_label
6950  *     is not a #GtkLabel, @menu_label must be specified if the
6951  *     page-switch menu is to be used.
6952  * @position: the index (starting at 0) at which to insert the page,
6953  *     or -1 to append the page after all other pages.
6954  *
6955  * Insert a page into @notebook at the given position, specifying
6956  * the widget to use as the label in the popup menu.
6957  *
6958  * Return value: the index (starting from 0) of the inserted
6959  *     page in the notebook
6960  */
6961 gint
6962 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6963                                GtkWidget   *child,
6964                                GtkWidget   *tab_label,
6965                                GtkWidget   *menu_label,
6966                                gint         position)
6967 {
6968   GtkNotebookClass *class;
6969
6970   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6971   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6972   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6973   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6974
6975   class = GTK_NOTEBOOK_GET_CLASS (notebook);
6976
6977   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6978 }
6979
6980 /**
6981  * gtk_notebook_remove_page:
6982  * @notebook: a #GtkNotebook
6983  * @page_num: the index of a notebook page, starting
6984  *     from 0. If -1, the last page will be removed.
6985  *
6986  * Removes a page from the notebook given its index
6987  * in the notebook.
6988  */
6989 void
6990 gtk_notebook_remove_page (GtkNotebook *notebook,
6991                           gint         page_num)
6992 {
6993   GtkNotebookPrivate *priv;
6994   GList *list = NULL;
6995
6996   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6997
6998   priv = notebook->priv;
6999
7000   if (page_num >= 0)
7001     list = g_list_nth (priv->children, page_num);
7002   else
7003     list = g_list_last (priv->children);
7004
7005   if (list)
7006     gtk_container_remove (GTK_CONTAINER (notebook),
7007                           ((GtkNotebookPage *) list->data)->child);
7008 }
7009
7010 /* Public GtkNotebook Page Switch Methods :
7011  * gtk_notebook_get_current_page
7012  * gtk_notebook_page_num
7013  * gtk_notebook_set_current_page
7014  * gtk_notebook_next_page
7015  * gtk_notebook_prev_page
7016  */
7017 /**
7018  * gtk_notebook_get_current_page:
7019  * @notebook: a #GtkNotebook
7020  *
7021  * Returns the page number of the current page.
7022  *
7023  * Return value: the index (starting from 0) of the current
7024  *     page in the notebook. If the notebook has no pages,
7025  *     then -1 will be returned.
7026  */
7027 gint
7028 gtk_notebook_get_current_page (GtkNotebook *notebook)
7029 {
7030   GtkNotebookPrivate *priv;
7031
7032   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7033
7034   priv = notebook->priv;
7035
7036   if (!priv->cur_page)
7037     return -1;
7038
7039   return g_list_index (priv->children, priv->cur_page);
7040 }
7041
7042 /**
7043  * gtk_notebook_get_nth_page:
7044  * @notebook: a #GtkNotebook
7045  * @page_num: the index of a page in the notebook, or -1
7046  *     to get the last page
7047  *
7048  * Returns the child widget contained in page number @page_num.
7049  *
7050  * Return value: (transfer none): the child widget, or %NULL
7051  *     if @page_num is out of bounds
7052  */
7053 GtkWidget*
7054 gtk_notebook_get_nth_page (GtkNotebook *notebook,
7055                            gint         page_num)
7056 {
7057   GtkNotebookPrivate *priv;
7058   GtkNotebookPage *page;
7059   GList *list;
7060
7061   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7062
7063   priv = notebook->priv;
7064
7065   if (page_num >= 0)
7066     list = g_list_nth (priv->children, page_num);
7067   else
7068     list = g_list_last (priv->children);
7069
7070   if (list)
7071     {
7072       page = list->data;
7073       return page->child;
7074     }
7075
7076   return NULL;
7077 }
7078
7079 /**
7080  * gtk_notebook_get_n_pages:
7081  * @notebook: a #GtkNotebook
7082  *
7083  * Gets the number of pages in a notebook.
7084  *
7085  * Return value: the number of pages in the notebook
7086  *
7087  * Since: 2.2
7088  */
7089 gint
7090 gtk_notebook_get_n_pages (GtkNotebook *notebook)
7091 {
7092   GtkNotebookPrivate *priv;
7093
7094   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
7095
7096   priv = notebook->priv;
7097
7098   return g_list_length (priv->children);
7099 }
7100
7101 /**
7102  * gtk_notebook_page_num:
7103  * @notebook: a #GtkNotebook
7104  * @child: a #GtkWidget
7105  *
7106  * Finds the index of the page which contains the given child
7107  * widget.
7108  *
7109  * Return value: the index of the page containing @child, or
7110  *     -1 if @child is not in the notebook
7111  */
7112 gint
7113 gtk_notebook_page_num (GtkNotebook      *notebook,
7114                        GtkWidget        *child)
7115 {
7116   GtkNotebookPrivate *priv;
7117   GList *children;
7118   gint num;
7119
7120   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7121
7122   priv = notebook->priv;
7123
7124   num = 0;
7125   children = priv->children;
7126   while (children)
7127     {
7128       GtkNotebookPage *page =  children->data;
7129
7130       if (page->child == child)
7131         return num;
7132
7133       children = children->next;
7134       num++;
7135     }
7136
7137   return -1;
7138 }
7139
7140 /**
7141  * gtk_notebook_set_current_page:
7142  * @notebook: a #GtkNotebook
7143  * @page_num: index of the page to switch to, starting from 0.
7144  *     If negative, the last page will be used. If greater
7145  *     than the number of pages in the notebook, nothing
7146  *     will be done.
7147  *
7148  * Switches to the page number @page_num.
7149  *
7150  * Note that due to historical reasons, GtkNotebook refuses
7151  * to switch to a page unless the child widget is visible.
7152  * Therefore, it is recommended to show child widgets before
7153  * adding them to a notebook.
7154  */
7155 void
7156 gtk_notebook_set_current_page (GtkNotebook *notebook,
7157                                gint         page_num)
7158 {
7159   GtkNotebookPrivate *priv;
7160   GList *list;
7161
7162   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7163
7164   priv = notebook->priv;
7165
7166   if (page_num < 0)
7167     page_num = g_list_length (priv->children) - 1;
7168
7169   list = g_list_nth (priv->children, page_num);
7170   if (list)
7171     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7172 }
7173
7174 /**
7175  * gtk_notebook_next_page:
7176  * @notebook: a #GtkNotebook
7177  *
7178  * Switches to the next page. Nothing happens if the current page is
7179  * the last page.
7180  */
7181 void
7182 gtk_notebook_next_page (GtkNotebook *notebook)
7183 {
7184   GtkNotebookPrivate *priv;
7185   GList *list;
7186
7187   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7188
7189   priv = notebook->priv;
7190
7191   list = g_list_find (priv->children, priv->cur_page);
7192   if (!list)
7193     return;
7194
7195   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7196   if (!list)
7197     return;
7198
7199   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7200 }
7201
7202 /**
7203  * gtk_notebook_prev_page:
7204  * @notebook: a #GtkNotebook
7205  *
7206  * Switches to the previous page. Nothing happens if the current page
7207  * is the first page.
7208  */
7209 void
7210 gtk_notebook_prev_page (GtkNotebook *notebook)
7211 {
7212   GtkNotebookPrivate *priv;
7213   GList *list;
7214
7215   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7216
7217   priv = notebook->priv;
7218
7219   list = g_list_find (priv->children, priv->cur_page);
7220   if (!list)
7221     return;
7222
7223   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7224   if (!list)
7225     return;
7226
7227   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7228 }
7229
7230 /* Public GtkNotebook/Tab Style Functions
7231  *
7232  * gtk_notebook_set_show_border
7233  * gtk_notebook_get_show_border
7234  * gtk_notebook_set_show_tabs
7235  * gtk_notebook_get_show_tabs
7236  * gtk_notebook_set_tab_pos
7237  * gtk_notebook_get_tab_pos
7238  * gtk_notebook_set_scrollable
7239  * gtk_notebook_get_scrollable
7240  * gtk_notebook_get_tab_hborder
7241  * gtk_notebook_get_tab_vborder
7242  */
7243 /**
7244  * gtk_notebook_set_show_border:
7245  * @notebook: a #GtkNotebook
7246  * @show_border: %TRUE if a bevel should be drawn around the notebook
7247  *
7248  * Sets whether a bevel will be drawn around the notebook pages.
7249  * This only has a visual effect when the tabs are not shown.
7250  * See gtk_notebook_set_show_tabs().
7251  */
7252 void
7253 gtk_notebook_set_show_border (GtkNotebook *notebook,
7254                               gboolean     show_border)
7255 {
7256   GtkNotebookPrivate *priv;
7257
7258   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7259
7260   priv = notebook->priv;
7261
7262   if (priv->show_border != show_border)
7263     {
7264       priv->show_border = show_border;
7265
7266       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7267         gtk_widget_queue_resize (GTK_WIDGET (notebook));
7268
7269       g_object_notify (G_OBJECT (notebook), "show-border");
7270     }
7271 }
7272
7273 /**
7274  * gtk_notebook_get_show_border:
7275  * @notebook: a #GtkNotebook
7276  *
7277  * Returns whether a bevel will be drawn around the notebook pages.
7278  * See gtk_notebook_set_show_border().
7279  *
7280  * Return value: %TRUE if the bevel is drawn
7281  */
7282 gboolean
7283 gtk_notebook_get_show_border (GtkNotebook *notebook)
7284 {
7285   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7286
7287   return notebook->priv->show_border;
7288 }
7289
7290 /**
7291  * gtk_notebook_set_show_tabs:
7292  * @notebook: a #GtkNotebook
7293  * @show_tabs: %TRUE if the tabs should be shown
7294  *
7295  * Sets whether to show the tabs for the notebook or not.
7296  */
7297 void
7298 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7299                             gboolean     show_tabs)
7300 {
7301   GtkNotebookPrivate *priv;
7302   GtkNotebookPage *page;
7303   GtkStyleContext *context;
7304   GList *children;
7305   gint i;
7306
7307   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7308
7309   priv = notebook->priv;
7310
7311   show_tabs = show_tabs != FALSE;
7312
7313   if (priv->show_tabs == show_tabs)
7314     return;
7315
7316   priv->show_tabs = show_tabs;
7317   children = priv->children;
7318   context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7319
7320   if (!show_tabs)
7321     {
7322       gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7323
7324       while (children)
7325         {
7326           page = children->data;
7327           children = children->next;
7328           if (page->default_tab)
7329             {
7330               gtk_widget_destroy (page->tab_label);
7331               page->tab_label = NULL;
7332             }
7333           else
7334             gtk_widget_hide (page->tab_label);
7335         }
7336
7337       gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7338     }
7339   else
7340     {
7341       gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7342       gtk_notebook_update_labels (notebook);
7343       gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7344     }
7345
7346   for (i = 0; i < N_ACTION_WIDGETS; i++)
7347     {
7348       if (priv->action_widget[i])
7349         gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7350     }
7351
7352   gtk_widget_reset_style (GTK_WIDGET (notebook));
7353   gtk_widget_queue_resize (GTK_WIDGET (notebook));
7354
7355   g_object_notify (G_OBJECT (notebook), "show-tabs");
7356 }
7357
7358 /**
7359  * gtk_notebook_get_show_tabs:
7360  * @notebook: a #GtkNotebook
7361  *
7362  * Returns whether the tabs of the notebook are shown.
7363  * See gtk_notebook_set_show_tabs().
7364  *
7365  * Return value: %TRUE if the tabs are shown
7366  */
7367 gboolean
7368 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7369 {
7370   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7371
7372   return notebook->priv->show_tabs;
7373 }
7374
7375 /**
7376  * gtk_notebook_set_tab_pos:
7377  * @notebook: a #GtkNotebook.
7378  * @pos: the edge to draw the tabs at
7379  *
7380  * Sets the edge at which the tabs for switching pages in the
7381  * notebook are drawn.
7382  */
7383 void
7384 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
7385                           GtkPositionType  pos)
7386 {
7387   GtkNotebookPrivate *priv;
7388
7389   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7390
7391   priv = notebook->priv;
7392
7393   if (priv->tab_pos != pos)
7394     {
7395       priv->tab_pos = pos;
7396       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7397         gtk_widget_queue_resize (GTK_WIDGET (notebook));
7398     }
7399
7400   g_object_notify (G_OBJECT (notebook), "tab-pos");
7401 }
7402
7403 /**
7404  * gtk_notebook_get_tab_pos:
7405  * @notebook: a #GtkNotebook
7406  *
7407  * Gets the edge at which the tabs for switching pages in the
7408  * notebook are drawn.
7409  *
7410  * Return value: the edge at which the tabs are drawn
7411  */
7412 GtkPositionType
7413 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7414 {
7415   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7416
7417   return notebook->priv->tab_pos;
7418 }
7419
7420 /**
7421  * gtk_notebook_set_scrollable:
7422  * @notebook: a #GtkNotebook
7423  * @scrollable: %TRUE if scroll arrows should be added
7424  *
7425  * Sets whether the tab label area will have arrows for
7426  * scrolling if there are too many tabs to fit in the area.
7427  */
7428 void
7429 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7430                              gboolean     scrollable)
7431 {
7432   GtkNotebookPrivate *priv;
7433
7434   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7435
7436   priv = notebook->priv;
7437
7438   scrollable = (scrollable != FALSE);
7439
7440   if (scrollable != priv->scrollable)
7441     {
7442       priv->scrollable = scrollable;
7443
7444       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7445         gtk_widget_queue_resize (GTK_WIDGET (notebook));
7446
7447       g_object_notify (G_OBJECT (notebook), "scrollable");
7448     }
7449 }
7450
7451 /**
7452  * gtk_notebook_get_scrollable:
7453  * @notebook: a #GtkNotebook
7454  *
7455  * Returns whether the tab label area has arrows for scrolling.
7456  * See gtk_notebook_set_scrollable().
7457  *
7458  * Return value: %TRUE if arrows for scrolling are present
7459  */
7460 gboolean
7461 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7462 {
7463   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7464
7465   return notebook->priv->scrollable;
7466 }
7467
7468 /**
7469  * gtk_notebook_get_tab_hborder:
7470  * @notebook: a #GtkNotebook
7471  *
7472  * Returns the horizontal width of a tab border.
7473  *
7474  * Return value: horizontal width of a tab border
7475  *
7476  * Since: 2.22
7477  *
7478  * Deprecated: 3.4: this function returns zero
7479  */
7480 guint16
7481 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7482 {
7483   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7484
7485   return 0;
7486 }
7487
7488 /**
7489  * gtk_notebook_get_tab_vborder:
7490  * @notebook: a #GtkNotebook
7491  *
7492  * Returns the vertical width of a tab border.
7493  *
7494  * Return value: vertical width of a tab border
7495  *
7496  * Since: 2.22
7497  *
7498  * Deprecated: 3.4: this function returns zero
7499  */
7500 guint16
7501 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7502 {
7503   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7504
7505   return 0;
7506 }
7507
7508
7509 /* Public GtkNotebook Popup Menu Methods:
7510  *
7511  * gtk_notebook_popup_enable
7512  * gtk_notebook_popup_disable
7513  */
7514
7515
7516 /**
7517  * gtk_notebook_popup_enable:
7518  * @notebook: a #GtkNotebook
7519  *
7520  * Enables the popup menu: if the user clicks with the right
7521  * mouse button on the tab labels, a menu with all the pages
7522  * will be popped up.
7523  */
7524 void
7525 gtk_notebook_popup_enable (GtkNotebook *notebook)
7526 {
7527   GtkNotebookPrivate *priv;
7528   GList *list;
7529
7530   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7531
7532   priv = notebook->priv;
7533
7534   if (priv->menu)
7535     return;
7536
7537   priv->menu = gtk_menu_new ();
7538   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7539        list;
7540        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7541     gtk_notebook_menu_item_create (notebook, list);
7542
7543   gtk_notebook_update_labels (notebook);
7544   gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7545                              GTK_WIDGET (notebook),
7546                              gtk_notebook_menu_detacher);
7547
7548   g_object_notify (G_OBJECT (notebook), "enable-popup");
7549 }
7550
7551 /**
7552  * gtk_notebook_popup_disable:
7553  * @notebook: a #GtkNotebook
7554  *
7555  * Disables the popup menu.
7556  */
7557 void
7558 gtk_notebook_popup_disable  (GtkNotebook *notebook)
7559 {
7560   GtkNotebookPrivate *priv;
7561
7562   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7563
7564   priv = notebook->priv;
7565
7566   if (!priv->menu)
7567     return;
7568
7569   gtk_container_foreach (GTK_CONTAINER (priv->menu),
7570                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7571   gtk_widget_destroy (priv->menu);
7572
7573   g_object_notify (G_OBJECT (notebook), "enable-popup");
7574 }
7575
7576 /* Public GtkNotebook Page Properties Functions:
7577  *
7578  * gtk_notebook_get_tab_label
7579  * gtk_notebook_set_tab_label
7580  * gtk_notebook_set_tab_label_text
7581  * gtk_notebook_get_menu_label
7582  * gtk_notebook_set_menu_label
7583  * gtk_notebook_set_menu_label_text
7584  * gtk_notebook_get_tab_reorderable
7585  * gtk_notebook_set_tab_reorderable
7586  * gtk_notebook_get_tab_detachable
7587  * gtk_notebook_set_tab_detachable
7588  */
7589
7590 /**
7591  * gtk_notebook_get_tab_label:
7592  * @notebook: a #GtkNotebook
7593  * @child: the page
7594  *
7595  * Returns the tab label widget for the page @child.
7596  * %NULL is returned if @child is not in @notebook or
7597  * if no tab label has specifically been set for @child.
7598  *
7599  * Return value: (transfer none): the tab label
7600  */
7601 GtkWidget *
7602 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7603                             GtkWidget   *child)
7604 {
7605   GList *list;
7606
7607   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7608   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7609
7610   list = CHECK_FIND_CHILD (notebook, child);
7611   if (!list)
7612     return NULL;
7613
7614   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7615     return NULL;
7616
7617   return GTK_NOTEBOOK_PAGE (list)->tab_label;
7618 }
7619
7620 /**
7621  * gtk_notebook_set_tab_label:
7622  * @notebook: a #GtkNotebook
7623  * @child: the page
7624  * @tab_label: (allow-none): the tab label widget to use, or %NULL
7625  *     for default tab label
7626  *
7627  * Changes the tab label for @child.
7628  * If %NULL is specified for @tab_label, then the page will
7629  * have the label 'page N'.
7630  */
7631 void
7632 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7633                             GtkWidget   *child,
7634                             GtkWidget   *tab_label)
7635 {
7636   GtkNotebookPrivate *priv;
7637   GtkNotebookPage *page;
7638   GList *list;
7639
7640   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7641   g_return_if_fail (GTK_IS_WIDGET (child));
7642
7643   priv = notebook->priv;
7644
7645   list = CHECK_FIND_CHILD (notebook, child);
7646   if (!list)
7647     return;
7648
7649   /* a NULL pointer indicates a default_tab setting, otherwise
7650    * we need to set the associated label
7651    */
7652   page = list->data;
7653
7654   if (page->tab_label == tab_label)
7655     return;
7656
7657
7658   gtk_notebook_remove_tab_label (notebook, page);
7659
7660   if (tab_label)
7661     {
7662       page->default_tab = FALSE;
7663       page->tab_label = tab_label;
7664       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7665     }
7666   else
7667     {
7668       page->default_tab = TRUE;
7669       page->tab_label = NULL;
7670
7671       if (priv->show_tabs)
7672         {
7673           gchar string[32];
7674
7675           g_snprintf (string, sizeof(string), _("Page %u"),
7676                       g_list_position (priv->children, list));
7677           page->tab_label = gtk_label_new (string);
7678           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7679         }
7680     }
7681
7682   if (page->tab_label)
7683     page->mnemonic_activate_signal =
7684       g_signal_connect (page->tab_label,
7685                         "mnemonic-activate",
7686                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7687                         notebook);
7688
7689   if (priv->show_tabs && gtk_widget_get_visible (child))
7690     {
7691       gtk_widget_show (page->tab_label);
7692       gtk_widget_queue_resize (GTK_WIDGET (notebook));
7693     }
7694
7695   gtk_notebook_update_tab_states (notebook);
7696   gtk_widget_child_notify (child, "tab-label");
7697 }
7698
7699 /**
7700  * gtk_notebook_set_tab_label_text:
7701  * @notebook: a #GtkNotebook
7702  * @child: the page
7703  * @tab_text: the label text
7704  *
7705  * Creates a new label and sets it as the tab label for the page
7706  * containing @child.
7707  */
7708 void
7709 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7710                                  GtkWidget   *child,
7711                                  const gchar *tab_text)
7712 {
7713   GtkWidget *tab_label = NULL;
7714
7715   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7716
7717   if (tab_text)
7718     tab_label = gtk_label_new (tab_text);
7719   gtk_notebook_set_tab_label (notebook, child, tab_label);
7720   gtk_widget_child_notify (child, "tab-label");
7721 }
7722
7723 /**
7724  * gtk_notebook_get_tab_label_text:
7725  * @notebook: a #GtkNotebook
7726  * @child: a widget contained in a page of @notebook
7727  *
7728  * Retrieves the text of the tab label for the page containing
7729  * @child.
7730  *
7731  * Return value: the text of the tab label, or %NULL if the
7732  *     tab label widget is not a #GtkLabel. The string is owned
7733  *     by the widget and must not be freed.
7734  */
7735 const gchar *
7736 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7737                                  GtkWidget   *child)
7738 {
7739   GtkWidget *tab_label;
7740
7741   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7742   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7743
7744   tab_label = gtk_notebook_get_tab_label (notebook, child);
7745
7746   if (GTK_IS_LABEL (tab_label))
7747     return gtk_label_get_text (GTK_LABEL (tab_label));
7748   else
7749     return NULL;
7750 }
7751
7752 /**
7753  * gtk_notebook_get_menu_label:
7754  * @notebook: a #GtkNotebook
7755  * @child: a widget contained in a page of @notebook
7756  *
7757  * Retrieves the menu label widget of the page containing @child.
7758  *
7759  * Return value: (transfer none): the menu label, or %NULL if the
7760  *     notebook page does not have a menu label other than the
7761  *     default (the tab label).
7762  */
7763 GtkWidget*
7764 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7765                              GtkWidget   *child)
7766 {
7767   GList *list;
7768
7769   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7770   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7771
7772   list = CHECK_FIND_CHILD (notebook, child);
7773   if (!list)
7774     return NULL;
7775
7776   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7777     return NULL;
7778
7779   return GTK_NOTEBOOK_PAGE (list)->menu_label;
7780 }
7781
7782 /**
7783  * gtk_notebook_set_menu_label:
7784  * @notebook: a #GtkNotebook
7785  * @child: the child widget
7786  * @menu_label: (allow-none): the menu label, or %NULL for default
7787  *
7788  * Changes the menu label for the page containing @child.
7789  */
7790 void
7791 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7792                              GtkWidget   *child,
7793                              GtkWidget   *menu_label)
7794 {
7795   GtkNotebookPrivate *priv;
7796   GtkNotebookPage *page;
7797   GList *list;
7798
7799   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7800   g_return_if_fail (GTK_IS_WIDGET (child));
7801
7802   priv = notebook->priv;
7803
7804   list = CHECK_FIND_CHILD (notebook, child);
7805   if (!list)
7806     return;
7807
7808   page = list->data;
7809   if (page->menu_label)
7810     {
7811       if (priv->menu)
7812         gtk_container_remove (GTK_CONTAINER (priv->menu),
7813                               gtk_widget_get_parent (page->menu_label));
7814
7815       if (!page->default_menu)
7816         g_object_unref (page->menu_label);
7817     }
7818
7819   if (menu_label)
7820     {
7821       page->menu_label = menu_label;
7822       g_object_ref_sink (page->menu_label);
7823       page->default_menu = FALSE;
7824     }
7825   else
7826     page->default_menu = TRUE;
7827
7828   if (priv->menu)
7829     gtk_notebook_menu_item_create (notebook, list);
7830   gtk_widget_child_notify (child, "menu-label");
7831 }
7832
7833 /**
7834  * gtk_notebook_set_menu_label_text:
7835  * @notebook: a #GtkNotebook
7836  * @child: the child widget
7837  * @menu_text: the label text
7838  *
7839  * Creates a new label and sets it as the menu label of @child.
7840  */
7841 void
7842 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7843                                   GtkWidget   *child,
7844                                   const gchar *menu_text)
7845 {
7846   GtkWidget *menu_label = NULL;
7847
7848   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7849
7850   if (menu_text)
7851     {
7852       menu_label = gtk_label_new (menu_text);
7853       gtk_widget_set_halign (menu_label, GTK_ALIGN_START);
7854       gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER);
7855     }
7856   gtk_notebook_set_menu_label (notebook, child, menu_label);
7857   gtk_widget_child_notify (child, "menu-label");
7858 }
7859
7860 /**
7861  * gtk_notebook_get_menu_label_text:
7862  * @notebook: a #GtkNotebook
7863  * @child: the child widget of a page of the notebook.
7864  *
7865  * Retrieves the text of the menu label for the page containing
7866  * @child.
7867  *
7868  * Return value: the text of the tab label, or %NULL if the
7869  *     widget does not have a menu label other than the default
7870  *     menu label, or the menu label widget is not a #GtkLabel.
7871  *     The string is owned by the widget and must not be freed.
7872  */
7873 const gchar *
7874 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7875                                   GtkWidget *child)
7876 {
7877   GtkWidget *menu_label;
7878
7879   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7880   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7881
7882   menu_label = gtk_notebook_get_menu_label (notebook, child);
7883
7884   if (GTK_IS_LABEL (menu_label))
7885     return gtk_label_get_text (GTK_LABEL (menu_label));
7886   else
7887     return NULL;
7888 }
7889
7890 /* Helper function called when pages are reordered
7891  */
7892 static void
7893 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7894                               GtkNotebookPage *page)
7895 {
7896   GtkNotebookPrivate *priv = notebook->priv;
7897
7898   if (priv->menu)
7899     {
7900       GtkWidget *menu_item;
7901
7902       menu_item = gtk_widget_get_parent (page->menu_label);
7903       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7904       gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7905       gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7906     }
7907
7908   gtk_notebook_update_tab_states (notebook);
7909   gtk_notebook_update_labels (notebook);
7910 }
7911
7912 static void
7913 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7914                                     GtkWidget   *child,
7915                                     gboolean     expand,
7916                                     gboolean     fill)
7917 {
7918   GtkNotebookPrivate *priv;
7919   GtkNotebookPage *page;
7920   GList *list;
7921
7922   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7923   g_return_if_fail (GTK_IS_WIDGET (child));
7924
7925   priv = notebook->priv;
7926
7927   list = CHECK_FIND_CHILD (notebook, child);
7928   if (!list)
7929     return;
7930
7931   page = list->data;
7932   expand = expand != FALSE;
7933   fill = fill != FALSE;
7934   if (page->expand == expand && page->fill == fill)
7935     return;
7936
7937   gtk_widget_freeze_child_notify (child);
7938   page->expand = expand;
7939   gtk_widget_child_notify (child, "tab-expand");
7940   page->fill = fill;
7941   gtk_widget_child_notify (child, "tab-fill");
7942   gtk_widget_child_notify (child, "position");
7943   if (priv->show_tabs)
7944     gtk_widget_queue_resize (GTK_WIDGET (notebook));
7945   gtk_widget_thaw_child_notify (child);
7946 }
7947
7948 static void
7949 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7950                                       GtkWidget   *child,
7951                                       gboolean    *expand,
7952                                       gboolean    *fill)
7953 {
7954   GList *list;
7955
7956   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7957   g_return_if_fail (GTK_IS_WIDGET (child));
7958
7959   list = CHECK_FIND_CHILD (notebook, child);
7960   if (!list)
7961     return;
7962
7963   if (expand)
7964     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7965   if (fill)
7966     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7967 }
7968
7969 /**
7970  * gtk_notebook_reorder_child:
7971  * @notebook: a #GtkNotebook
7972  * @child: the child to move
7973  * @position: the new position, or -1 to move to the end
7974  *
7975  * Reorders the page containing @child, so that it appears in position
7976  * @position. If @position is greater than or equal to the number of
7977  * children in the list or negative, @child will be moved to the end
7978  * of the list.
7979  */
7980 void
7981 gtk_notebook_reorder_child (GtkNotebook *notebook,
7982                             GtkWidget   *child,
7983                             gint         position)
7984 {
7985   GtkNotebookPrivate *priv;
7986   GList *list, *new_list;
7987   GtkNotebookPage *page;
7988   gint old_pos;
7989   gint max_pos;
7990
7991   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7992   g_return_if_fail (GTK_IS_WIDGET (child));
7993
7994   priv = notebook->priv;
7995
7996   list = CHECK_FIND_CHILD (notebook, child);
7997   if (!list)
7998     return;
7999
8000   max_pos = g_list_length (priv->children) - 1;
8001   if (position < 0 || position > max_pos)
8002     position = max_pos;
8003
8004   old_pos = g_list_position (priv->children, list);
8005
8006   if (old_pos == position)
8007     return;
8008
8009   page = list->data;
8010   priv->children = g_list_delete_link (priv->children, list);
8011
8012   priv->children = g_list_insert (priv->children, page, position);
8013   new_list = g_list_nth (priv->children, position);
8014
8015   /* Fix up GList references in GtkNotebook structure */
8016   if (priv->first_tab == list)
8017     priv->first_tab = new_list;
8018   if (priv->focus_tab == list)
8019     priv->focus_tab = new_list;
8020
8021   gtk_widget_freeze_child_notify (child);
8022
8023   /* Move around the menu items if necessary */
8024   gtk_notebook_child_reordered (notebook, page);
8025   gtk_widget_child_notify (child, "position");
8026
8027   if (priv->show_tabs)
8028     gtk_notebook_pages_allocate (notebook);
8029
8030   gtk_widget_thaw_child_notify (child);
8031
8032   g_signal_emit (notebook,
8033                  notebook_signals[PAGE_REORDERED],
8034                  0,
8035                  child,
8036                  position);
8037 }
8038
8039 /**
8040  * gtk_notebook_set_group_name:
8041  * @notebook: a #GtkNotebook
8042  * @group_name: (allow-none): the name of the notebook group,
8043  *     or %NULL to unset it
8044  *
8045  * Sets a group name for @notebook.
8046  *
8047  * Notebooks with the same name will be able to exchange tabs
8048  * via drag and drop. A notebook with a %NULL group name will
8049  * not be able to exchange tabs with any other notebook.
8050  *
8051  * Since: 2.24
8052  */
8053 void
8054 gtk_notebook_set_group_name (GtkNotebook *notebook,
8055                              const gchar *group_name)
8056 {
8057   GtkNotebookPrivate *priv;
8058   GQuark group;
8059
8060   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8061
8062   priv = notebook->priv;
8063
8064   group = g_quark_from_string (group_name);
8065
8066   if (priv->group != group)
8067     {
8068       priv->group = group;
8069       g_object_notify (G_OBJECT (notebook), "group-name");
8070     }
8071 }
8072
8073 /**
8074  * gtk_notebook_get_group_name:
8075  * @notebook: a #GtkNotebook
8076  *
8077  * Gets the current group name for @notebook.
8078  *
8079  * Return Value: (transfer none): the group name,
8080  *     or %NULL if none is set.
8081  *
8082  * Since: 2.24
8083  */
8084 const gchar *
8085 gtk_notebook_get_group_name (GtkNotebook *notebook)
8086 {
8087   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8088
8089   return g_quark_to_string (notebook->priv->group);
8090 }
8091
8092 /**
8093  * gtk_notebook_get_tab_reorderable:
8094  * @notebook: a #GtkNotebook
8095  * @child: a child #GtkWidget
8096  *
8097  * Gets whether the tab can be reordered via drag and drop or not.
8098  *
8099  * Return Value: %TRUE if the tab is reorderable.
8100  *
8101  * Since: 2.10
8102  */
8103 gboolean
8104 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
8105                                   GtkWidget   *child)
8106 {
8107   GList *list;
8108
8109   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8110   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8111
8112   list = CHECK_FIND_CHILD (notebook, child);
8113   if (!list)
8114     return FALSE;
8115
8116   return GTK_NOTEBOOK_PAGE (list)->reorderable;
8117 }
8118
8119 /**
8120  * gtk_notebook_set_tab_reorderable:
8121  * @notebook: a #GtkNotebook
8122  * @child: a child #GtkWidget
8123  * @reorderable: whether the tab is reorderable or not
8124  *
8125  * Sets whether the notebook tab can be reordered
8126  * via drag and drop or not.
8127  *
8128  * Since: 2.10
8129  */
8130 void
8131 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
8132                                   GtkWidget   *child,
8133                                   gboolean     reorderable)
8134 {
8135   GList *list;
8136
8137   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8138   g_return_if_fail (GTK_IS_WIDGET (child));
8139
8140   list = CHECK_FIND_CHILD (notebook, child);
8141   if (!list)
8142     return;
8143
8144   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
8145     {
8146       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
8147       gtk_widget_child_notify (child, "reorderable");
8148     }
8149 }
8150
8151 /**
8152  * gtk_notebook_get_tab_detachable:
8153  * @notebook: a #GtkNotebook
8154  * @child: a child #GtkWidget
8155  *
8156  * Returns whether the tab contents can be detached from @notebook.
8157  *
8158  * Return Value: %TRUE if the tab is detachable.
8159  *
8160  * Since: 2.10
8161  */
8162 gboolean
8163 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8164                                  GtkWidget   *child)
8165 {
8166   GList *list;
8167
8168   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8169   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8170
8171   list = CHECK_FIND_CHILD (notebook, child);
8172   if (!list)
8173     return FALSE;
8174
8175   return GTK_NOTEBOOK_PAGE (list)->detachable;
8176 }
8177
8178 /**
8179  * gtk_notebook_set_tab_detachable:
8180  * @notebook: a #GtkNotebook
8181  * @child: a child #GtkWidget
8182  * @detachable: whether the tab is detachable or not
8183  *
8184  * Sets whether the tab can be detached from @notebook to another
8185  * notebook or widget.
8186  *
8187  * Note that 2 notebooks must share a common group identificator
8188  * (see gtk_notebook_set_group_name()) to allow automatic tabs
8189  * interchange between them.
8190  *
8191  * If you want a widget to interact with a notebook through DnD
8192  * (i.e.: accept dragged tabs from it) it must be set as a drop
8193  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8194  * will fill the selection with a GtkWidget** pointing to the child
8195  * widget that corresponds to the dropped tab.
8196  * |[
8197  *  static void
8198  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
8199  *                                   GdkDragContext   *context,
8200  *                                   gint              x,
8201  *                                   gint              y,
8202  *                                   GtkSelectionData *selection_data,
8203  *                                   guint             info,
8204  *                                   guint             time,
8205  *                                   gpointer          user_data)
8206  *  {
8207  *    GtkWidget *notebook;
8208  *    GtkWidget **child;
8209  *
8210  *    notebook = gtk_drag_get_source_widget (context);
8211  *    child = (void*) gtk_selection_data_get_data (selection_data);
8212  *
8213  *    process_widget (*child);
8214  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
8215  *  }
8216  * ]|
8217  *
8218  * If you want a notebook to accept drags from other widgets,
8219  * you will have to set your own DnD code to do it.
8220  *
8221  * Since: 2.10
8222  */
8223 void
8224 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8225                                  GtkWidget  *child,
8226                                  gboolean    detachable)
8227 {
8228   GList *list;
8229
8230   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8231   g_return_if_fail (GTK_IS_WIDGET (child));
8232
8233   list = CHECK_FIND_CHILD (notebook, child);
8234   if (!list)
8235     return;
8236
8237   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8238     {
8239       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8240       gtk_widget_child_notify (child, "detachable");
8241     }
8242 }
8243
8244 /**
8245  * gtk_notebook_get_action_widget:
8246  * @notebook: a #GtkNotebook
8247  * @pack_type: pack type of the action widget to receive
8248  *
8249  * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8250  *
8251  * Returns: (transfer none): The action widget with the given @pack_type
8252  *     or %NULL when this action widget has not been set
8253  *
8254  * Since: 2.20
8255  */
8256 GtkWidget*
8257 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8258                                 GtkPackType  pack_type)
8259 {
8260   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8261
8262   return notebook->priv->action_widget[pack_type];
8263 }
8264
8265 /**
8266  * gtk_notebook_set_action_widget:
8267  * @notebook: a #GtkNotebook
8268  * @widget: a #GtkWidget
8269  * @pack_type: pack type of the action widget
8270  *
8271  * Sets @widget as one of the action widgets. Depending on the pack type
8272  * the widget will be placed before or after the tabs. You can use
8273  * a #GtkBox if you need to pack more than one widget on the same side.
8274  *
8275  * Note that action widgets are "internal" children of the notebook and thus
8276  * not included in the list returned from gtk_container_foreach().
8277  *
8278  * Since: 2.20
8279  */
8280 void
8281 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8282                                 GtkWidget   *widget,
8283                                 GtkPackType  pack_type)
8284 {
8285   GtkNotebookPrivate *priv;
8286
8287   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8288   g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8289   g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8290
8291   priv = notebook->priv;
8292
8293   if (priv->action_widget[pack_type])
8294     gtk_widget_unparent (priv->action_widget[pack_type]);
8295
8296   priv->action_widget[pack_type] = widget;
8297
8298   if (widget)
8299     {
8300       gtk_widget_set_child_visible (widget, priv->show_tabs);
8301       gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8302     }
8303
8304   gtk_widget_queue_resize (GTK_WIDGET (notebook));
8305 }