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