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