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