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