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