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