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