]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
2c6a507a4c55daab6640bf7869a77c695a75c087
[~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_redraw_tabs (GTK_NOTEBOOK (widget));
3098   
3099   return FALSE;
3100 }
3101
3102 static gint
3103 gtk_notebook_focus_out (GtkWidget     *widget,
3104                         GdkEventFocus *event)
3105 {
3106   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3107
3108   return FALSE;
3109 }
3110
3111 static void
3112 gtk_notebook_draw_focus (GtkWidget      *widget,
3113                          GdkEventExpose *event)
3114 {
3115   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3116
3117   if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3118       notebook->show_tabs && notebook->cur_page &&
3119       notebook->cur_page->tab_label->window == event->window)
3120     {
3121       GtkNotebookPage *page;
3122
3123       page = notebook->cur_page;
3124
3125       if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3126         {
3127           GdkRectangle area;
3128           gint focus_width;
3129
3130           gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3131
3132           area.x = page->tab_label->allocation.x - focus_width;
3133           area.y = page->tab_label->allocation.y - focus_width;
3134           area.width = page->tab_label->allocation.width + 2 * focus_width;
3135           area.height = page->tab_label->allocation.height + 2 * focus_width;
3136
3137           gtk_paint_focus (widget->style, event->window, 
3138                            GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3139                            area.x, area.y, area.width, area.height);
3140         }
3141     }
3142 }
3143
3144 static void
3145 gtk_notebook_style_set  (GtkWidget *widget,
3146                          GtkStyle  *previous)
3147 {
3148   GtkNotebook *notebook;
3149
3150   gboolean has_before_previous;
3151   gboolean has_before_next;
3152   gboolean has_after_previous;
3153   gboolean has_after_next;
3154
3155   notebook = GTK_NOTEBOOK (widget);
3156   
3157   gtk_widget_style_get (widget,
3158                         "has-backward-stepper", &has_before_previous,
3159                         "has-secondary-forward-stepper", &has_before_next,
3160                         "has-secondary-backward-stepper", &has_after_previous,
3161                         "has-forward-stepper", &has_after_next,
3162                         NULL);
3163   
3164   notebook->has_before_previous = has_before_previous;
3165   notebook->has_before_next = has_before_next;
3166   notebook->has_after_previous = has_after_previous;
3167   notebook->has_after_next = has_after_next;
3168
3169   GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3170 }
3171
3172 static gboolean
3173 on_drag_icon_expose (GtkWidget      *widget,
3174                      GdkEventExpose *event,
3175                      gpointer        data)
3176 {
3177   GtkWidget *notebook, *child = GTK_WIDGET (data);
3178   GtkRequisition requisition;
3179   gint gap_pos;
3180
3181   notebook = GTK_WIDGET (data);
3182   child = GTK_BIN (widget)->child;
3183   gtk_widget_size_request (widget, &requisition);
3184   gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3185
3186   gtk_paint_extension (notebook->style, widget->window,
3187                        GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3188                        NULL, widget, "tab",
3189                        0, 0,
3190                        requisition.width, requisition.height,
3191                        gap_pos);
3192   if (child)
3193     gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3194
3195   return TRUE;
3196 }
3197
3198 static void
3199 gtk_notebook_drag_begin (GtkWidget        *widget,
3200                          GdkDragContext   *context)
3201 {
3202   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3203   GtkNotebook *notebook = (GtkNotebook*) widget;
3204   GtkWidget *tab_label;
3205
3206   if (priv->dnd_timer)
3207     {
3208       g_source_remove (priv->dnd_timer);
3209       priv->dnd_timer = 0;
3210     }
3211
3212   priv->operation = DRAG_OPERATION_DETACH;
3213   gtk_notebook_pages_allocate (notebook);
3214
3215   tab_label = priv->detached_tab->tab_label;
3216
3217   hide_drag_window (notebook, priv, notebook->cur_page);
3218   g_object_ref (tab_label);
3219   gtk_widget_unparent (tab_label);
3220
3221   priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3222   gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3223                          gtk_widget_get_screen (widget));
3224   gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3225   gtk_widget_set_size_request (priv->dnd_window,
3226                                priv->detached_tab->allocation.width,
3227                                priv->detached_tab->allocation.height);
3228   g_object_unref (tab_label);
3229
3230   g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3231                     G_CALLBACK (on_drag_icon_expose), notebook);
3232
3233   gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3234 }
3235
3236 static void
3237 gtk_notebook_drag_end (GtkWidget      *widget,
3238                        GdkDragContext *context)
3239 {
3240   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3241
3242   gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3243
3244   if (priv->detached_tab)
3245     gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3246
3247   GTK_BIN (priv->dnd_window)->child = NULL;
3248   gtk_widget_destroy (priv->dnd_window);
3249   priv->dnd_window = NULL;
3250
3251   priv->operation = DRAG_OPERATION_NONE;
3252 }
3253
3254 static GtkNotebook *
3255 gtk_notebook_create_window (GtkNotebook *notebook,
3256                             GtkWidget   *page,
3257                             gint         x,
3258                             gint         y)
3259 {
3260   if (window_creation_hook)
3261     return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3262
3263   return NULL;
3264 }
3265
3266 static gboolean
3267 gtk_notebook_drag_failed (GtkWidget      *widget,
3268                           GdkDragContext *context,
3269                           GtkDragResult   result,
3270                           gpointer        data)
3271 {
3272   if (result == GTK_DRAG_RESULT_NO_TARGET)
3273     {
3274       GtkNotebookPrivate *priv;
3275       GtkNotebook *notebook, *dest_notebook = NULL;
3276       GdkDisplay *display;
3277       gint x, y;
3278
3279       notebook = GTK_NOTEBOOK (widget);
3280       priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3281
3282       display = gtk_widget_get_display (widget);
3283       gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3284
3285       g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3286                      priv->detached_tab->child, x, y, &dest_notebook);
3287
3288       if (dest_notebook)
3289         do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3290
3291       return TRUE;
3292     }
3293
3294   return FALSE;
3295 }
3296
3297 static gboolean
3298 gtk_notebook_switch_tab_timeout (gpointer data)
3299 {
3300   GtkNotebook *notebook;
3301   GtkNotebookPrivate *priv;
3302   GList *tab;
3303   gint x, y;
3304
3305   notebook = GTK_NOTEBOOK (data);
3306   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3307
3308   priv->switch_tab_timer = 0;
3309   x = priv->mouse_x;
3310   y = priv->mouse_y;
3311
3312   if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3313     {
3314       /* FIXME: hack, we don't want the
3315        * focus to move fom the source widget
3316        */
3317       notebook->child_has_focus = FALSE;
3318       gtk_notebook_switch_focus_tab (notebook, tab);
3319     }
3320
3321   return FALSE;
3322 }
3323
3324 static gboolean
3325 gtk_notebook_drag_motion (GtkWidget      *widget,
3326                           GdkDragContext *context,
3327                           gint            x,
3328                           gint            y,
3329                           guint           time)
3330 {
3331   GtkNotebook *notebook;
3332   GtkNotebookPrivate *priv;
3333   GdkRectangle position;
3334   GtkSettings *settings;
3335   GtkNotebookArrow arrow;
3336   guint timeout;
3337   GdkAtom target, tab_target;
3338
3339   notebook = GTK_NOTEBOOK (widget);
3340   arrow = gtk_notebook_get_arrow (notebook,
3341                                   x + widget->allocation.x,
3342                                   y + widget->allocation.y);
3343   if (arrow)
3344     {
3345       notebook->click_child = arrow;
3346       gtk_notebook_set_scroll_timer (notebook);
3347       gdk_drag_status (context, 0, time);
3348       return TRUE;
3349     }
3350
3351   stop_scrolling (notebook);
3352   target = gtk_drag_dest_find_target (widget, context, NULL);
3353   tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3354
3355   if (target == tab_target)
3356     {
3357       gpointer widget_group, source_widget_group;
3358       GtkWidget *source_widget;
3359
3360       source_widget = gtk_drag_get_source_widget (context);
3361       g_assert (source_widget);
3362
3363       widget_group = gtk_notebook_get_group (notebook);
3364       source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3365
3366       if (widget_group && source_widget_group &&
3367           widget_group == source_widget_group &&
3368           !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child || 
3369             gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3370         {
3371           gdk_drag_status (context, GDK_ACTION_MOVE, time);
3372           return TRUE;
3373         }
3374       else
3375         {
3376           /* it's a tab, but doesn't share
3377            * ID with this notebook */
3378           gdk_drag_status (context, 0, time);
3379         }
3380     }
3381
3382   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3383   x += widget->allocation.x;
3384   y += widget->allocation.y;
3385
3386   if (gtk_notebook_get_event_window_position (notebook, &position) &&
3387       x >= position.x && x <= position.x + position.width &&
3388       y >= position.y && y <= position.y + position.height)
3389     {
3390       priv->mouse_x = x;
3391       priv->mouse_y = y;
3392
3393       if (!priv->switch_tab_timer)
3394         {
3395           settings = gtk_widget_get_settings (widget);
3396
3397           g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3398           priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3399                                                   gtk_notebook_switch_tab_timeout,
3400                                                   widget);
3401         }
3402     }
3403   else
3404     {
3405       if (priv->switch_tab_timer)
3406         {
3407           g_source_remove (priv->switch_tab_timer);
3408           priv->switch_tab_timer = 0;
3409         }
3410     }
3411
3412   return (target == tab_target) ? TRUE : FALSE;
3413 }
3414
3415 static void
3416 gtk_notebook_drag_leave (GtkWidget      *widget,
3417                          GdkDragContext *context,
3418                          guint           time)
3419 {
3420   GtkNotebookPrivate *priv;
3421
3422   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3423
3424   if (priv->switch_tab_timer)
3425     {
3426       g_source_remove (priv->switch_tab_timer);
3427       priv->switch_tab_timer = 0;
3428     }
3429
3430   stop_scrolling (GTK_NOTEBOOK (widget));
3431 }
3432
3433 static gboolean
3434 gtk_notebook_drag_drop (GtkWidget        *widget,
3435                         GdkDragContext   *context,
3436                         gint              x,
3437                         gint              y,
3438                         guint             time)
3439 {
3440   GdkAtom target, tab_target;
3441
3442   target = gtk_drag_dest_find_target (widget, context, NULL);
3443   tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3444
3445   if (target == tab_target)
3446     {
3447       gtk_drag_get_data (widget, context, target, time);
3448       return TRUE;
3449     }
3450
3451   return FALSE;
3452 }
3453
3454 static void
3455 do_detach_tab (GtkNotebook     *from,
3456                GtkNotebook     *to,
3457                GtkWidget       *child,
3458                gint             x,
3459                gint             y)
3460 {
3461   GtkNotebookPrivate *priv;
3462   GtkWidget *tab_label, *menu_label;
3463   gboolean tab_expand, tab_fill, reorderable, detachable;
3464   GList *element;
3465   guint tab_pack;
3466   gint page_num;
3467
3468   menu_label = gtk_notebook_get_menu_label (from, child);
3469
3470   if (menu_label)
3471     g_object_ref (menu_label);
3472
3473   tab_label = gtk_notebook_get_tab_label (from, child);
3474   
3475   if (tab_label)
3476     g_object_ref (tab_label);
3477
3478   g_object_ref (child);
3479
3480   gtk_container_child_get (GTK_CONTAINER (from),
3481                            child,
3482                            "tab-expand", &tab_expand,
3483                            "tab-fill", &tab_fill,
3484                            "tab-pack", &tab_pack,
3485                            "reorderable", &reorderable,
3486                            "detachable", &detachable,
3487                            NULL);
3488
3489   gtk_container_remove (GTK_CONTAINER (from), child);
3490
3491   priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3492   priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3493   priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3494
3495   element = get_drop_position (to, tab_pack);
3496   page_num = g_list_position (to->children, element);
3497   gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3498
3499   gtk_container_child_set (GTK_CONTAINER (to), child,
3500                            "tab-pack", tab_pack,
3501                            "tab-expand", tab_expand,
3502                            "tab-fill", tab_fill,
3503                            "reorderable", reorderable,
3504                            "detachable", detachable,
3505                            NULL);
3506   if (child)
3507     g_object_unref (child);
3508
3509   if (tab_label)
3510     g_object_unref (tab_label);
3511
3512   if (menu_label)
3513     g_object_unref (menu_label);
3514
3515   gtk_notebook_set_current_page (to, page_num);
3516 }
3517
3518 static void
3519 gtk_notebook_drag_data_get (GtkWidget        *widget,
3520                             GdkDragContext   *context,
3521                             GtkSelectionData *data,
3522                             guint             info,
3523                             guint             time)
3524 {
3525   GtkNotebookPrivate *priv;
3526
3527   if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3528     {
3529       priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3530
3531       gtk_selection_data_set (data,
3532                               data->target,
3533                               8,
3534                               (void*) &priv->detached_tab->child,
3535                               sizeof (gpointer));
3536     }
3537 }
3538
3539 static void
3540 gtk_notebook_drag_data_received (GtkWidget        *widget,
3541                                  GdkDragContext   *context,
3542                                  gint              x,
3543                                  gint              y,
3544                                  GtkSelectionData *data,
3545                                  guint             info,
3546                                  guint             time)
3547 {
3548   GtkNotebook *notebook;
3549   GtkWidget *source_widget;
3550   GtkWidget **child;
3551
3552   notebook = GTK_NOTEBOOK (widget);
3553   source_widget = gtk_drag_get_source_widget (context);
3554
3555   if (source_widget &&
3556       data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3557     {
3558       child = (void*) data->data;
3559
3560       do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3561       gtk_drag_finish (context, TRUE, FALSE, time);
3562     }
3563   else
3564     gtk_drag_finish (context, FALSE, FALSE, time);
3565 }
3566
3567 /* Private GtkContainer Methods :
3568  * 
3569  * gtk_notebook_set_child_arg
3570  * gtk_notebook_get_child_arg
3571  * gtk_notebook_add
3572  * gtk_notebook_remove
3573  * gtk_notebook_focus
3574  * gtk_notebook_set_focus_child
3575  * gtk_notebook_child_type
3576  * gtk_notebook_forall
3577  */
3578 static void
3579 gtk_notebook_set_child_property (GtkContainer    *container,
3580                                  GtkWidget       *child,
3581                                  guint            property_id,
3582                                  const GValue    *value,
3583                                  GParamSpec      *pspec)
3584 {
3585   gboolean expand;
3586   gboolean fill;
3587   GtkPackType pack_type;
3588
3589   /* not finding child's page is valid for menus or labels */
3590   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3591     return;
3592
3593   switch (property_id)
3594     {
3595     case CHILD_PROP_TAB_LABEL:
3596       /* a NULL pointer indicates a default_tab setting, otherwise
3597        * we need to set the associated label
3598        */
3599       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3600                                        g_value_get_string (value));
3601       break;
3602     case CHILD_PROP_MENU_LABEL:
3603       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3604                                         g_value_get_string (value));
3605       break;
3606     case CHILD_PROP_POSITION:
3607       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3608                                   g_value_get_int (value));
3609       break;
3610     case CHILD_PROP_TAB_EXPAND:
3611       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3612                                             &expand, &fill, &pack_type);
3613       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3614                                           g_value_get_boolean (value),
3615                                           fill, pack_type);
3616       break;
3617     case CHILD_PROP_TAB_FILL:
3618       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3619                                             &expand, &fill, &pack_type);
3620       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3621                                           expand,
3622                                           g_value_get_boolean (value),
3623                                           pack_type);
3624       break;
3625     case CHILD_PROP_TAB_PACK:
3626       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3627                                             &expand, &fill, &pack_type);
3628       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3629                                           expand, fill,
3630                                           g_value_get_enum (value));
3631       break;
3632     case CHILD_PROP_REORDERABLE:
3633       gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3634                                         g_value_get_boolean (value));
3635       break;
3636     case CHILD_PROP_DETACHABLE:
3637       gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3638                                        g_value_get_boolean (value));
3639       break;
3640     default:
3641       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3642       break;
3643     }
3644 }
3645
3646 static void
3647 gtk_notebook_get_child_property (GtkContainer    *container,
3648                                  GtkWidget       *child,
3649                                  guint            property_id,
3650                                  GValue          *value,
3651                                  GParamSpec      *pspec)
3652 {
3653   GList *list;
3654   GtkNotebook *notebook;
3655   GtkWidget *label;
3656   gboolean expand;
3657   gboolean fill;
3658   GtkPackType pack_type;
3659
3660   notebook = GTK_NOTEBOOK (container);
3661
3662   /* not finding child's page is valid for menus or labels */
3663   list = gtk_notebook_find_child (notebook, child, NULL);
3664   if (!list)
3665     {
3666       /* nothing to set on labels or menus */
3667       g_param_value_set_default (pspec, value);
3668       return;
3669     }
3670
3671   switch (property_id)
3672     {
3673     case CHILD_PROP_TAB_LABEL:
3674       label = gtk_notebook_get_tab_label (notebook, child);
3675
3676       if (GTK_IS_LABEL (label))
3677         g_value_set_string (value, GTK_LABEL (label)->label);
3678       else
3679         g_value_set_string (value, NULL);
3680       break;
3681     case CHILD_PROP_MENU_LABEL:
3682       label = gtk_notebook_get_menu_label (notebook, child);
3683
3684       if (GTK_IS_LABEL (label))
3685         g_value_set_string (value, GTK_LABEL (label)->label);
3686       else
3687         g_value_set_string (value, NULL);
3688       break;
3689     case CHILD_PROP_POSITION:
3690       g_value_set_int (value, g_list_position (notebook->children, list));
3691       break;
3692     case CHILD_PROP_TAB_EXPAND:
3693         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3694                                               &expand, NULL, NULL);
3695         g_value_set_boolean (value, expand);
3696       break;
3697     case CHILD_PROP_TAB_FILL:
3698         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3699                                               NULL, &fill, NULL);
3700         g_value_set_boolean (value, fill);
3701       break;
3702     case CHILD_PROP_TAB_PACK:
3703         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3704                                               NULL, NULL, &pack_type);
3705         g_value_set_enum (value, pack_type);
3706       break;
3707     case CHILD_PROP_REORDERABLE:
3708       g_value_set_boolean (value,
3709                            gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3710       break;
3711     case CHILD_PROP_DETACHABLE:
3712       g_value_set_boolean (value,
3713                            gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3714       break;
3715     default:
3716       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3717       break;
3718     }
3719 }
3720
3721 static void
3722 gtk_notebook_add (GtkContainer *container,
3723                   GtkWidget    *widget)
3724 {
3725   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
3726                                  NULL, NULL, -1);
3727 }
3728
3729 static void
3730 gtk_notebook_remove (GtkContainer *container,
3731                      GtkWidget    *widget)
3732 {
3733   GtkNotebook *notebook;
3734   GtkNotebookPage *page;
3735   GList *children;
3736   gint page_num = 0;
3737
3738   notebook = GTK_NOTEBOOK (container);
3739
3740   children = notebook->children;
3741   while (children)
3742     {
3743       page = children->data;
3744
3745       if (page->child == widget)
3746         break;
3747
3748       page_num++;
3749       children = children->next;
3750     }
3751  
3752   if (children == NULL)
3753     return;
3754   
3755   g_object_ref (widget);
3756
3757   gtk_notebook_real_remove (notebook, children);
3758
3759   g_signal_emit (notebook,
3760                  notebook_signals[PAGE_REMOVED],
3761                  0,
3762                  widget,
3763                  page_num);
3764   
3765   g_object_unref (widget);
3766 }
3767
3768 static gboolean
3769 focus_tabs_in (GtkNotebook *notebook)
3770 {
3771   if (notebook->show_tabs && notebook->cur_page)
3772     {
3773       gtk_widget_grab_focus (GTK_WIDGET (notebook));
3774
3775       gtk_notebook_switch_focus_tab (notebook,
3776                                      g_list_find (notebook->children,
3777                                                   notebook->cur_page));
3778
3779       return TRUE;
3780     }
3781   else
3782     return FALSE;
3783 }
3784
3785 static gboolean
3786 focus_tabs_move (GtkNotebook     *notebook,
3787                  GtkDirectionType direction,
3788                  gint             search_direction)
3789 {
3790   GList *new_page;
3791
3792   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3793                                        search_direction, TRUE);
3794   if (!new_page)
3795     {
3796       gboolean wrap_around;
3797
3798       g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3799                     "gtk-keynav-wrap-around", &wrap_around,
3800                     NULL);
3801
3802       if (wrap_around)
3803         new_page = gtk_notebook_search_page (notebook, NULL,
3804                                              search_direction, TRUE);
3805     }
3806
3807   if (new_page)
3808     gtk_notebook_switch_focus_tab (notebook, new_page);
3809   else
3810     gtk_widget_error_bell (GTK_WIDGET (notebook));
3811
3812   return TRUE;
3813 }
3814
3815 static gboolean
3816 focus_child_in (GtkNotebook     *notebook,
3817                 GtkDirectionType direction)
3818 {
3819   if (notebook->cur_page)
3820     return gtk_widget_child_focus (notebook->cur_page->child, direction);
3821   else
3822     return FALSE;
3823 }
3824
3825 /* Focus in the notebook can either be on the pages, or on
3826  * the tabs.
3827  */
3828 static gint
3829 gtk_notebook_focus (GtkWidget        *widget,
3830                     GtkDirectionType  direction)
3831 {
3832   GtkWidget *old_focus_child;
3833   GtkNotebook *notebook;
3834   GtkDirectionType effective_direction;
3835
3836   gboolean widget_is_focus;
3837   GtkContainer *container;
3838
3839   container = GTK_CONTAINER (widget);
3840   notebook = GTK_NOTEBOOK (container);
3841
3842   if (notebook->focus_out)
3843     {
3844       notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3845       return FALSE;
3846     }
3847
3848   widget_is_focus = gtk_widget_is_focus (widget);
3849   old_focus_child = container->focus_child; 
3850
3851   effective_direction = get_effective_direction (notebook, direction);
3852
3853   if (old_focus_child)          /* Focus on page child */
3854     {
3855       if (gtk_widget_child_focus (old_focus_child, direction))
3856         return TRUE;
3857       
3858       switch (effective_direction)
3859         {
3860         case GTK_DIR_TAB_BACKWARD:
3861         case GTK_DIR_UP:
3862           /* Focus onto the tabs */
3863           return focus_tabs_in (notebook);
3864         case GTK_DIR_DOWN:
3865         case GTK_DIR_TAB_FORWARD:
3866         case GTK_DIR_LEFT:
3867         case GTK_DIR_RIGHT:
3868           return FALSE;
3869         }
3870     }
3871   else if (widget_is_focus)     /* Focus was on tabs */
3872     {
3873       switch (effective_direction)
3874         {
3875         case GTK_DIR_TAB_BACKWARD:
3876         case GTK_DIR_UP:
3877           return FALSE;
3878         case GTK_DIR_TAB_FORWARD:
3879         case GTK_DIR_DOWN:
3880           /* We use TAB_FORWARD rather than direction so that we focus a more
3881            * predictable widget for the user; users may be using arrow focusing
3882            * in this situation even if they don't usually use arrow focusing.
3883            */
3884           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3885         case GTK_DIR_LEFT:
3886           return focus_tabs_move (notebook, direction, STEP_PREV);
3887         case GTK_DIR_RIGHT:
3888           return focus_tabs_move (notebook, direction, STEP_NEXT);
3889         }
3890     }
3891   else /* Focus was not on widget */
3892     {
3893       switch (effective_direction)
3894         {
3895         case GTK_DIR_TAB_FORWARD:
3896         case GTK_DIR_DOWN:
3897           if (focus_tabs_in (notebook))
3898             return TRUE;
3899           if (focus_child_in (notebook, direction))
3900             return TRUE;
3901           return FALSE;
3902         case GTK_DIR_TAB_BACKWARD:
3903         case GTK_DIR_UP:
3904           if (focus_child_in (notebook, direction))
3905             return TRUE;
3906           if (focus_tabs_in (notebook))
3907             return TRUE;
3908           return FALSE;
3909         case GTK_DIR_LEFT:
3910         case GTK_DIR_RIGHT:
3911           return focus_child_in (notebook, direction);
3912         }
3913     }
3914
3915   g_assert_not_reached ();
3916   return FALSE;
3917 }  
3918
3919 static void
3920 gtk_notebook_set_focus_child (GtkContainer *container,
3921                               GtkWidget    *child)
3922 {
3923   GtkNotebook *notebook = GTK_NOTEBOOK (container);
3924   GtkWidget *page_child;
3925   GtkWidget *toplevel;
3926
3927   /* If the old focus widget was within a page of the notebook,
3928    * (child may either be NULL or not in this case), record it
3929    * for future use if we switch to the page with a mnemonic.
3930    */
3931
3932   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3933   if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3934     {
3935       page_child = GTK_WINDOW (toplevel)->focus_widget; 
3936       while (page_child)
3937         {
3938           if (page_child->parent == GTK_WIDGET (container))
3939             {
3940               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3941               if (list != NULL) 
3942                 {
3943                   GtkNotebookPage *page = list->data;
3944               
3945                   if (page->last_focus_child)
3946                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3947                   
3948                   page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3949                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3950               
3951                   break;
3952                 }
3953             }
3954
3955           page_child = page_child->parent;
3956         }
3957     }
3958   
3959   if (child)
3960     {
3961       g_return_if_fail (GTK_IS_WIDGET (child));
3962
3963       notebook->child_has_focus = TRUE;
3964       if (!notebook->focus_tab)
3965         {
3966           GList *children;
3967           GtkNotebookPage *page;
3968
3969           children = notebook->children;
3970           while (children)
3971             {
3972               page = children->data;
3973               if (page->child == child || page->tab_label == child)
3974                 gtk_notebook_switch_focus_tab (notebook, children);
3975               children = children->next;
3976             }
3977         }
3978     }
3979   else
3980     notebook->child_has_focus = FALSE;
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   gboolean child_has_focus;
5803
5804   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5805     return;
5806
5807   /* save the value here, changing visibility changes focus */
5808   child_has_focus = notebook->child_has_focus;
5809
5810   if (notebook->cur_page)
5811     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5812
5813   notebook->cur_page = page;
5814
5815   if (!notebook->focus_tab ||
5816       notebook->focus_tab->data != (gpointer) notebook->cur_page)
5817     notebook->focus_tab = 
5818       g_list_find (notebook->children, notebook->cur_page);
5819
5820   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5821
5822   /* If the focus was on the previous page, move it to the first
5823    * element on the new page, if possible, or if not, to the
5824    * notebook itself.
5825    */
5826   if (child_has_focus)
5827     {
5828       if (notebook->cur_page->last_focus_child &&
5829           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5830         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5831       else
5832         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5833           gtk_widget_grab_focus (GTK_WIDGET (notebook));
5834     }
5835   
5836   gtk_notebook_update_tab_states (notebook);
5837   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5838   g_object_notify (G_OBJECT (notebook), "page");
5839 }
5840
5841 /* Private GtkNotebook Page Switch Functions:
5842  *
5843  * gtk_notebook_switch_page
5844  * gtk_notebook_page_select
5845  * gtk_notebook_switch_focus_tab
5846  * gtk_notebook_menu_switch_page
5847  */
5848 static void
5849 gtk_notebook_switch_page (GtkNotebook     *notebook,
5850                           GtkNotebookPage *page)
5851
5852   guint page_num;
5853
5854   if (notebook->cur_page == page)
5855     return;
5856
5857   page_num = g_list_index (notebook->children, page);
5858
5859   g_signal_emit (notebook,
5860                  notebook_signals[SWITCH_PAGE],
5861                  0,
5862                  page,
5863                  page_num);
5864 }
5865
5866 static gint
5867 gtk_notebook_page_select (GtkNotebook *notebook,
5868                           gboolean     move_focus)
5869 {
5870   GtkNotebookPage *page;
5871   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5872   gint tab_pos = get_effective_tab_pos (notebook);
5873
5874   if (!notebook->focus_tab)
5875     return FALSE;
5876
5877   page = notebook->focus_tab->data;
5878   gtk_notebook_switch_page (notebook, page);
5879
5880   if (move_focus)
5881     {
5882       switch (tab_pos)
5883         {
5884         case GTK_POS_TOP:
5885           dir = GTK_DIR_DOWN;
5886           break;
5887         case GTK_POS_BOTTOM:
5888           dir = GTK_DIR_UP;
5889           break;
5890         case GTK_POS_LEFT:
5891           dir = GTK_DIR_RIGHT;
5892           break;
5893         case GTK_POS_RIGHT:
5894           dir = GTK_DIR_LEFT;
5895           break;
5896         }
5897
5898       if (gtk_widget_child_focus (page->child, dir))
5899         return TRUE;
5900     }
5901   return FALSE;
5902 }
5903
5904 static void
5905 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
5906                                GList       *new_child)
5907 {
5908   GList *old_child;
5909   GtkNotebookPage *page;
5910
5911   if (notebook->focus_tab == new_child)
5912     return;
5913
5914   old_child = notebook->focus_tab;
5915   notebook->focus_tab = new_child;
5916
5917   if (notebook->scrollable)
5918     gtk_notebook_redraw_arrows (notebook);
5919
5920   if (!notebook->show_tabs || !notebook->focus_tab)
5921     return;
5922
5923   page = notebook->focus_tab->data;
5924   if (GTK_WIDGET_MAPPED (page->tab_label))
5925     gtk_notebook_redraw_tabs (notebook);
5926   else
5927     gtk_notebook_pages_allocate (notebook);
5928
5929   gtk_notebook_switch_page (notebook, page);
5930 }
5931
5932 static void
5933 gtk_notebook_menu_switch_page (GtkWidget       *widget,
5934                                GtkNotebookPage *page)
5935 {
5936   GtkNotebook *notebook;
5937   GList *children;
5938   guint page_num;
5939
5940   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5941                            (GTK_MENU (widget->parent)));
5942
5943   if (notebook->cur_page == page)
5944     return;
5945
5946   page_num = 0;
5947   children = notebook->children;
5948   while (children && children->data != page)
5949     {
5950       children = children->next;
5951       page_num++;
5952     }
5953
5954   g_signal_emit (notebook,
5955                  notebook_signals[SWITCH_PAGE],
5956                  0,
5957                  page,
5958                  page_num);
5959 }
5960
5961 /* Private GtkNotebook Menu Functions:
5962  *
5963  * gtk_notebook_menu_item_create
5964  * gtk_notebook_menu_label_unparent
5965  * gtk_notebook_menu_detacher
5966  */
5967 static void
5968 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
5969                                GList       *list)
5970 {       
5971   GtkNotebookPage *page;
5972   GtkWidget *menu_item;
5973
5974   page = list->data;
5975   if (page->default_menu)
5976     {
5977       if (GTK_IS_LABEL (page->tab_label))
5978         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5979       else
5980         page->menu_label = gtk_label_new ("");
5981       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5982     }
5983
5984   gtk_widget_show (page->menu_label);
5985   menu_item = gtk_menu_item_new ();
5986   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5987   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5988                          gtk_notebook_real_page_position (notebook, list));
5989   g_signal_connect (menu_item, "activate",
5990                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
5991   if (GTK_WIDGET_VISIBLE (page->child))
5992     gtk_widget_show (menu_item);
5993 }
5994
5995 static void
5996 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
5997                                   gpointer  data)
5998 {
5999   gtk_widget_unparent (GTK_BIN (widget)->child);
6000   GTK_BIN (widget)->child = NULL;
6001 }
6002
6003 static void
6004 gtk_notebook_menu_detacher (GtkWidget *widget,
6005                             GtkMenu   *menu)
6006 {
6007   GtkNotebook *notebook;
6008
6009   notebook = GTK_NOTEBOOK (widget);
6010   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6011
6012   notebook->menu = NULL;
6013 }
6014
6015 /* Private GtkNotebook Setter Functions:
6016  *
6017  * gtk_notebook_set_homogeneous_tabs_internal
6018  * gtk_notebook_set_tab_border_internal
6019  * gtk_notebook_set_tab_hborder_internal
6020  * gtk_notebook_set_tab_vborder_internal
6021  */
6022 static void
6023 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6024                                             gboolean     homogeneous)
6025 {
6026   if (homogeneous == notebook->homogeneous)
6027     return;
6028
6029   notebook->homogeneous = homogeneous;
6030   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6031
6032   g_object_notify (G_OBJECT (notebook), "homogeneous");
6033 }
6034
6035 static void
6036 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6037                                       guint        border_width)
6038 {
6039   notebook->tab_hborder = border_width;
6040   notebook->tab_vborder = border_width;
6041
6042   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6043     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6044
6045   g_object_freeze_notify (G_OBJECT (notebook));
6046   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6047   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6048   g_object_thaw_notify (G_OBJECT (notebook));
6049 }
6050
6051 static void
6052 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6053                                        guint        tab_hborder)
6054 {
6055   if (notebook->tab_hborder == tab_hborder)
6056     return;
6057
6058   notebook->tab_hborder = tab_hborder;
6059
6060   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6061     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6062
6063   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6064 }
6065
6066 static void
6067 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6068                                        guint        tab_vborder)
6069 {
6070   if (notebook->tab_vborder == tab_vborder)
6071     return;
6072
6073   notebook->tab_vborder = tab_vborder;
6074
6075   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6076     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6077
6078   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6079 }
6080
6081 /* Public GtkNotebook Page Insert/Remove Methods :
6082  *
6083  * gtk_notebook_append_page
6084  * gtk_notebook_append_page_menu
6085  * gtk_notebook_prepend_page
6086  * gtk_notebook_prepend_page_menu
6087  * gtk_notebook_insert_page
6088  * gtk_notebook_insert_page_menu
6089  * gtk_notebook_remove_page
6090  */
6091 /**
6092  * gtk_notebook_append_page:
6093  * @notebook: a #GtkNotebook
6094  * @child: the #GtkWidget to use as the contents of the page.
6095  * @tab_label: the #GtkWidget to be used as the label for the page,
6096  *             or %NULL to use the default label, 'page N'.
6097  * 
6098  * Appends a page to @notebook.
6099  *
6100  * Return value: the index (starting from 0) of the appended
6101  * page in the notebook, or -1 if function fails
6102  **/
6103 gint
6104 gtk_notebook_append_page (GtkNotebook *notebook,
6105                           GtkWidget   *child,
6106                           GtkWidget   *tab_label)
6107 {
6108   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6109   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6110   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6111   
6112   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6113 }
6114
6115 /**
6116  * gtk_notebook_append_page_menu:
6117  * @notebook: a #GtkNotebook
6118  * @child: the #GtkWidget to use as the contents of the page.
6119  * @tab_label: the #GtkWidget to be used as the label for the page,
6120  *             or %NULL to use the default label, 'page N'.
6121  * @menu_label: the widget to use as a label for the page-switch
6122  *              menu, if that is enabled. If %NULL, and @tab_label
6123  *              is a #GtkLabel or %NULL, then the menu label will be
6124  *              a newly created label with the same text as @tab_label;
6125  *              If @tab_label is not a #GtkLabel, @menu_label must be
6126  *              specified if the page-switch menu is to be used.
6127  * 
6128  * Appends a page to @notebook, specifying the widget to use as the
6129  * label in the popup menu.
6130  *
6131  * Return value: the index (starting from 0) of the appended
6132  * page in the notebook, or -1 if function fails
6133  **/
6134 gint
6135 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6136                                GtkWidget   *child,
6137                                GtkWidget   *tab_label,
6138                                GtkWidget   *menu_label)
6139 {
6140   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6141   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6142   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6143   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6144   
6145   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6146 }
6147
6148 /**
6149  * gtk_notebook_prepend_page:
6150  * @notebook: a #GtkNotebook
6151  * @child: the #GtkWidget to use as the contents of the page.
6152  * @tab_label: the #GtkWidget to be used as the label for the page,
6153  *             or %NULL to use the default label, 'page N'.
6154  *
6155  * Prepends a page to @notebook.
6156  *
6157  * Return value: the index (starting from 0) of the prepended
6158  * page in the notebook, or -1 if function fails
6159  **/
6160 gint
6161 gtk_notebook_prepend_page (GtkNotebook *notebook,
6162                            GtkWidget   *child,
6163                            GtkWidget   *tab_label)
6164 {
6165   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6166   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6167   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6168   
6169   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6170 }
6171
6172 /**
6173  * gtk_notebook_prepend_page_menu:
6174  * @notebook: a #GtkNotebook
6175  * @child: the #GtkWidget to use as the contents of the page.
6176  * @tab_label: the #GtkWidget to be used as the label for the page,
6177  *             or %NULL to use the default label, 'page N'.
6178  * @menu_label: the widget to use as a label for the page-switch
6179  *              menu, if that is enabled. If %NULL, and @tab_label
6180  *              is a #GtkLabel or %NULL, then the menu label will be
6181  *              a newly created label with the same text as @tab_label;
6182  *              If @tab_label is not a #GtkLabel, @menu_label must be
6183  *              specified if the page-switch menu is to be used.
6184  * 
6185  * Prepends a page to @notebook, specifying the widget to use as the
6186  * label in the popup menu.
6187  *
6188  * Return value: the index (starting from 0) of the prepended
6189  * page in the notebook, or -1 if function fails
6190  **/
6191 gint
6192 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6193                                 GtkWidget   *child,
6194                                 GtkWidget   *tab_label,
6195                                 GtkWidget   *menu_label)
6196 {
6197   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6198   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6199   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6200   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6201   
6202   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6203 }
6204
6205 /**
6206  * gtk_notebook_insert_page:
6207  * @notebook: a #GtkNotebook
6208  * @child: the #GtkWidget to use as the contents of the page.
6209  * @tab_label: the #GtkWidget to be used as the label for the page,
6210  *             or %NULL to use the default label, 'page N'.
6211  * @position: the index (starting at 0) at which to insert the page,
6212  *            or -1 to append the page after all other pages.
6213  * 
6214  * Insert a page into @notebook at the given position.
6215  *
6216  * Return value: the index (starting from 0) of the inserted
6217  * page in the notebook, or -1 if function fails
6218  **/
6219 gint
6220 gtk_notebook_insert_page (GtkNotebook *notebook,
6221                           GtkWidget   *child,
6222                           GtkWidget   *tab_label,
6223                           gint         position)
6224 {
6225   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6226   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6227   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6228   
6229   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6230 }
6231
6232
6233 static gint
6234 gtk_notebook_page_compare_tab (gconstpointer a,
6235                                gconstpointer b)
6236 {
6237   return (((GtkNotebookPage *) a)->tab_label != b);
6238 }
6239
6240 static gboolean
6241 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6242                                             gboolean overload,
6243                                             gpointer data)
6244 {
6245   GtkNotebook *notebook = GTK_NOTEBOOK (data);
6246   GList *list;
6247   
6248   list = g_list_find_custom (notebook->children, child,
6249                              gtk_notebook_page_compare_tab);
6250   if (list)
6251     {
6252       GtkNotebookPage *page = list->data;
6253
6254       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
6255       gtk_notebook_switch_page (notebook, page);
6256       focus_tabs_in (notebook);
6257     }
6258
6259   return TRUE;
6260 }
6261
6262 /**
6263  * gtk_notebook_insert_page_menu:
6264  * @notebook: a #GtkNotebook
6265  * @child: the #GtkWidget to use as the contents of the page.
6266  * @tab_label: the #GtkWidget to be used as the label for the page,
6267  *             or %NULL to use the default label, 'page N'.
6268  * @menu_label: the widget to use as a label for the page-switch
6269  *              menu, if that is enabled. If %NULL, and @tab_label
6270  *              is a #GtkLabel or %NULL, then the menu label will be
6271  *              a newly created label with the same text as @tab_label;
6272  *              If @tab_label is not a #GtkLabel, @menu_label must be
6273  *              specified if the page-switch menu is to be used.
6274  * @position: the index (starting at 0) at which to insert the page,
6275  *            or -1 to append the page after all other pages.
6276  * 
6277  * Insert a page into @notebook at the given position, specifying
6278  * the widget to use as the label in the popup menu.
6279  *
6280  * Return value: the index (starting from 0) of the inserted
6281  * page in the notebook
6282  **/
6283 gint
6284 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6285                                GtkWidget   *child,
6286                                GtkWidget   *tab_label,
6287                                GtkWidget   *menu_label,
6288                                gint         position)
6289 {
6290   GtkNotebookClass *class;
6291
6292   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6293   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6294   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6295   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6296
6297   class = GTK_NOTEBOOK_GET_CLASS (notebook);
6298
6299   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6300 }
6301
6302 /**
6303  * gtk_notebook_remove_page:
6304  * @notebook: a #GtkNotebook.
6305  * @page_num: the index of a notebook page, starting
6306  *            from 0. If -1, the last page will
6307  *            be removed.
6308  * 
6309  * Removes a page from the notebook given its index
6310  * in the notebook.
6311  **/
6312 void
6313 gtk_notebook_remove_page (GtkNotebook *notebook,
6314                           gint         page_num)
6315 {
6316   GList *list = NULL;
6317
6318   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6319
6320   if (page_num >= 0)
6321     list = g_list_nth (notebook->children, page_num);
6322   else
6323     list = g_list_last (notebook->children);
6324
6325   if (list)
6326     gtk_container_remove (GTK_CONTAINER (notebook),
6327                           ((GtkNotebookPage *) list->data)->child);
6328 }
6329
6330 /* Public GtkNotebook Page Switch Methods :
6331  * gtk_notebook_get_current_page
6332  * gtk_notebook_page_num
6333  * gtk_notebook_set_current_page
6334  * gtk_notebook_next_page
6335  * gtk_notebook_prev_page
6336  */
6337 /**
6338  * gtk_notebook_get_current_page:
6339  * @notebook: a #GtkNotebook
6340  * 
6341  * Returns the page number of the current page.
6342  * 
6343  * Return value: the index (starting from 0) of the current
6344  * page in the notebook. If the notebook has no pages, then
6345  * -1 will be returned.
6346  **/
6347 gint
6348 gtk_notebook_get_current_page (GtkNotebook *notebook)
6349 {
6350   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6351
6352   if (!notebook->cur_page)
6353     return -1;
6354
6355   return g_list_index (notebook->children, notebook->cur_page);
6356 }
6357
6358 /**
6359  * gtk_notebook_get_nth_page:
6360  * @notebook: a #GtkNotebook
6361  * @page_num: the index of a page in the notebook, or -1
6362  *            to get the last page.
6363  * 
6364  * Returns the child widget contained in page number @page_num.
6365  * 
6366  * Return value: the child widget, or %NULL if @page_num is
6367  * out of bounds.
6368  **/
6369 GtkWidget*
6370 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6371                            gint         page_num)
6372 {
6373   GtkNotebookPage *page;
6374   GList *list;
6375
6376   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6377
6378   if (page_num >= 0)
6379     list = g_list_nth (notebook->children, page_num);
6380   else
6381     list = g_list_last (notebook->children);
6382
6383   if (list)
6384     {
6385       page = list->data;
6386       return page->child;
6387     }
6388
6389   return NULL;
6390 }
6391
6392 /**
6393  * gtk_notebook_get_n_pages:
6394  * @notebook: a #GtkNotebook
6395  * 
6396  * Gets the number of pages in a notebook.
6397  * 
6398  * Return value: the number of pages in the notebook.
6399  *
6400  * Since: 2.2
6401  **/
6402 gint
6403 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6404 {
6405   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6406
6407   return g_list_length (notebook->children);
6408 }
6409
6410 /**
6411  * gtk_notebook_page_num:
6412  * @notebook: a #GtkNotebook
6413  * @child: a #GtkWidget
6414  * 
6415  * Finds the index of the page which contains the given child
6416  * widget.
6417  * 
6418  * Return value: the index of the page containing @child, or
6419  *   -1 if @child is not in the notebook.
6420  **/
6421 gint
6422 gtk_notebook_page_num (GtkNotebook      *notebook,
6423                        GtkWidget        *child)
6424 {
6425   GList *children;
6426   gint num;
6427
6428   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6429
6430   num = 0;
6431   children = notebook->children;
6432   while (children)
6433     {
6434       GtkNotebookPage *page =  children->data;
6435       
6436       if (page->child == child)
6437         return num;
6438
6439       children = children->next;
6440       num++;
6441     }
6442
6443   return -1;
6444 }
6445
6446 /**
6447  * gtk_notebook_set_current_page:
6448  * @notebook: a #GtkNotebook
6449  * @page_num: index of the page to switch to, starting from 0.
6450  *            If negative, the last page will be used. If greater
6451  *            than the number of pages in the notebook, nothing
6452  *            will be done.
6453  *                
6454  * Switches to the page number @page_num. 
6455  *
6456  * Note that due to historical reasons, GtkNotebook refuses
6457  * to switch to a page unless the child widget is visible. 
6458  * Therefore, it is recommended to show child widgets before
6459  * adding them to a notebook. 
6460  */
6461 void
6462 gtk_notebook_set_current_page (GtkNotebook *notebook,
6463                                gint         page_num)
6464 {
6465   GList *list;
6466
6467   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6468
6469   if (page_num < 0)
6470     page_num = g_list_length (notebook->children) - 1;
6471
6472   list = g_list_nth (notebook->children, page_num);
6473   if (list)
6474     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6475 }
6476
6477 /**
6478  * gtk_notebook_next_page:
6479  * @notebook: a #GtkNotebook
6480  * 
6481  * Switches to the next page. Nothing happens if the current page is
6482  * the last page.
6483  **/
6484 void
6485 gtk_notebook_next_page (GtkNotebook *notebook)
6486 {
6487   GList *list;
6488
6489   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6490
6491   list = g_list_find (notebook->children, notebook->cur_page);
6492   if (!list)
6493     return;
6494
6495   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6496   if (!list)
6497     return;
6498
6499   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6500 }
6501
6502 /**
6503  * gtk_notebook_prev_page:
6504  * @notebook: a #GtkNotebook
6505  * 
6506  * Switches to the previous page. Nothing happens if the current page
6507  * is the first page.
6508  **/
6509 void
6510 gtk_notebook_prev_page (GtkNotebook *notebook)
6511 {
6512   GList *list;
6513
6514   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6515
6516   list = g_list_find (notebook->children, notebook->cur_page);
6517   if (!list)
6518     return;
6519
6520   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6521   if (!list)
6522     return;
6523
6524   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6525 }
6526
6527 /* Public GtkNotebook/Tab Style Functions
6528  *
6529  * gtk_notebook_set_show_border
6530  * gtk_notebook_set_show_tabs
6531  * gtk_notebook_set_tab_pos
6532  * gtk_notebook_set_homogeneous_tabs
6533  * gtk_notebook_set_tab_border
6534  * gtk_notebook_set_tab_hborder
6535  * gtk_notebook_set_tab_vborder
6536  * gtk_notebook_set_scrollable
6537  */
6538 /**
6539  * gtk_notebook_set_show_border:
6540  * @notebook: a #GtkNotebook
6541  * @show_border: %TRUE if a bevel should be drawn around the notebook.
6542  * 
6543  * Sets whether a bevel will be drawn around the notebook pages.
6544  * This only has a visual effect when the tabs are not shown.
6545  * See gtk_notebook_set_show_tabs().
6546  **/
6547 void
6548 gtk_notebook_set_show_border (GtkNotebook *notebook,
6549                               gboolean     show_border)
6550 {
6551   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6552
6553   if (notebook->show_border != show_border)
6554     {
6555       notebook->show_border = show_border;
6556
6557       if (GTK_WIDGET_VISIBLE (notebook))
6558         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6559       
6560       g_object_notify (G_OBJECT (notebook), "show-border");
6561     }
6562 }
6563
6564 /**
6565  * gtk_notebook_get_show_border:
6566  * @notebook: a #GtkNotebook
6567  *
6568  * Returns whether a bevel will be drawn around the notebook pages. See
6569  * gtk_notebook_set_show_border().
6570  *
6571  * Return value: %TRUE if the bevel is drawn
6572  **/
6573 gboolean
6574 gtk_notebook_get_show_border (GtkNotebook *notebook)
6575 {
6576   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6577
6578   return notebook->show_border;
6579 }
6580
6581 /**
6582  * gtk_notebook_set_show_tabs:
6583  * @notebook: a #GtkNotebook
6584  * @show_tabs: %TRUE if the tabs should be shown.
6585  * 
6586  * Sets whether to show the tabs for the notebook or not.
6587  **/
6588 void
6589 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6590                             gboolean     show_tabs)
6591 {
6592   GtkNotebookPage *page;
6593   GList *children;
6594
6595   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6596
6597   show_tabs = show_tabs != FALSE;
6598
6599   if (notebook->show_tabs == show_tabs)
6600     return;
6601
6602   notebook->show_tabs = show_tabs;
6603   children = notebook->children;
6604
6605   if (!show_tabs)
6606     {
6607       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6608       
6609       while (children)
6610         {
6611           page = children->data;
6612           children = children->next;
6613           if (page->default_tab)
6614             {
6615               gtk_widget_destroy (page->tab_label);
6616               page->tab_label = NULL;
6617             }
6618           else
6619             gtk_widget_hide (page->tab_label);
6620         }
6621     }
6622   else
6623     {
6624       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6625       gtk_notebook_update_labels (notebook);
6626     }
6627   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6628
6629   g_object_notify (G_OBJECT (notebook), "show-tabs");
6630 }
6631
6632 /**
6633  * gtk_notebook_get_show_tabs:
6634  * @notebook: a #GtkNotebook
6635  *
6636  * Returns whether the tabs of the notebook are shown. See
6637  * gtk_notebook_set_show_tabs().
6638  *
6639  * Return value: %TRUE if the tabs are shown
6640  **/
6641 gboolean
6642 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6643 {
6644   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6645
6646   return notebook->show_tabs;
6647 }
6648
6649 /**
6650  * gtk_notebook_set_tab_pos:
6651  * @notebook: a #GtkNotebook.
6652  * @pos: the edge to draw the tabs at.
6653  * 
6654  * Sets the edge at which the tabs for switching pages in the
6655  * notebook are drawn.
6656  **/
6657 void
6658 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6659                           GtkPositionType  pos)
6660 {
6661   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6662
6663   if (notebook->tab_pos != pos)
6664     {
6665       notebook->tab_pos = pos;
6666       if (GTK_WIDGET_VISIBLE (notebook))
6667         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6668     }
6669
6670   g_object_notify (G_OBJECT (notebook), "tab-pos");
6671 }
6672
6673 /**
6674  * gtk_notebook_get_tab_pos:
6675  * @notebook: a #GtkNotebook
6676  *
6677  * Gets the edge at which the tabs for switching pages in the
6678  * notebook are drawn.
6679  *
6680  * Return value: the edge at which the tabs are drawn
6681  **/
6682 GtkPositionType
6683 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6684 {
6685   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6686
6687   return notebook->tab_pos;
6688 }
6689
6690 /**
6691  * gtk_notebook_set_homogeneous_tabs:
6692  * @notebook: a #GtkNotebook
6693  * @homogeneous: %TRUE if all tabs should be the same size.
6694  * 
6695  * Sets whether the tabs must have all the same size or not.
6696  **/
6697 void
6698 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6699                                    gboolean     homogeneous)
6700 {
6701   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6702
6703   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6704 }
6705
6706 /**
6707  * gtk_notebook_set_tab_border:
6708  * @notebook: a #GtkNotebook
6709  * @border_width: width of the border around the tab labels.
6710  * 
6711  * Sets the width the border around the tab labels
6712  * in a notebook. This is equivalent to calling
6713  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6714  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6715  **/
6716 void
6717 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6718                              guint        border_width)
6719 {
6720   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6721
6722   gtk_notebook_set_tab_border_internal (notebook, border_width);
6723 }
6724
6725 /**
6726  * gtk_notebook_set_tab_hborder:
6727  * @notebook: a #GtkNotebook
6728  * @tab_hborder: width of the horizontal border of tab labels.
6729  * 
6730  * Sets the width of the horizontal border of tab labels.
6731  **/
6732 void
6733 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6734                               guint        tab_hborder)
6735 {
6736   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6737
6738   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6739 }
6740
6741 /**
6742  * gtk_notebook_set_tab_vborder:
6743  * @notebook: a #GtkNotebook
6744  * @tab_vborder: width of the vertical border of tab labels.
6745  * 
6746  * Sets the width of the vertical border of tab labels.
6747  **/
6748 void
6749 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6750                               guint        tab_vborder)
6751 {
6752   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6753
6754   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6755 }
6756
6757 /**
6758  * gtk_notebook_set_scrollable:
6759  * @notebook: a #GtkNotebook
6760  * @scrollable: %TRUE if scroll arrows should be added
6761  * 
6762  * Sets whether the tab label area will have arrows for scrolling if
6763  * there are too many tabs to fit in the area.
6764  **/
6765 void
6766 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6767                              gboolean     scrollable)
6768 {
6769   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6770
6771   scrollable = (scrollable != FALSE);
6772
6773   if (scrollable != notebook->scrollable)
6774     {
6775       notebook->scrollable = scrollable;
6776
6777       if (GTK_WIDGET_VISIBLE (notebook))
6778         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6779
6780       g_object_notify (G_OBJECT (notebook), "scrollable");
6781     }
6782 }
6783
6784 /**
6785  * gtk_notebook_get_scrollable:
6786  * @notebook: a #GtkNotebook
6787  *
6788  * Returns whether the tab label area has arrows for scrolling. See
6789  * gtk_notebook_set_scrollable().
6790  *
6791  * Return value: %TRUE if arrows for scrolling are present
6792  **/
6793 gboolean
6794 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6795 {
6796   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6797
6798   return notebook->scrollable;
6799 }
6800
6801 /* Public GtkNotebook Popup Menu Methods:
6802  *
6803  * gtk_notebook_popup_enable
6804  * gtk_notebook_popup_disable
6805  */
6806
6807
6808 /**
6809  * gtk_notebook_popup_enable:
6810  * @notebook: a #GtkNotebook
6811  * 
6812  * Enables the popup menu: if the user clicks with the right mouse button on
6813  * the bookmarks, a menu with all the pages will be popped up.
6814  **/
6815 void
6816 gtk_notebook_popup_enable (GtkNotebook *notebook)
6817 {
6818   GList *list;
6819
6820   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6821
6822   if (notebook->menu)
6823     return;
6824
6825   notebook->menu = gtk_menu_new ();
6826   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6827        list;
6828        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6829     gtk_notebook_menu_item_create (notebook, list);
6830
6831   gtk_notebook_update_labels (notebook);
6832   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6833                              GTK_WIDGET (notebook),
6834                              gtk_notebook_menu_detacher);
6835
6836   g_object_notify (G_OBJECT (notebook), "enable-popup");
6837 }
6838
6839 /**
6840  * gtk_notebook_popup_disable:
6841  * @notebook: a #GtkNotebook
6842  * 
6843  * Disables the popup menu.
6844  **/
6845 void       
6846 gtk_notebook_popup_disable  (GtkNotebook *notebook)
6847 {
6848   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6849
6850   if (!notebook->menu)
6851     return;
6852
6853   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6854                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6855   gtk_widget_destroy (notebook->menu);
6856
6857   g_object_notify (G_OBJECT (notebook), "enable-popup");
6858 }
6859
6860 /* Public GtkNotebook Page Properties Functions:
6861  *
6862  * gtk_notebook_get_tab_label
6863  * gtk_notebook_set_tab_label
6864  * gtk_notebook_set_tab_label_text
6865  * gtk_notebook_get_menu_label
6866  * gtk_notebook_set_menu_label
6867  * gtk_notebook_set_menu_label_text
6868  * gtk_notebook_set_tab_label_packing
6869  * gtk_notebook_query_tab_label_packing
6870  * gtk_notebook_get_tab_reorderable
6871  * gtk_notebook_set_tab_reorderable
6872  * gtk_notebook_get_tab_detachable
6873  * gtk_notebook_set_tab_detachable
6874  */
6875
6876 /**
6877  * gtk_notebook_get_tab_label:
6878  * @notebook: a #GtkNotebook
6879  * @child: the page
6880  * 
6881  * Returns the tab label widget for the page @child. %NULL is returned
6882  * if @child is not in @notebook or if no tab label has specifically
6883  * been set for @child.
6884  * 
6885  * Return value: the tab label
6886  **/
6887 GtkWidget *
6888 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6889                             GtkWidget   *child)
6890 {
6891   GList *list;
6892
6893   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6894   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6895
6896   list = CHECK_FIND_CHILD (notebook, child);
6897   if (!list)  
6898     return NULL;
6899
6900   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6901     return NULL;
6902
6903   return GTK_NOTEBOOK_PAGE (list)->tab_label;
6904 }  
6905
6906 /**
6907  * gtk_notebook_set_tab_label:
6908  * @notebook: a #GtkNotebook
6909  * @child: the page
6910  * @tab_label: the tab label widget to use, or %NULL for default tab
6911  *             label.
6912  * 
6913  * Changes the tab label for @child. If %NULL is specified
6914  * for @tab_label, then the page will have the label 'page N'.
6915  **/
6916 void
6917 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6918                             GtkWidget   *child,
6919                             GtkWidget   *tab_label)
6920 {
6921   GtkNotebookPage *page;
6922   GList *list;
6923
6924   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6925   g_return_if_fail (GTK_IS_WIDGET (child));
6926
6927   list = CHECK_FIND_CHILD (notebook, child);
6928   if (!list)  
6929     return;
6930
6931   /* a NULL pointer indicates a default_tab setting, otherwise
6932    * we need to set the associated label
6933    */
6934   page = list->data;
6935   
6936   if (page->tab_label == tab_label)
6937     return;
6938   
6939
6940   gtk_notebook_remove_tab_label (notebook, page);
6941   
6942   if (tab_label)
6943     {
6944       page->default_tab = FALSE;
6945       page->tab_label = tab_label;
6946       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6947     }
6948   else
6949     {
6950       page->default_tab = TRUE;
6951       page->tab_label = NULL;
6952
6953       if (notebook->show_tabs)
6954         {
6955           gchar string[32];
6956
6957           g_snprintf (string, sizeof(string), _("Page %u"), 
6958                       gtk_notebook_real_page_position (notebook, list));
6959           page->tab_label = gtk_label_new (string);
6960           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6961         }
6962     }
6963
6964   if (page->tab_label)
6965     page->mnemonic_activate_signal =
6966       g_signal_connect (page->tab_label,
6967                         "mnemonic-activate",
6968                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6969                         notebook);
6970
6971   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6972     {
6973       gtk_widget_show (page->tab_label);
6974       gtk_widget_queue_resize (GTK_WIDGET (notebook));
6975     }
6976
6977   gtk_notebook_update_tab_states (notebook);
6978   gtk_widget_child_notify (child, "tab-label");
6979 }
6980
6981 /**
6982  * gtk_notebook_set_tab_label_text:
6983  * @notebook: a #GtkNotebook
6984  * @child: the page
6985  * @tab_text: the label text
6986  * 
6987  * Creates a new label and sets it as the tab label for the page
6988  * containing @child.
6989  **/
6990 void
6991 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6992                                  GtkWidget   *child,
6993                                  const gchar *tab_text)
6994 {
6995   GtkWidget *tab_label = NULL;
6996
6997   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6998
6999   if (tab_text)
7000     tab_label = gtk_label_new (tab_text);
7001   gtk_notebook_set_tab_label (notebook, child, tab_label);
7002   gtk_widget_child_notify (child, "tab-label");
7003 }
7004
7005 /**
7006  * gtk_notebook_get_tab_label_text:
7007  * @notebook: a #GtkNotebook
7008  * @child: a widget contained in a page of @notebook
7009  *
7010  * Retrieves the text of the tab label for the page containing
7011  *    @child.
7012  *
7013  * Return value: the text of the tab label, or %NULL if the
7014  *               tab label widget is not a #GtkLabel. The
7015  *               string is owned by the widget and must not
7016  *               be freed.
7017  **/
7018 G_CONST_RETURN gchar *
7019 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7020                                  GtkWidget   *child)
7021 {
7022   GtkWidget *tab_label;
7023
7024   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7025   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7026
7027   tab_label = gtk_notebook_get_tab_label (notebook, child);
7028
7029   if (GTK_IS_LABEL (tab_label))
7030     return gtk_label_get_text (GTK_LABEL (tab_label));
7031   else
7032     return NULL;
7033 }
7034
7035 /**
7036  * gtk_notebook_get_menu_label:
7037  * @notebook: a #GtkNotebook
7038  * @child: a widget contained in a page of @notebook
7039  * 
7040  * Retrieves the menu label widget of the page containing @child.
7041  * 
7042  * Return value: the menu label, or %NULL if the
7043  *               notebook page does not have a menu label other
7044  *               than the default (the tab label).
7045  **/
7046 GtkWidget*
7047 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7048                              GtkWidget   *child)
7049 {
7050   GList *list;
7051
7052   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7053   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7054
7055   list = CHECK_FIND_CHILD (notebook, child);
7056   if (!list)  
7057     return NULL;
7058
7059   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7060     return NULL;
7061
7062   return GTK_NOTEBOOK_PAGE (list)->menu_label;
7063 }  
7064
7065 /**
7066  * gtk_notebook_set_menu_label:
7067  * @notebook: a #GtkNotebook
7068  * @child: the child widget
7069  * @menu_label: the menu label, or NULL for default
7070  * 
7071  * Changes the menu label for the page containing @child. 
7072  **/
7073 void
7074 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7075                              GtkWidget   *child,
7076                              GtkWidget   *menu_label)
7077 {
7078   GtkNotebookPage *page;
7079   GList *list;
7080
7081   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7082   g_return_if_fail (GTK_IS_WIDGET (child));
7083
7084   list = CHECK_FIND_CHILD (notebook, child);
7085   if (!list)  
7086     return;
7087
7088   page = list->data;
7089   if (page->menu_label)
7090     {
7091       if (notebook->menu)
7092         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
7093                               page->menu_label->parent);
7094
7095       if (!page->default_menu)
7096         g_object_unref (page->menu_label);
7097     }
7098
7099   if (menu_label)
7100     {
7101       page->menu_label = menu_label;
7102       g_object_ref_sink (page->menu_label);
7103       page->default_menu = FALSE;
7104     }
7105   else
7106     page->default_menu = TRUE;
7107
7108   if (notebook->menu)
7109     gtk_notebook_menu_item_create (notebook, list);
7110   gtk_widget_child_notify (child, "menu-label");
7111 }
7112
7113 /**
7114  * gtk_notebook_set_menu_label_text:
7115  * @notebook: a #GtkNotebook
7116  * @child: the child widget
7117  * @menu_text: the label text
7118  * 
7119  * Creates a new label and sets it as the menu label of @child.
7120  **/
7121 void
7122 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7123                                   GtkWidget   *child,
7124                                   const gchar *menu_text)
7125 {
7126   GtkWidget *menu_label = NULL;
7127
7128   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7129
7130   if (menu_text)
7131     {
7132       menu_label = gtk_label_new (menu_text);
7133       gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7134     }
7135   gtk_notebook_set_menu_label (notebook, child, menu_label);
7136   gtk_widget_child_notify (child, "menu-label");
7137 }
7138
7139 /**
7140  * gtk_notebook_get_menu_label_text:
7141  * @notebook: a #GtkNotebook
7142  * @child: the child widget of a page of the notebook.
7143  *
7144  * Retrieves the text of the menu label for the page containing
7145  *    @child.
7146  *
7147  * Return value: the text of the tab label, or %NULL if the
7148  *               widget does not have a menu label other than
7149  *               the default menu label, or the menu label widget
7150  *               is not a #GtkLabel. The string is owned by
7151  *               the widget and must not be freed.
7152  **/
7153 G_CONST_RETURN gchar *
7154 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7155                                   GtkWidget *child)
7156 {
7157   GtkWidget *menu_label;
7158
7159   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7160   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7161  
7162   menu_label = gtk_notebook_get_menu_label (notebook, child);
7163
7164   if (GTK_IS_LABEL (menu_label))
7165     return gtk_label_get_text (GTK_LABEL (menu_label));
7166   else
7167     return NULL;
7168 }
7169   
7170 /* Helper function called when pages are reordered
7171  */
7172 static void
7173 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7174                               GtkNotebookPage *page)
7175 {
7176   if (notebook->menu)
7177     {
7178       GtkWidget *menu_item;
7179       
7180       menu_item = page->menu_label->parent;
7181       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7182       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7183       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7184     }
7185
7186   gtk_notebook_update_tab_states (notebook);
7187   gtk_notebook_update_labels (notebook);
7188 }
7189
7190 /**
7191  * gtk_notebook_set_tab_label_packing:
7192  * @notebook: a #GtkNotebook
7193  * @child: the child widget
7194  * @expand: whether to expand the bookmark or not
7195  * @fill: whether the bookmark should fill the allocated area or not
7196  * @pack_type: the position of the bookmark
7197  * 
7198  * Sets the packing parameters for the tab label of the page
7199  * containing @child. See gtk_box_pack_start() for the exact meaning
7200  * of the parameters.
7201  **/
7202 void
7203 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7204                                     GtkWidget   *child,
7205                                     gboolean     expand,
7206                                     gboolean     fill,
7207                                     GtkPackType  pack_type)
7208 {
7209   GtkNotebookPage *page;
7210   GList *list;
7211
7212   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7213   g_return_if_fail (GTK_IS_WIDGET (child));
7214
7215   list = CHECK_FIND_CHILD (notebook, child);
7216   if (!list)  
7217     return;
7218
7219   page = list->data;
7220   expand = expand != FALSE;
7221   fill = fill != FALSE;
7222   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7223     return;
7224
7225   gtk_widget_freeze_child_notify (child);
7226   page->expand = expand;
7227   gtk_widget_child_notify (child, "tab-expand");
7228   page->fill = fill;
7229   gtk_widget_child_notify (child, "tab-fill");
7230   if (page->pack != pack_type)
7231     {
7232       page->pack = pack_type;
7233       gtk_notebook_child_reordered (notebook, page);
7234     }
7235   gtk_widget_child_notify (child, "tab-pack");
7236   gtk_widget_child_notify (child, "position");
7237   if (notebook->show_tabs)
7238     gtk_notebook_pages_allocate (notebook);
7239   gtk_widget_thaw_child_notify (child);
7240 }  
7241
7242 /**
7243  * gtk_notebook_query_tab_label_packing:
7244  * @notebook: a #GtkNotebook
7245  * @child: the page
7246  * @expand: location to store the expand value (or NULL)
7247  * @fill: location to store the fill value (or NULL)
7248  * @pack_type: location to store the pack_type (or NULL)
7249  * 
7250  * Query the packing attributes for the tab label of the page
7251  * containing @child.
7252  **/
7253 void
7254 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7255                                       GtkWidget   *child,
7256                                       gboolean    *expand,
7257                                       gboolean    *fill,
7258                                       GtkPackType *pack_type)
7259 {
7260   GList *list;
7261
7262   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7263   g_return_if_fail (GTK_IS_WIDGET (child));
7264
7265   list = CHECK_FIND_CHILD (notebook, child);
7266   if (!list)
7267     return;
7268
7269   if (expand)
7270     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7271   if (fill)
7272     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7273   if (pack_type)
7274     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7275 }
7276
7277 /**
7278  * gtk_notebook_reorder_child:
7279  * @notebook: a #GtkNotebook
7280  * @child: the child to move
7281  * @position: the new position, or -1 to move to the end
7282  * 
7283  * Reorders the page containing @child, so that it appears in position
7284  * @position. If @position is greater than or equal to the number of
7285  * children in the list or negative, @child will be moved to the end
7286  * of the list.
7287  **/
7288 void
7289 gtk_notebook_reorder_child (GtkNotebook *notebook,
7290                             GtkWidget   *child,
7291                             gint         position)
7292 {
7293   GList *list, *new_list;
7294   GtkNotebookPage *page;
7295   gint old_pos;
7296   gint max_pos;
7297
7298   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7299   g_return_if_fail (GTK_IS_WIDGET (child));
7300
7301   list = CHECK_FIND_CHILD (notebook, child);
7302   if (!list)
7303     return;
7304
7305   max_pos = g_list_length (notebook->children) - 1;
7306   if (position < 0 || position > max_pos)
7307     position = max_pos;
7308
7309   old_pos = g_list_position (notebook->children, list);
7310
7311   if (old_pos == position)
7312     return;
7313
7314   page = list->data;
7315   notebook->children = g_list_delete_link (notebook->children, list);
7316
7317   notebook->children = g_list_insert (notebook->children, page, position);
7318   new_list = g_list_nth (notebook->children, position);
7319
7320   /* Fix up GList references in GtkNotebook structure */
7321   if (notebook->first_tab == list)
7322     notebook->first_tab = new_list;
7323   if (notebook->focus_tab == list)
7324     notebook->focus_tab = new_list;
7325
7326   gtk_widget_freeze_child_notify (child);
7327
7328   /* Move around the menu items if necessary */
7329   gtk_notebook_child_reordered (notebook, page);
7330   gtk_widget_child_notify (child, "tab-pack");
7331   gtk_widget_child_notify (child, "position");
7332
7333   if (notebook->show_tabs)
7334     gtk_notebook_pages_allocate (notebook);
7335
7336   gtk_widget_thaw_child_notify (child);
7337
7338   g_signal_emit (notebook,
7339                  notebook_signals[PAGE_REORDERED],
7340                  0,
7341                  child,
7342                  position);
7343 }
7344
7345 /**
7346  * gtk_notebook_set_window_creation_hook:
7347  * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7348  * @data: user data for @func
7349  * @destroy: Destroy notifier for @data, or %NULL
7350  *
7351  * Installs a global function used to create a window
7352  * when a detached tab is dropped in an empty area.
7353  * 
7354  * Since: 2.10
7355  **/
7356 void
7357 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
7358                                        gpointer                       data,
7359                                        GDestroyNotify                 destroy)
7360 {
7361   if (window_creation_hook_destroy)
7362     window_creation_hook_destroy (window_creation_hook_data);
7363
7364   window_creation_hook = func;
7365   window_creation_hook_data = data;
7366   window_creation_hook_destroy = destroy;
7367 }
7368
7369 /**
7370  * gtk_notebook_set_group_id:
7371  * @notebook: a #GtkNotebook
7372  * @group_id: a group identificator, or -1 to unset it
7373  *
7374  * Sets an group identificator for @notebook, notebooks sharing
7375  * the same group identificator will be able to exchange tabs
7376  * via drag and drop. A notebook with group identificator -1 will
7377  * not be able to exchange tabs with any other notebook.
7378  * 
7379  * Since: 2.10
7380  * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7381  */
7382 void
7383 gtk_notebook_set_group_id (GtkNotebook *notebook,
7384                            gint         group_id)
7385 {
7386   gpointer group;
7387
7388   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7389
7390   /* add 1 to get rid of the -1/NULL difference */
7391   group = GINT_TO_POINTER (group_id + 1);
7392   gtk_notebook_set_group (notebook, group);
7393 }
7394
7395 /**
7396  * gtk_notebook_set_group:
7397  * @notebook: a #GtkNotebook
7398  * @group: a pointer to identify the notebook group, or %NULL to unset it
7399  *
7400  * Sets a group identificator pointer for @notebook, notebooks sharing
7401  * the same group identificator pointer will be able to exchange tabs
7402  * via drag and drop. A notebook with a %NULL group identificator will
7403  * not be able to exchange tabs with any other notebook.
7404  * 
7405  * Since: 2.12
7406  */
7407 void
7408 gtk_notebook_set_group (GtkNotebook *notebook,
7409                         gpointer     group)
7410 {
7411   GtkNotebookPrivate *priv;
7412
7413   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7414
7415   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7416
7417   if (priv->group != group)
7418     {
7419       priv->group = group;
7420       g_object_notify (G_OBJECT (notebook), "group-id");
7421       g_object_notify (G_OBJECT (notebook), "group");
7422     }
7423 }
7424
7425 /**
7426  * gtk_notebook_get_group_id:
7427  * @notebook: a #GtkNotebook
7428  * 
7429  * Gets the current group identificator for @notebook.
7430  * 
7431  * Return Value: the group identificator, or -1 if none is set.
7432  *
7433  * Since: 2.10
7434  * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7435  */
7436 gint
7437 gtk_notebook_get_group_id (GtkNotebook *notebook)
7438 {
7439   GtkNotebookPrivate *priv;
7440
7441   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7442
7443   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7444
7445   /* substract 1 to get rid of the -1/NULL difference */
7446   return GPOINTER_TO_INT (priv->group) - 1;
7447 }
7448
7449 /**
7450  * gtk_notebook_get_group:
7451  * @notebook: a #GtkNotebook
7452  * 
7453  * Gets the current group identificator pointer for @notebook.
7454  * 
7455  * Return Value: the group identificator, or %NULL if none is set.
7456  *
7457  * Since: 2.12
7458  **/
7459 gpointer
7460 gtk_notebook_get_group (GtkNotebook *notebook)
7461 {
7462   GtkNotebookPrivate *priv;
7463
7464   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7465
7466   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7467   return priv->group;
7468 }
7469
7470 /**
7471  * gtk_notebook_get_tab_reorderable:
7472  * @notebook: a #GtkNotebook
7473  * @child: a child #GtkWidget
7474  * 
7475  * Gets whether the tab can be reordered via drag and drop or not.
7476  * 
7477  * Return Value: %TRUE if the tab is reorderable.
7478  * 
7479  * Since: 2.10
7480  **/
7481 gboolean
7482 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7483                                   GtkWidget   *child)
7484 {
7485   GList *list;
7486
7487   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7488   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7489
7490   list = CHECK_FIND_CHILD (notebook, child);
7491   if (!list)  
7492     return FALSE;
7493
7494   return GTK_NOTEBOOK_PAGE (list)->reorderable;
7495 }
7496
7497 /**
7498  * gtk_notebook_set_tab_reorderable:
7499  * @notebook: a #GtkNotebook
7500  * @child: a child #GtkWidget
7501  * @reorderable: whether the tab is reorderable or not.
7502  *
7503  * Sets whether the notebook tab can be reordered
7504  * via drag and drop or not.
7505  * 
7506  * Since: 2.10
7507  **/
7508 void
7509 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7510                                   GtkWidget   *child,
7511                                   gboolean     reorderable)
7512 {
7513   GList *list;
7514
7515   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7516   g_return_if_fail (GTK_IS_WIDGET (child));
7517
7518   list = CHECK_FIND_CHILD (notebook, child);
7519   if (!list)  
7520     return;
7521
7522   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7523     {
7524       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7525       gtk_widget_child_notify (child, "reorderable");
7526     }
7527 }
7528
7529 /**
7530  * gtk_notebook_get_tab_detachable:
7531  * @notebook: a #GtkNotebook
7532  * @child: a child #GtkWidget
7533  * 
7534  * Returns whether the tab contents can be detached from @notebook.
7535  * 
7536  * Return Value: TRUE if the tab is detachable.
7537  *
7538  * Since: 2.10
7539  **/
7540 gboolean
7541 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7542                                  GtkWidget   *child)
7543 {
7544   GList *list;
7545
7546   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7547   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7548
7549   list = CHECK_FIND_CHILD (notebook, child);
7550   if (!list)  
7551     return FALSE;
7552
7553   return GTK_NOTEBOOK_PAGE (list)->detachable;
7554 }
7555
7556 /**
7557  * gtk_notebook_set_tab_detachable:
7558  * @notebook: a #GtkNotebook
7559  * @child: a child #GtkWidget
7560  * @detachable: whether the tab is detachable or not
7561  *
7562  * Sets whether the tab can be detached from @notebook to another
7563  * notebook or widget.
7564  *
7565  * Note that 2 notebooks must share a common group identificator
7566  * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7567  * interchange between them.
7568  *
7569  * If you want a widget to interact with a notebook through DnD
7570  * (i.e.: accept dragged tabs from it) it must be set as a drop
7571  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7572  * will fill the selection with a GtkWidget** pointing to the child
7573  * widget that corresponds to the dropped tab.
7574  * |[
7575  *  static void
7576  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
7577  *                                   GdkDragContext   *context,
7578  *                                   gint              x,
7579  *                                   gint              y,
7580  *                                   GtkSelectionData *selection_data,
7581  *                                   guint             info,
7582  *                                   guint             time,
7583  *                                   gpointer          user_data)
7584  *  {
7585  *    GtkWidget *notebook;
7586  *    GtkWidget **child;
7587  *    
7588  *    notebook = gtk_drag_get_source_widget (context);
7589  *    child = (void*) selection_data->data;
7590  *    
7591  *    process_widget (*child);
7592  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
7593  *  }
7594  * ]|
7595  *
7596  * If you want a notebook to accept drags from other widgets,
7597  * you will have to set your own DnD code to do it.
7598  *
7599  * Since: 2.10
7600  **/
7601 void
7602 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7603                                  GtkWidget  *child,
7604                                  gboolean    detachable)
7605 {
7606   GList *list;
7607
7608   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7609   g_return_if_fail (GTK_IS_WIDGET (child));
7610
7611   list = CHECK_FIND_CHILD (notebook, child);
7612   if (!list)  
7613     return;
7614
7615   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7616     {
7617       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7618       gtk_widget_child_notify (child, "detachable");
7619     }
7620 }
7621
7622 #define __GTK_NOTEBOOK_C__
7623 #include "gtkaliasdef.c"