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