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