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