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