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