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