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