]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtknotebook.c
Deprecate flag macros for toplevel, state, no window and composite child
[~andy/gtk] / gtk / gtknotebook.c
index dfef203d6c6e803b48c8ac9f6a30449b7df6233d..8a9b699eb5edb56fcd059c9c144782ffbea64831 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#undef GTK_DISABLE_DEPRECATED
+
 #include "gtknotebook.h"
 #include "gtkmain.h"
 #include "gtkmenu.h"
 #include "gtkmenuitem.h"
 #include "gtklabel.h"
-#include <gdk/gdkkeysyms.h>
-#include <stdio.h>
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkbindings.h"
 #include "gtkprivate.h"
-#include "gtkalias.h"
 #include "gtkdnd.h"
+#include "gtkbuildable.h"
+
+#include "gtkalias.h"
 
 #define SCROLL_DELAY_FACTOR   5
 #define SCROLL_THRESHOLD      12
 #define DND_THRESHOLD_MULTIPLIER 4
+#define FRAMES_PER_SECOND     45
+#define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
 
 enum {
   SWITCH_PAGE,
@@ -54,6 +64,7 @@ enum {
   PAGE_REORDERED,
   PAGE_REMOVED,
   PAGE_ADDED,
+  CREATE_WINDOW,
   LAST_SIGNAL
 };
 
@@ -100,6 +111,7 @@ enum {
   PROP_PAGE,
   PROP_ENABLE_POPUP,
   PROP_GROUP_ID,
+  PROP_GROUP,
   PROP_HOMOGENEOUS
 };
 
@@ -115,6 +127,12 @@ enum {
   CHILD_PROP_DETACHABLE
 };
 
+enum {
+  ACTION_WIDGET_START,
+  ACTION_WIDGET_END,
+  N_ACTION_WIDGETS
+};
+
 #define GTK_NOTEBOOK_PAGE(_glist_)         ((GtkNotebookPage *)((GList *)(_glist_))->data)
 
 /* some useful defines for calculating coords */
@@ -141,6 +159,11 @@ struct _GtkNotebookPage
   guint reorderable  : 1;
   guint detachable   : 1;
 
+  /* if true, the tab label was visible on last allocation; we track this so
+   * that we know to redraw the tab area if a tab label was hidden then shown
+   * without changing position */
+  guint tab_allocated_visible : 1;
+
   GtkRequisition requisition;
   GtkAllocation allocation;
 
@@ -154,13 +177,20 @@ typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
 
 struct _GtkNotebookPrivate
 {
-  gint  group_id;
+  gpointer group;
   gint  mouse_x;
   gint  mouse_y;
   gint  pressed_button;
   guint dnd_timer;
   guint switch_tab_timer;
 
+  gint  drag_begin_x;
+  gint  drag_begin_y;
+
+  gint  drag_offset_x;
+  gint  drag_offset_y;
+
+  GtkWidget *dnd_window;
   GtkTargetList *source_targets;
   GtkNotebookDragOperation operation;
   GdkWindow *drag_window;
@@ -168,17 +198,17 @@ struct _GtkNotebookPrivate
   gint drag_window_y;
   GtkNotebookPage *detached_tab;
 
-  gboolean during_detach : 1;
-  gboolean has_scrolled  : 1;
-};
+  guint32 timestamp;
 
-static const GtkTargetEntry notebook_source_targets [] = {
-  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
-  { "application/x-rootwindow-drop", 0, 1 }
+  GtkWidget *action_widget[N_ACTION_WIDGETS];
+
+  guint during_reorder : 1;
+  guint during_detach  : 1;
+  guint has_scrolled   : 1;
 };
 
-static const GtkTargetEntry notebook_dest_targets[] = {
-  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
+static const GtkTargetEntry notebook_targets [] = {
+  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
 };
 
 #ifdef G_DISABLE_CHECKS
@@ -194,13 +224,15 @@ static gboolean gtk_notebook_select_page         (GtkNotebook      *notebook,
                                                  gboolean          move_focus);
 static gboolean gtk_notebook_focus_tab           (GtkNotebook      *notebook,
                                                  GtkNotebookTab    type);
-static void     gtk_notebook_change_current_page (GtkNotebook      *notebook,
+static gboolean gtk_notebook_change_current_page (GtkNotebook      *notebook,
                                                  gint              offset);
 static void     gtk_notebook_move_focus_out      (GtkNotebook      *notebook,
                                                  GtkDirectionType  direction_type);
-static void     gtk_notebook_reorder_tab         (GtkNotebook      *notebook,
+static gboolean gtk_notebook_reorder_tab         (GtkNotebook      *notebook,
                                                  GtkDirectionType  direction_type,
                                                  gboolean          move_to_last);
+static void     gtk_notebook_remove_tab_label    (GtkNotebook      *notebook,
+                                                 GtkNotebookPage  *page);
 
 /*** GtkObject Methods ***/
 static void gtk_notebook_destroy             (GtkObject        *object);
@@ -231,8 +263,6 @@ static gint gtk_notebook_button_press        (GtkWidget        *widget,
 static gint gtk_notebook_button_release      (GtkWidget        *widget,
                                              GdkEventButton   *event);
 static gboolean gtk_notebook_popup_menu      (GtkWidget        *widget);
-static gint gtk_notebook_enter_notify        (GtkWidget        *widget,
-                                             GdkEventCrossing *event);
 static gint gtk_notebook_leave_notify        (GtkWidget        *widget,
                                              GdkEventCrossing *event);
 static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
@@ -245,7 +275,8 @@ static void gtk_notebook_grab_notify         (GtkWidget          *widget,
                                              gboolean            was_grabbed);
 static void gtk_notebook_state_changed       (GtkWidget          *widget,
                                              GtkStateType        previous_state);
-static void gtk_notebook_draw_focus          (GtkWidget        *widget);
+static void gtk_notebook_draw_focus          (GtkWidget        *widget,
+                                             GdkEventExpose   *event);
 static gint gtk_notebook_focus               (GtkWidget        *widget,
                                              GtkDirectionType  direction);
 static void gtk_notebook_style_set           (GtkWidget        *widget,
@@ -254,6 +285,12 @@ static void gtk_notebook_style_set           (GtkWidget        *widget,
 /*** Drag and drop Methods ***/
 static void gtk_notebook_drag_begin          (GtkWidget        *widget,
                                              GdkDragContext   *context);
+static void gtk_notebook_drag_end            (GtkWidget        *widget,
+                                             GdkDragContext   *context);
+static gboolean gtk_notebook_drag_failed     (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             GtkDragResult     result,
+                                             gpointer          data);
 static gboolean gtk_notebook_drag_motion     (GtkWidget        *widget,
                                              GdkDragContext   *context,
                                              gint              x,
@@ -310,6 +347,11 @@ static gint gtk_notebook_real_insert_page    (GtkNotebook      *notebook,
                                              GtkWidget        *menu_label,
                                              gint              position);
 
+static GtkNotebook *gtk_notebook_create_window (GtkNotebook    *notebook,
+                                                GtkWidget      *page,
+                                                gint            x,
+                                                gint            y);
+
 /*** GtkNotebook Private Functions ***/
 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
@@ -329,6 +371,8 @@ static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
                                              GList            *list,
                                              gint              direction,
                                              gboolean          find_visible);
+static void  gtk_notebook_child_reordered    (GtkNotebook      *notebook,
+                                             GtkNotebookPage  *page);
 
 /*** GtkNotebook Drawing Functions ***/
 static void gtk_notebook_paint               (GtkWidget        *widget,
@@ -341,7 +385,7 @@ static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
 
 /*** GtkNotebook Size Allocate Functions ***/
 static void gtk_notebook_pages_allocate      (GtkNotebook      *notebook);
-static void gtk_notebook_page_allocate       (GtkNotebook      *notebook,
+static gboolean gtk_notebook_page_allocate   (GtkNotebook      *notebook,
                                              GtkNotebookPage  *page);
 static void gtk_notebook_calc_tabs           (GtkNotebook      *notebook,
                                              GList            *start,
@@ -356,8 +400,7 @@ static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
 
 /*** GtkNotebook Page Switch Functions ***/
 static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
-                                             GtkNotebookPage  *page,
-                                             gint              page_num);
+                                             GtkNotebookPage  *page);
 static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
                                              gboolean          move_focus);
 static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
@@ -393,14 +436,28 @@ static gboolean focus_child_in (GtkNotebook      *notebook,
                                GtkDirectionType  direction);
 
 static void stop_scrolling (GtkNotebook *notebook);
+static void do_detach_tab  (GtkNotebook *from,
+                           GtkNotebook *to,
+                           GtkWidget   *child,
+                           gint         x,
+                           gint         y);
 
+/* GtkBuildable */
+static void gtk_notebook_buildable_init           (GtkBuildableIface *iface);
+static void gtk_notebook_buildable_add_child      (GtkBuildable *buildable,
+                                                  GtkBuilder   *builder,
+                                                  GObject      *child,
+                                                  const gchar  *type);
 
 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
 static gpointer window_creation_hook_data;
+static GDestroyNotify window_creation_hook_destroy = NULL;
 
 static guint notebook_signals[LAST_SIGNAL] = { 0 };
 
-G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                               gtk_notebook_buildable_init))
 
 static void
 add_tab_bindings (GtkBindingSet    *binding_set,
@@ -448,6 +505,22 @@ add_reorder_bindings (GtkBindingSet    *binding_set,
                                G_TYPE_BOOLEAN, move_to_last);
 }
 
+static gboolean
+gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
+                                GValue                *return_accu,
+                                const GValue          *handler_return,
+                                gpointer               dummy)
+{
+  gboolean continue_emission;
+  GObject *object;
+
+  object = g_value_get_object (handler_return);
+  g_value_set_object (return_accu, object);
+  continue_emission = !object;
+
+  return continue_emission;
+}
+
 static void
 gtk_notebook_class_init (GtkNotebookClass *class)
 {
@@ -472,7 +545,6 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   widget_class->button_press_event = gtk_notebook_button_press;
   widget_class->button_release_event = gtk_notebook_button_release;
   widget_class->popup_menu = gtk_notebook_popup_menu;
-  widget_class->enter_notify_event = gtk_notebook_enter_notify;
   widget_class->leave_notify_event = gtk_notebook_leave_notify;
   widget_class->motion_notify_event = gtk_notebook_motion_notify;
   widget_class->grab_notify = gtk_notebook_grab_notify;
@@ -482,6 +554,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   widget_class->focus = gtk_notebook_focus;
   widget_class->style_set = gtk_notebook_style_set;
   widget_class->drag_begin = gtk_notebook_drag_begin;
+  widget_class->drag_end = gtk_notebook_drag_end;
   widget_class->drag_motion = gtk_notebook_drag_motion;
   widget_class->drag_leave = gtk_notebook_drag_leave;
   widget_class->drag_drop = gtk_notebook_drag_drop;
@@ -504,15 +577,16 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   class->change_current_page = gtk_notebook_change_current_page;
   class->move_focus_out = gtk_notebook_move_focus_out;
   class->reorder_tab = gtk_notebook_reorder_tab;
+  class->create_window = gtk_notebook_create_window;
   
   g_object_class_install_property (gobject_class,
                                   PROP_PAGE,
                                   g_param_spec_int ("page",
                                                     P_("Page"),
                                                     P_("The index of the current page"),
-                                                    0,
+                                                    -1,
                                                     G_MAXINT,
-                                                    0,
+                                                    -1,
                                                     GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_POS,
@@ -594,6 +668,20 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                                                     -1,
                                                     GTK_PARAM_READWRITE));
 
+  /**
+   * GtkNotebook:group:
+   *  
+   * Group for tabs drag and drop.
+   *
+   * Since: 2.12
+   */    
+  g_object_class_install_property (gobject_class,
+                                  PROP_GROUP,
+                                  g_param_spec_pointer ("group",
+                                                        P_("Group"),
+                                                        P_("Group for tabs drag and drop"),
+                                                        GTK_PARAM_READWRITE));
+
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_LABEL,
                                              g_param_spec_string ("tab-label", 
@@ -620,7 +708,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                                              g_param_spec_boolean ("tab-expand", 
                                                                    P_("Tab expand"), 
                                                                    P_("Whether to expand the child's tab or not"),
-                                                                   TRUE,
+                                                                   FALSE,
                                                                    GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_FILL,
@@ -749,22 +837,22 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   /**
    * GtkNotebook:arrow-spacing:
    *
-   * The "arrow-size" property defines the spacing between the scroll
+   * The "arrow-spacing" property defines the spacing between the scroll
    * arrows and the tabs.
    *
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("arrow-spacing",
-                                                             _("Arrow spacing"),
-                                                             _("Scroll arrow spacing"),
+                                                             P_("Arrow spacing"),
+                                                             P_("Scroll arrow spacing"),
                                                              0,
                                                              G_MAXINT,
                                                              0,
                                                              GTK_PARAM_READABLE));
 
   notebook_signals[SWITCH_PAGE] =
-    g_signal_new (I_("switch_page"),
+    g_signal_new (I_("switch-page"),
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
@@ -774,7 +862,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                  G_TYPE_POINTER,
                  G_TYPE_UINT);
   notebook_signals[FOCUS_TAB] = 
-    g_signal_new (I_("focus_tab"),
+    g_signal_new (I_("focus-tab"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
@@ -783,7 +871,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                   G_TYPE_BOOLEAN, 1,
                   GTK_TYPE_NOTEBOOK_TAB);
   notebook_signals[SELECT_PAGE] = 
-    g_signal_new (I_("select_page"),
+    g_signal_new (I_("select-page"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, select_page),
@@ -792,16 +880,16 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                   G_TYPE_BOOLEAN, 1,
                   G_TYPE_BOOLEAN);
   notebook_signals[CHANGE_CURRENT_PAGE] = 
-    g_signal_new (I_("change_current_page"),
+    g_signal_new (I_("change-current-page"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
                   NULL, NULL,
-                  _gtk_marshal_VOID__INT,
-                  G_TYPE_NONE, 1,
+                  _gtk_marshal_BOOLEAN__INT,
+                  G_TYPE_BOOLEAN, 1,
                   G_TYPE_INT);
   notebook_signals[MOVE_FOCUS_OUT] =
-    g_signal_new (I_("move_focus_out"),
+    g_signal_new (I_("move-focus-out"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
@@ -810,13 +898,13 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                   G_TYPE_NONE, 1,
                   GTK_TYPE_DIRECTION_TYPE);
   notebook_signals[REORDER_TAB] =
-    g_signal_new (I_("reorder_tab"),
+    g_signal_new (I_("reorder-tab"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
                   NULL, NULL,
-                  _gtk_marshal_VOID__ENUM_BOOLEAN,
-                  G_TYPE_NONE, 2,
+                  _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
+                  G_TYPE_BOOLEAN, 2,
                   GTK_TYPE_DIRECTION_TYPE,
                  G_TYPE_BOOLEAN);
   /**
@@ -831,7 +919,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
    * Since: 2.10
    **/
   notebook_signals[PAGE_REORDERED] =
-    g_signal_new (I_("page_reordered"),
+    g_signal_new (I_("page-reordered"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST,
                   0, NULL, NULL,
@@ -851,7 +939,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
    * Since: 2.10
    **/
   notebook_signals[PAGE_REMOVED] =
-    g_signal_new (I_("page_removed"),
+    g_signal_new (I_("page-removed"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST,
                   0, NULL, NULL,
@@ -871,7 +959,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
    * Since: 2.10
    **/
   notebook_signals[PAGE_ADDED] =
-    g_signal_new (I_("page_added"),
+    g_signal_new (I_("page-added"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST,
                   0, NULL, NULL,
@@ -880,49 +968,82 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
 
+  /**
+   * GtkNotebook::create-window:
+   * @notebook: the #GtkNotebook emitting the signal
+   * @page: the tab of @notebook that is being detached
+   * @x: the X coordinate where the drop happens
+   * @y: the Y coordinate where the drop happens
+   *
+   * The ::create-window signal is emitted when a detachable
+   * tab is dropped on the root window. 
+   *
+   * A handler for this signal can create a window containing 
+   * a notebook where the tab will be attached. It is also 
+   * responsible for moving/resizing the window and adding the 
+   * necessary properties to the notebook (e.g. the 
+   * #GtkNotebook:group-id ).
+   *
+   * The default handler uses the global window creation hook,
+   * if one has been set with gtk_notebook_set_window_creation_hook().
+   *
+   * Returns: a #GtkNotebook that @page should be added to, or %NULL.
+   *
+   * Since: 2.12
+   */
+  notebook_signals[CREATE_WINDOW] = 
+    g_signal_new (I_("create-window"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkNotebookClass, create_window),
+                  gtk_object_handled_accumulator, NULL,
+                  _gtk_marshal_OBJECT__OBJECT_INT_INT,
+                  GTK_TYPE_NOTEBOOK, 3,
+                  GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
   binding_set = gtk_binding_set_by_class (class);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_space, 0,
-                                "select_page", 1, 
+                                "select-page", 1, 
                                 G_TYPE_BOOLEAN, FALSE);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_KP_Space, 0,
-                                "select_page", 1, 
+                                "select-page", 1, 
                                 G_TYPE_BOOLEAN, FALSE);
   
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_Home, 0,
-                                "focus_tab", 1, 
+                                "focus-tab", 1, 
                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_KP_Home, 0,
-                                "focus_tab", 1, 
+                                "focus-tab", 1, 
                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_End, 0,
-                                "focus_tab", 1, 
+                                "focus-tab", 1, 
                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_KP_End, 0,
-                                "focus_tab", 1, 
+                                "focus-tab", 1, 
                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
 
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_Page_Up, GDK_CONTROL_MASK,
-                                "change_current_page", 1,
+                                "change-current-page", 1,
                                 G_TYPE_INT, -1);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_Page_Down, GDK_CONTROL_MASK,
-                                "change_current_page", 1,
+                                "change-current-page", 1,
                                 G_TYPE_INT, 1);
 
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
-                                "change_current_page", 1,
+                                "change-current-page", 1,
                                 G_TYPE_INT, -1);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
-                                "change_current_page", 1,
+                                "change-current-page", 1,
                                 G_TYPE_INT, 1);
 
   add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
@@ -982,30 +1103,70 @@ gtk_notebook_init (GtkNotebook *notebook)
   notebook->has_after_previous  = 0;
   notebook->has_after_next      = 1;
 
-  priv->group_id = -1;
+  priv->group = NULL;
   priv->pressed_button = -1;
   priv->dnd_timer = 0;
   priv->switch_tab_timer = 0;
-  priv->source_targets = gtk_target_list_new (notebook_source_targets,
-                                             G_N_ELEMENTS (notebook_source_targets));
+  priv->source_targets = gtk_target_list_new (notebook_targets,
+                                             G_N_ELEMENTS (notebook_targets));
   priv->operation = DRAG_OPERATION_NONE;
   priv->detached_tab = NULL;
   priv->during_detach = FALSE;
   priv->has_scrolled = FALSE;
 
-  gtk_drag_dest_set (GTK_WIDGET (notebook),
-                    GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
-                    notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
+  gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
+                    notebook_targets, G_N_ELEMENTS (notebook_targets),
                      GDK_ACTION_MOVE);
 
+  g_signal_connect (G_OBJECT (notebook), "drag-failed",
+                   G_CALLBACK (gtk_notebook_drag_failed), NULL);
+
   gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
 }
 
+static void
+gtk_notebook_buildable_init (GtkBuildableIface *iface)
+{
+  iface->add_child = gtk_notebook_buildable_add_child;
+}
+
+static void
+gtk_notebook_buildable_add_child (GtkBuildable  *buildable,
+                                 GtkBuilder    *builder,
+                                 GObject       *child,
+                                 const gchar   *type)
+{
+  GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
+
+  if (type && strcmp (type, "tab") == 0)
+    {
+      GtkWidget * page;
+
+      page = gtk_notebook_get_nth_page (notebook, -1);
+      /* To set the tab label widget, we must have already a child
+       * inside the tab container. */
+      g_assert (page != NULL);
+      gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
+    }
+  else if (type && strcmp (type, "action-start") == 0)
+    {
+      gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
+    }
+  else if (type && strcmp (type, "action-end") == 0)
+    {
+      gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
+    }
+  else if (!type)
+    gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
+  else
+    GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
+}
+
 static gboolean
 gtk_notebook_select_page (GtkNotebook *notebook,
                           gboolean     move_focus)
 {
-  if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
+  if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
     {
       gtk_notebook_page_select (notebook, move_focus);
       return TRUE;
@@ -1020,7 +1181,7 @@ gtk_notebook_focus_tab (GtkNotebook       *notebook,
 {
   GList *list;
 
-  if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
+  if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
     {
       switch (type)
        {
@@ -1042,25 +1203,49 @@ gtk_notebook_focus_tab (GtkNotebook       *notebook,
     return FALSE;
 }
 
-static void
+static gboolean
 gtk_notebook_change_current_page (GtkNotebook *notebook,
                                  gint         offset)
 {
   GList *current = NULL;
 
+  if (!notebook->show_tabs)
+    return FALSE;
+
   if (notebook->cur_page)
     current = g_list_find (notebook->children, notebook->cur_page);
 
   while (offset != 0)
     {
-      current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
+      current = gtk_notebook_search_page (notebook, current,
+                                          offset < 0 ? STEP_PREV : STEP_NEXT,
+                                          TRUE);
+
+      if (!current)
+        {
+          gboolean wrap_around;
+
+          g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
+                        "gtk-keynav-wrap-around", &wrap_around,
+                        NULL);
+
+          if (wrap_around)
+            current = gtk_notebook_search_page (notebook, NULL,
+                                                offset < 0 ? STEP_PREV : STEP_NEXT,
+                                                TRUE);
+          else
+            break;
+        }
+
       offset += offset < 0 ? 1 : -1;
     }
 
   if (current)
-    gtk_notebook_switch_page (notebook, current->data, -1);
+    gtk_notebook_switch_page (notebook, current->data);
   else
-    gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
+    gtk_widget_error_bell (GTK_WIDGET (notebook));
+
+  return TRUE;
 }
 
 static GtkDirectionType
@@ -1152,13 +1337,13 @@ gtk_notebook_move_focus_out (GtkNotebook      *notebook,
    * do this by setting a flag, then propagating the focus motion to the notebook.
    */
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
-  if (!GTK_WIDGET_TOPLEVEL (toplevel))
+  if (!gtk_widget_is_toplevel (toplevel))
     return;
 
   g_object_ref (notebook);
   
   notebook->focus_out = TRUE;
-  g_signal_emit_by_name (toplevel, "move_focus", direction_type);
+  g_signal_emit_by_name (toplevel, "move-focus", direction_type);
   notebook->focus_out = FALSE;
   
   g_object_unref (notebook);
@@ -1208,7 +1393,7 @@ reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
   return g_list_position (notebook->children, tab);
 }
 
-static void
+static gboolean
 gtk_notebook_reorder_tab (GtkNotebook      *notebook,
                          GtkDirectionType  direction_type,
                          gboolean          move_to_last)
@@ -1218,13 +1403,16 @@ gtk_notebook_reorder_tab (GtkNotebook      *notebook,
   GList *last, *child;
   gint page_num;
 
+  if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
+    return FALSE;
+
   if (!notebook->cur_page ||
       !notebook->cur_page->reorderable)
-    return;
+    return FALSE;
 
   if (effective_direction != GTK_DIR_LEFT &&
       effective_direction != GTK_DIR_RIGHT)
-    return;
+    return FALSE;
 
   if (move_to_last)
     {
@@ -1247,7 +1435,7 @@ gtk_notebook_reorder_tab (GtkNotebook      *notebook,
                                      TRUE);
 
   if (!child || child->data == notebook->cur_page)
-    return;
+    return FALSE;
 
   page = child->data;
 
@@ -1265,7 +1453,11 @@ gtk_notebook_reorder_tab (GtkNotebook      *notebook,
                     0,
                     ((GtkNotebookPage *) notebook->focus_tab->data)->child,
                     page_num);
+
+      return TRUE;
     }
+
+  return FALSE;
 }
 
 /**
@@ -1292,7 +1484,7 @@ gtk_notebook_destroy (GtkObject *object)
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (object);
   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  
+
   if (notebook->menu)
     gtk_notebook_popup_disable (notebook);
 
@@ -1359,7 +1551,11 @@ gtk_notebook_set_property (GObject         *object,
     case PROP_GROUP_ID:
       gtk_notebook_set_group_id (notebook, g_value_get_int (value));
       break;
+    case PROP_GROUP:
+      gtk_notebook_set_group (notebook, g_value_get_pointer (value));
+      break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
@@ -1406,7 +1602,10 @@ gtk_notebook_get_property (GObject         *object,
       g_value_set_uint (value, notebook->tab_vborder);
       break;
     case PROP_GROUP_ID:
-      g_value_set_int (value, priv->group_id);
+      g_value_set_int (value, gtk_notebook_get_group_id (notebook));
+      break;
+    case PROP_GROUP:
+      g_value_set_pointer (value, priv->group);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1426,7 +1625,6 @@ gtk_notebook_get_property (GObject         *object,
  * gtk_notebook_button_press
  * gtk_notebook_button_release
  * gtk_notebook_popup_menu
- * gtk_notebook_enter_notify
  * gtk_notebook_leave_notify
  * gtk_notebook_motion_notify
  * gtk_notebook_focus_in
@@ -1434,6 +1632,8 @@ gtk_notebook_get_property (GObject         *object,
  * gtk_notebook_draw_focus
  * gtk_notebook_style_set
  * gtk_notebook_drag_begin
+ * gtk_notebook_drag_end
+ * gtk_notebook_drag_failed
  * gtk_notebook_drag_motion
  * gtk_notebook_drag_drop
  * gtk_notebook_drag_data_get
@@ -1443,11 +1643,14 @@ static gboolean
 gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
                                        GdkRectangle *rectangle)
 {
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
   GtkWidget *widget = GTK_WIDGET (notebook);
   gint border_width = GTK_CONTAINER (notebook)->border_width;
   GtkNotebookPage *visible_page = NULL;
   GList *tmp_list;
   gint tab_pos = get_effective_tab_pos (notebook);
+  gboolean is_rtl;
+  gint i;
 
   for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
     {
@@ -1463,9 +1666,10 @@ gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
     {
       if (rectangle)
        {
+         is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
          rectangle->x = widget->allocation.x + border_width;
          rectangle->y = widget->allocation.y + border_width;
-         
+
          switch (tab_pos)
            {
            case GTK_POS_TOP:
@@ -1474,6 +1678,18 @@ gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
              rectangle->height = visible_page->requisition.height;
              if (tab_pos == GTK_POS_BOTTOM)
                rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
+
+              for (i = 0; i < N_ACTION_WIDGETS; i++)
+                {
+                  if (priv->action_widget[i] &&
+                      GTK_WIDGET_VISIBLE (priv->action_widget[i]))
+                    {
+                      rectangle->width -= priv->action_widget[i]->allocation.width;
+                      if ((!is_rtl && i == ACTION_WIDGET_START) ||
+                          (is_rtl && i == ACTION_WIDGET_END))
+                        rectangle->x += priv->action_widget[i]->allocation.width;
+                    }
+                }
              break;
            case GTK_POS_LEFT:
            case GTK_POS_RIGHT:
@@ -1481,7 +1697,19 @@ gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
              rectangle->height = widget->allocation.height - 2 * border_width;
              if (tab_pos == GTK_POS_RIGHT)
                rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
-             break;
+
+              for (i = 0; i < N_ACTION_WIDGETS; i++)
+                {
+                  if (priv->action_widget[i] &&
+                      GTK_WIDGET_VISIBLE (priv->action_widget[i]))
+                    {
+                      rectangle->height -= priv->action_widget[i]->allocation.height;
+
+                      if (i == ACTION_WIDGET_START)
+                        rectangle->y += priv->action_widget[i]->allocation.height;
+                    }
+                }
+              break;
            }
        }
 
@@ -1502,21 +1730,33 @@ gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
 static void
 gtk_notebook_map (GtkWidget *widget)
 {
+  GtkNotebookPrivate *priv;
   GtkNotebook *notebook;
   GtkNotebookPage *page;
   GList *children;
-
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
+  gint i;
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
   notebook = GTK_NOTEBOOK (widget);
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
 
   if (notebook->cur_page && 
       GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
       !GTK_WIDGET_MAPPED (notebook->cur_page->child))
     gtk_widget_map (notebook->cur_page->child);
 
+  if (notebook->show_tabs)
+  {
+    for (i = 0; i < 2; i++)
+    {
+      if (priv->action_widget[i] &&
+          GTK_WIDGET_VISIBLE (priv->action_widget[i]) &&
+          !GTK_WIDGET_MAPPED (priv->action_widget[i]))
+        gtk_widget_map (priv->action_widget[i]);
+    }
+  }
+    
   if (notebook->scrollable)
     gtk_notebook_pages_allocate (notebook);
   else
@@ -1542,8 +1782,6 @@ gtk_notebook_map (GtkWidget *widget)
 static void
 gtk_notebook_unmap (GtkWidget *widget)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   stop_scrolling (GTK_NOTEBOOK (widget));
   
   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
@@ -1561,8 +1799,6 @@ gtk_notebook_realize (GtkWidget *widget)
   gint attributes_mask;
   GdkRectangle event_window_pos;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
 
@@ -1580,7 +1816,7 @@ gtk_notebook_realize (GtkWidget *widget)
   attributes.event_mask = gtk_widget_get_events (widget);
   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
                            GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
-                           GDK_BUTTON1_MOTION_MASK |
+                           GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
                            GDK_SCROLL_MASK);
   attributes_mask = GDK_WA_X | GDK_WA_Y;
 
@@ -1597,8 +1833,6 @@ gtk_notebook_unrealize (GtkWidget *widget)
   GtkNotebook *notebook;
   GtkNotebookPrivate *priv;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
 
@@ -1613,18 +1847,19 @@ gtk_notebook_unrealize (GtkWidget *widget)
       priv->drag_window = NULL;
     }
 
-  if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
+  GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
 }
 
 static void
 gtk_notebook_size_request (GtkWidget      *widget,
                           GtkRequisition *requisition)
 {
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   GtkNotebookPage *page;
   GList *children;
   GtkRequisition child_requisition;
+  GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
   gboolean switch_page = FALSE;
   gint vis_pages;
   gint focus_width;
@@ -1635,7 +1870,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
   gint scroll_arrow_vlength;
 
   gtk_widget_style_get (widget,
-                       "focus-line-width", &focus_width,
+                        "focus-line-width", &focus_width,
                        "tab-overlap", &tab_overlap,
                        "tab-curvature", &tab_curvature,
                         "arrow-spacing", &arrow_spacing,
@@ -1686,6 +1921,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
          gint tab_height = 0;
          gint tab_max = 0;
          gint padding;
+          gint i;
          
          for (children = notebook->children; children;
               children = children->next)
@@ -1733,6 +1969,16 @@ gtk_notebook_size_request (GtkWidget      *widget,
 
          if (vis_pages)
            {
+              for (i = 0; i < N_ACTION_WIDGETS; i++)
+                {
+                  if (priv->action_widget[i])
+                    {
+                      gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
+                      action_widget_requisition[i].width += widget->style->xthickness;
+                      action_widget_requisition[i].height += widget->style->ythickness;
+                    }
+                }
+
              switch (notebook->tab_pos)
                {
                case GTK_POS_TOP:
@@ -1744,6 +1990,9 @@ gtk_notebook_size_request (GtkWidget      *widget,
                      widget->requisition.width < tab_width)
                    tab_height = MAX (tab_height, scroll_arrow_hlength);
 
+                  tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
+                  tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
+
                  padding = 2 * (tab_curvature + focus_width +
                                 notebook->tab_hborder) - tab_overlap;
                  tab_max += padding;
@@ -1776,6 +2025,8 @@ gtk_notebook_size_request (GtkWidget      *widget,
                     widget->requisition.width = MAX (widget->requisition.width,
                                                      tab_width + tab_overlap);
 
+                 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_START].width;
+                 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_END].width;
                  widget->requisition.height += tab_height;
                  break;
                case GTK_POS_LEFT:
@@ -1788,6 +2039,9 @@ gtk_notebook_size_request (GtkWidget      *widget,
                    tab_width = MAX (tab_width,
                                      arrow_spacing + 2 * scroll_arrow_vlength);
 
+                 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
+                 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
+
                  padding = 2 * (tab_curvature + focus_width +
                                 notebook->tab_vborder) - tab_overlap;
                  tab_max += padding;
@@ -1800,7 +2054,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
                      if (!GTK_WIDGET_VISIBLE (page->child))
                        continue;
 
-                     page->requisition.width   = tab_width;
+                     page->requisition.width = tab_width;
 
                      if (notebook->homogeneous)
                        page->requisition.height = tab_max;
@@ -1812,9 +2066,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
 
                  if (notebook->scrollable && vis_pages > 1 && 
                      widget->requisition.height < tab_height)
-                   tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
-
-                 widget->requisition.width += tab_width;
+                   tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
 
                   if (notebook->homogeneous && !notebook->scrollable)
                     widget->requisition.height =
@@ -1830,6 +2082,10 @@ gtk_notebook_size_request (GtkWidget      *widget,
                  widget->requisition.height = MAX (widget->requisition.height,
                                                    vis_pages * tab_max +
                                                    tab_overlap);
+
+                 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_START].height;
+                 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_END].height;
+                 widget->requisition.width += tab_width;
                  break;
                }
            }
@@ -1860,7 +2116,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
              page = children->data;
              if (GTK_WIDGET_VISIBLE (page->child))
                {
-                 gtk_notebook_switch_page (notebook, page, -1);
+                 gtk_notebook_switch_page (notebook, page);
                  break;
                }
            }
@@ -1877,7 +2133,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
       if (children)
        {
          notebook->first_tab = children;
-         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
+         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
        }
     }
 }
@@ -1886,9 +2142,14 @@ static void
 gtk_notebook_size_allocate (GtkWidget     *widget,
                            GtkAllocation *allocation)
 {
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   gint tab_pos = get_effective_tab_pos (notebook);
+  gboolean is_rtl;
+  gint focus_width;
 
+  gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
+  
   widget->allocation = *allocation;
   if (GTK_WIDGET_REALIZED (widget))
     {
@@ -1912,6 +2173,7 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
       GtkNotebookPage *page;
       GtkAllocation child_allocation;
       GList *children;
+      gint i;
       
       child_allocation.x = widget->allocation.x + border_width;
       child_allocation.y = widget->allocation.y + border_width;
@@ -1946,6 +2208,55 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
                         notebook->cur_page->requisition.width);
                  break;
                }
+
+              for (i = 0; i < N_ACTION_WIDGETS; i++)
+                {
+                  GtkAllocation widget_allocation;
+
+                  if (!priv->action_widget[i])
+                    continue;
+
+                 widget_allocation.x = widget->allocation.x + border_width;
+                 widget_allocation.y = widget->allocation.y + border_width;
+                 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+                 switch (tab_pos)
+                   {
+                   case GTK_POS_BOTTOM:
+                     widget_allocation.y +=
+                       widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
+                     /* fall through */
+                   case GTK_POS_TOP:
+                     widget_allocation.width = priv->action_widget[i]->requisition.width;
+                     widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
+
+                     if ((i == ACTION_WIDGET_START && is_rtl) ||
+                          (i == ACTION_WIDGET_END && !is_rtl))
+                       widget_allocation.x +=
+                         widget->allocation.width - 2 * border_width -
+                         priv->action_widget[i]->requisition.width;
+                      if (tab_pos == GTK_POS_TOP) /* no fall through */
+                          widget_allocation.y += 2 * focus_width;
+                     break;
+                   case GTK_POS_RIGHT:
+                     widget_allocation.x +=
+                       widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
+                     /* fall through */
+                   case GTK_POS_LEFT:
+                     widget_allocation.height = priv->action_widget[i]->requisition.height;
+                     widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
+
+                      if (i == ACTION_WIDGET_END)
+                        widget_allocation.y +=
+                          widget->allocation.height - 2 * border_width -
+                          priv->action_widget[i]->requisition.height;
+                      if (tab_pos == GTK_POS_LEFT) /* no fall through */  
+                        widget_allocation.x += 2 * focus_width;
+                     break;
+                   }
+
+                 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
+               }
            }
        }
 
@@ -1969,10 +2280,7 @@ gtk_notebook_expose (GtkWidget      *widget,
 {
   GtkNotebook *notebook;
   GtkNotebookPrivate *priv;
-  GdkRectangle child_area;
-
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  gint i;
 
   notebook = GTK_NOTEBOOK (widget);
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
@@ -1980,29 +2288,66 @@ gtk_notebook_expose (GtkWidget      *widget,
   if (event->window == priv->drag_window)
     {
       GdkRectangle area = { 0, };
+      cairo_t *cr;
+
+      /* FIXME: This is a workaround to make tabs reordering work better
+       * with engines with rounded tabs. If the drag window background
+       * isn't set, the rounded corners would be black.
+       *
+       * Ideally, these corners should be made transparent, Either by using
+       * ARGB visuals or shape windows.
+       */
+      cr = gdk_cairo_create (priv->drag_window);
+      gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
+      cairo_paint (cr);
+      cairo_destroy (cr);
 
       gdk_drawable_get_size (priv->drag_window,
                             &area.width, &area.height);
       gtk_notebook_draw_tab (notebook,
                             notebook->cur_page,
                             &area);
+      gtk_notebook_draw_focus (widget, event);
+      gtk_container_propagate_expose (GTK_CONTAINER (notebook),
+                                     notebook->cur_page->tab_label, event);
     }
   else if (GTK_WIDGET_DRAWABLE (widget))
     {
       gtk_notebook_paint (widget, &event->area);
       if (notebook->show_tabs)
        {
-         if (notebook->cur_page && 
-             gtk_widget_intersect (notebook->cur_page->tab_label, 
-                                   &event->area, &child_area))
-           gtk_notebook_draw_focus (widget);
+         GtkNotebookPage *page;
+         GList *pages;
+
+         gtk_notebook_draw_focus (widget, event);
+         pages = notebook->children;
+
+         while (pages)
+           {
+             page = GTK_NOTEBOOK_PAGE (pages);
+             pages = pages->next;
+
+             if (page->tab_label->window == event->window &&
+                 GTK_WIDGET_DRAWABLE (page->tab_label))
+               gtk_container_propagate_expose (GTK_CONTAINER (notebook),
+                                               page->tab_label, event);
+           }
        }
 
-      
       if (notebook->cur_page)
        gtk_container_propagate_expose (GTK_CONTAINER (notebook),
                                        notebook->cur_page->child,
                                        event);
+      if (notebook->show_tabs)
+      {
+        for (i = 0; i < N_ACTION_WIDGETS; i++)
+        {
+          if (priv->action_widget[i] &&
+              GTK_WIDGET_DRAWABLE (priv->action_widget[i]))
+            gtk_container_propagate_expose (GTK_CONTAINER (notebook),
+                                            priv->action_widget[i], event);
+        }
+      }
     }
 
   return FALSE;
@@ -2137,7 +2482,6 @@ gtk_notebook_do_arrow (GtkNotebook     *notebook,
                       GtkNotebookArrow arrow)
 {
   GtkWidget *widget = GTK_WIDGET (notebook);
-  GtkDirectionType dir;
   gboolean is_rtl, left;
 
   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
@@ -2149,12 +2493,8 @@ gtk_notebook_do_arrow (GtkNotebook     *notebook,
                                left ? STEP_PREV : STEP_NEXT,
                                TRUE))
     {
-      if (notebook->tab_pos == GTK_POS_LEFT ||
-         notebook->tab_pos == GTK_POS_RIGHT)
-       dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
-      else
-       dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
-      gtk_widget_child_focus (widget, dir);
+      gtk_notebook_change_current_page (notebook, left ? -1 : 1);
+      gtk_widget_grab_focus (widget);
     }
 }
 
@@ -2230,21 +2570,29 @@ static gboolean
 gtk_notebook_scroll (GtkWidget      *widget,
                      GdkEventScroll *event)
 {
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-
-  GtkWidget* child;
-  GtkWidget* originator;
+  GtkWidget *child, *event_widget;
+  gint i;
 
   if (!notebook->cur_page)
     return FALSE;
 
   child = notebook->cur_page->child;
-  originator = gtk_get_event_widget ((GdkEvent *)event);
+  event_widget = gtk_get_event_widget ((GdkEvent *)event);
 
   /* ignore scroll events from the content of the page */
-  if (!originator || gtk_widget_is_ancestor (originator, child))
+  if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
     return FALSE;
-  
+
+  /* nor from the action area */
+  for (i = 0; i < 2; i++)
+    {
+      if (event_widget == priv->action_widget[i] ||
+          gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
+        return FALSE;
+    }
+
   switch (event->direction)
     {
     case GDK_SCROLL_RIGHT:
@@ -2325,21 +2673,27 @@ gtk_notebook_button_press (GtkWidget      *widget,
       page = tab->data;
       page_changed = page != notebook->cur_page;
       was_focus = gtk_widget_is_focus (widget);
-         
+
       gtk_notebook_switch_focus_tab (notebook, tab);
       gtk_widget_grab_focus (widget);
-         
+
       if (page_changed && !was_focus)
        gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
-         
+
       /* save press to possibly begin a drag */
       if (page->reorderable || page->detachable)
        {
          priv->during_detach = FALSE;
+         priv->during_reorder = FALSE;
          priv->pressed_button = event->button;
 
-         priv->mouse_x = x - widget->allocation.x;
-         priv->mouse_y = y - widget->allocation.y;
+         priv->mouse_x = x;
+         priv->mouse_y = y;
+
+         priv->drag_begin_x = priv->mouse_x;
+         priv->drag_begin_y = priv->mouse_y;
+         priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
+         priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
        }
     }
 
@@ -2424,8 +2778,8 @@ get_drop_position (GtkNotebook *notebook,
   gint x, y;
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  x = priv->mouse_x + GTK_WIDGET (notebook)->allocation.x;
-  y = priv->mouse_y + GTK_WIDGET (notebook)->allocation.y;
+  x = priv->mouse_x;
+  y = priv->mouse_y;
 
   is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
   children = notebook->children;
@@ -2545,7 +2899,6 @@ hide_drag_window (GtkNotebook        *notebook,
       else
        gtk_widget_unparent (page->tab_label);
 
-      gtk_widget_set_parent_window (page->tab_label, widget->window);
       gtk_widget_set_parent (page->tab_label, widget);
       g_object_unref (page->tab_label);
     }
@@ -2555,44 +2908,43 @@ hide_drag_window (GtkNotebook        *notebook,
     gdk_window_hide (priv->drag_window);
 }
 
-static gint
-gtk_notebook_button_release (GtkWidget      *widget,
-                            GdkEventButton *event)
+static void
+gtk_notebook_stop_reorder (GtkNotebook *notebook)
 {
-  GtkNotebook *notebook;
   GtkNotebookPrivate *priv;
   GtkNotebookPage *page;
-  GList *element;
-  gint old_page_num, page_num;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
 
-  if (event->type != GDK_BUTTON_RELEASE)
-    return FALSE;
+  if (priv->operation == DRAG_OPERATION_DETACH)
+    page = priv->detached_tab;
+  else
+    page = notebook->cur_page;
 
-  notebook = GTK_NOTEBOOK (widget);
-  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  page = notebook->cur_page;
+  if (!page || !page->tab_label)
+    return;
 
-  if (page->reorderable &&
-      event->button == priv->pressed_button)
-    {
-      priv->pressed_button = -1;
+  priv->pressed_button = -1;
 
-      if (!priv->during_detach)
+  if (page->reorderable || page->detachable)
+    {
+      if (priv->during_reorder)
        {
+         gint old_page_num, page_num;
+         GList *element;
+
          element = get_drop_position (notebook, page->pack);
          old_page_num = g_list_position (notebook->children, notebook->focus_tab);
          page_num = reorder_tab (notebook, element, notebook->focus_tab);
-
-         if (priv->has_scrolled ||
-             old_page_num != page_num)
+          gtk_notebook_child_reordered (notebook, page);
+          
+         if (priv->has_scrolled || old_page_num != page_num)
            g_signal_emit (notebook,
                           notebook_signals[PAGE_REORDERED], 0,
                           page->child, page_num);
 
          priv->has_scrolled = FALSE;
+          priv->during_reorder = FALSE; 
        }
 
       hide_drag_window (notebook, priv, page);
@@ -2606,43 +2958,35 @@ gtk_notebook_button_release (GtkWidget      *widget,
          priv->dnd_timer = 0;
        }
     }
-
-  if (event->button == notebook->button)
-    {
-      stop_scrolling (notebook);
-      return TRUE;
-    }
-  else
-    return FALSE;
 }
 
 static gint
-gtk_notebook_enter_notify (GtkWidget        *widget,
-                          GdkEventCrossing *event)
+gtk_notebook_button_release (GtkWidget      *widget,
+                            GdkEventButton *event)
 {
   GtkNotebook *notebook;
-  GtkNotebookArrow arrow;
-  gint x, y;
+  GtkNotebookPrivate *priv;
+  GtkNotebookPage *page;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  if (event->type != GDK_BUTTON_RELEASE)
+    return FALSE;
 
   notebook = GTK_NOTEBOOK (widget);
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+  page = notebook->cur_page;
 
-  if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
-    return FALSE;
-
-  arrow = gtk_notebook_get_arrow (notebook, x, y);
+  if (!priv->during_detach &&
+      page->reorderable &&
+      event->button == priv->pressed_button)
+    gtk_notebook_stop_reorder (notebook);
 
-  if (arrow != notebook->in_child)
+  if (event->button == notebook->button)
     {
-      notebook->in_child = arrow;
-      gtk_notebook_redraw_arrows (notebook);
-
+      stop_scrolling (notebook);
       return TRUE;
     }
-
-  return TRUE;
+  else
+    return FALSE;
 }
 
 static gint
@@ -2668,30 +3012,39 @@ static GtkNotebookPointerPosition
 get_pointer_position (GtkNotebook *notebook)
 {
   GtkWidget *widget = (GtkWidget *) notebook;
-  GtkContainer *container = (GtkContainer *) notebook;
   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+  gint wx, wy, width, height;
   gboolean is_rtl;
 
   if (!notebook->scrollable)
     return POINTER_BETWEEN;
 
+  gdk_window_get_position (notebook->event_window, &wx, &wy);
+  gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
+
   if (notebook->tab_pos == GTK_POS_TOP ||
       notebook->tab_pos == GTK_POS_BOTTOM)
     {
+      gint x;
+
       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+      x = priv->mouse_x - wx;
 
-      if (priv->mouse_x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
+      if (x > width - SCROLL_THRESHOLD)
        return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
-      else if (priv->mouse_x < SCROLL_THRESHOLD + container->border_width)
+      else if (x < SCROLL_THRESHOLD)
        return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
       else
        return POINTER_BETWEEN;
     }
   else
     {
-      if (priv->mouse_y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
+      gint y;
+
+      y = priv->mouse_y - wy;
+      if (y > height - SCROLL_THRESHOLD)
        return POINTER_AFTER;
-      else if (priv->mouse_y < SCROLL_THRESHOLD + container->border_width)
+      else if (y < SCROLL_THRESHOLD)
        return POINTER_BEFORE;
       else
        return POINTER_BETWEEN;
@@ -2768,26 +3121,49 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
   GtkNotebookPage *page;
+  GtkNotebookArrow arrow;
   GtkNotebookPointerPosition pointer_position;
   GtkSettings *settings;
   guint timeout;
+  gint x_win, y_win;
 
-  if (priv->pressed_button == -1)
+  page = notebook->cur_page;
+
+  if (!page)
     return FALSE;
 
-  if (!notebook->cur_page)
+  if (!(event->state & GDK_BUTTON1_MASK) &&
+      priv->pressed_button != -1)
+    {
+      gtk_notebook_stop_reorder (notebook);
+      stop_scrolling (notebook);
+    }
+
+  if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
     return FALSE;
 
-  page = notebook->cur_page;
+  priv->timestamp = event->time;
+
+  /* While animating the move, event->x is relative to the flying tab
+   * (priv->drag_window has a pointer grab), but we need coordinates relative to
+   * the notebook widget.
+   */
+  gdk_window_get_origin (widget->window, &x_win, &y_win);
+  priv->mouse_x = event->x_root - x_win;
+  priv->mouse_y = event->y_root - y_win;
+
+  arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
+  if (arrow != notebook->in_child)
+    {
+      notebook->in_child = arrow;
+      gtk_notebook_redraw_arrows (notebook);
+    }
 
-  get_widget_coordinates (widget, (GdkEvent*) event, &priv->mouse_x, &priv->mouse_y);
-  priv->mouse_x -= widget->allocation.x;
-  priv->mouse_y -= widget->allocation.y;
+  if (priv->pressed_button == -1)
+    return FALSE;
 
   if (page->detachable &&
-      check_threshold (notebook,
-                      priv->mouse_x + widget->allocation.x,
-                      priv->mouse_y + widget->allocation.y))
+      check_threshold (notebook, priv->mouse_x, priv->mouse_y))
     {
       priv->detached_tab = notebook->cur_page;
       priv->during_detach = TRUE;
@@ -2797,8 +3173,11 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
       return TRUE;
     }
 
-  if (page->reorderable)
+  if (page->reorderable &&
+      (priv->during_reorder ||
+       gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
     {
+      priv->during_reorder = TRUE;
       pointer_position = get_pointer_position (notebook);
 
       if (event->window == priv->drag_window &&
@@ -2812,8 +3191,8 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
              settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
              g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
 
-             priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
-                                              (GSourceFunc) scroll_notebook_timer, 
+             priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
+                                              scroll_notebook_timer, 
                                               (gpointer) notebook);
            }
        }
@@ -2832,8 +3211,8 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
          /* the drag operation is beginning, create the window */
          if (priv->operation != DRAG_OPERATION_REORDER)
            {
-             show_drag_window (notebook, priv, page);
              priv->operation = DRAG_OPERATION_REORDER;
+             show_drag_window (notebook, priv, page);
            }
 
          gtk_notebook_pages_allocate (notebook);
@@ -2852,8 +3231,13 @@ static void
 gtk_notebook_grab_notify (GtkWidget *widget,
                          gboolean   was_grabbed)
 {
+  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+
   if (!was_grabbed)
-    stop_scrolling (GTK_NOTEBOOK (widget));
+    {
+      gtk_notebook_stop_reorder (notebook);
+      stop_scrolling (notebook);
+    }
 }
 
 static void
@@ -2868,8 +3252,6 @@ static gint
 gtk_notebook_focus_in (GtkWidget     *widget,
                       GdkEventFocus *event)
 {
-  GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
-
   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
   
   return FALSE;
@@ -2885,27 +3267,35 @@ gtk_notebook_focus_out (GtkWidget     *widget,
 }
 
 static void
-gtk_notebook_draw_focus (GtkWidget *widget)
+gtk_notebook_draw_focus (GtkWidget      *widget,
+                        GdkEventExpose *event)
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
 
-  if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
-      notebook->focus_tab)
+  if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
+      notebook->show_tabs && notebook->cur_page &&
+      notebook->cur_page->tab_label->window == event->window)
     {
       GtkNotebookPage *page;
-      GdkRectangle area;
-      gint focus_width;
-      
-      gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
 
-      page = notebook->focus_tab->data;
+      page = notebook->cur_page;
+
+      if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
+        {
+          GdkRectangle area;
+          gint focus_width;
 
-      area.x = page->tab_label->allocation.x - focus_width;
-      area.y = page->tab_label->allocation.y - focus_width;
-      area.width = page->tab_label->allocation.width + 2 * focus_width;
-      area.height = page->tab_label->allocation.height + 2 * focus_width;
+          gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
 
-      gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
+          area.x = page->tab_label->allocation.x - focus_width;
+          area.y = page->tab_label->allocation.y - focus_width;
+          area.width = page->tab_label->allocation.width + 2 * focus_width;
+          area.height = page->tab_label->allocation.height + 2 * focus_width;
+
+         gtk_paint_focus (widget->style, event->window, 
+                           GTK_WIDGET_STATE (widget), NULL, widget, "tab",
+                          area.x, area.y, area.width, area.height);
+        }
     }
 }
 
@@ -2933,8 +3323,8 @@ gtk_notebook_style_set  (GtkWidget *widget,
   notebook->has_before_next = has_before_next;
   notebook->has_after_previous = has_after_previous;
   notebook->has_after_next = has_after_next;
-  
-  (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
+
+  GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
 }
 
 static gboolean
@@ -2969,8 +3359,7 @@ gtk_notebook_drag_begin (GtkWidget        *widget,
 {
   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   GtkNotebook *notebook = (GtkNotebook*) widget;
-  GtkWidget *tab_label, *window;
-  gint width, height;
+  GtkWidget *tab_label;
 
   if (priv->dnd_timer)
     {
@@ -2978,25 +3367,89 @@ gtk_notebook_drag_begin (GtkWidget        *widget,
       priv->dnd_timer = 0;
     }
 
+  priv->operation = DRAG_OPERATION_DETACH;
+  gtk_notebook_pages_allocate (notebook);
+
   tab_label = priv->detached_tab->tab_label;
-  gdk_drawable_get_size (priv->drag_window, &width, &height);
 
   hide_drag_window (notebook, priv, notebook->cur_page);
   g_object_ref (tab_label);
   gtk_widget_unparent (tab_label);
 
-  window = gtk_window_new (GTK_WINDOW_POPUP);
-  gtk_container_add (GTK_CONTAINER (window), tab_label);
-  gtk_widget_set_size_request (window, width, height);
+  priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
+                         gtk_widget_get_screen (widget));
+  gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
+  gtk_widget_set_size_request (priv->dnd_window,
+                              priv->detached_tab->allocation.width,
+                              priv->detached_tab->allocation.height);
   g_object_unref (tab_label);
 
-  g_signal_connect (G_OBJECT (window), "expose-event",
+  g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
                    G_CALLBACK (on_drag_icon_expose), notebook);
 
-  gtk_drag_set_icon_widget (context, window, -2, -2);
+  gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
+}
 
-  priv->operation = DRAG_OPERATION_DETACH;
-  gtk_notebook_pages_allocate (notebook);
+static void
+gtk_notebook_drag_end (GtkWidget      *widget,
+                      GdkDragContext *context)
+{
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+
+  gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
+
+  if (priv->detached_tab)
+    gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
+
+  GTK_BIN (priv->dnd_window)->child = NULL;
+  gtk_widget_destroy (priv->dnd_window);
+  priv->dnd_window = NULL;
+
+  priv->operation = DRAG_OPERATION_NONE;
+}
+
+static GtkNotebook *
+gtk_notebook_create_window (GtkNotebook *notebook,
+                            GtkWidget   *page,
+                            gint         x,
+                            gint         y)
+{
+  if (window_creation_hook)
+    return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
+
+  return NULL;
+}
+
+static gboolean
+gtk_notebook_drag_failed (GtkWidget      *widget,
+                         GdkDragContext *context,
+                         GtkDragResult   result,
+                         gpointer        data)
+{
+  if (result == GTK_DRAG_RESULT_NO_TARGET)
+    {
+      GtkNotebookPrivate *priv;
+      GtkNotebook *notebook, *dest_notebook = NULL;
+      GdkDisplay *display;
+      gint x, y;
+
+      notebook = GTK_NOTEBOOK (widget);
+      priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+      display = gtk_widget_get_display (widget);
+      gdk_display_get_pointer (display, NULL, &x, &y, NULL);
+
+      g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
+                     priv->detached_tab->child, x, y, &dest_notebook);
+
+      if (dest_notebook)
+       do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
+
+      return TRUE;
+    }
+
+  return FALSE;
 }
 
 static gboolean
@@ -3049,6 +3502,7 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
     {
       notebook->click_child = arrow;
       gtk_notebook_set_scroll_timer (notebook);
+      gdk_drag_status (context, 0, time);
       return TRUE;
     }
 
@@ -3058,35 +3512,35 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
 
   if (target == tab_target)
     {
-      gint widget_group, source_widget_group;
+      gpointer widget_group, source_widget_group;
       GtkWidget *source_widget;
 
       source_widget = gtk_drag_get_source_widget (context);
       g_assert (source_widget);
 
-      widget_group = gtk_notebook_get_group_id (notebook);
-      source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
+      widget_group = gtk_notebook_get_group (notebook);
+      source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
 
-      if (widget_group != -1 &&
-         source_widget_group != -1 &&
-         widget_group == source_widget_group)
+      if (widget_group && source_widget_group &&
+         widget_group == source_widget_group &&
+         !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child || 
+           gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
        {
          gdk_drag_status (context, GDK_ACTION_MOVE, time);
          return TRUE;
        }
+      else
+       {
+         /* it's a tab, but doesn't share
+          * ID with this notebook */
+         gdk_drag_status (context, 0, time);
+       }
     }
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   x += widget->allocation.x;
   y += widget->allocation.y;
 
-  if (target == tab_target)
-    {
-      /* it's a tab, but doesn't share
-       * ID with this notebook */
-      gdk_drag_status (context, 0, time);
-    }
-
   if (gtk_notebook_get_event_window_position (notebook, &position) &&
       x >= position.x && x <= position.x + position.width &&
       y >= position.y && y <= position.y + position.height)
@@ -3099,8 +3553,8 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
           settings = gtk_widget_get_settings (widget);
 
           g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
-         priv->switch_tab_timer = g_timeout_add (timeout,
-                                                 (GSourceFunc) gtk_notebook_switch_tab_timeout,
+         priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
+                                                 gtk_notebook_switch_tab_timeout,
                                                  widget);
        }
     }
@@ -3113,7 +3567,7 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
        }
     }
 
-  return TRUE;
+  return (target == tab_target) ? TRUE : FALSE;
 }
 
 static void
@@ -3141,14 +3595,18 @@ gtk_notebook_drag_drop (GtkWidget        *widget,
                        gint              y,
                        guint             time)
 {
-  GdkAtom target;
+  GdkAtom target, tab_target;
 
   target = gtk_drag_dest_find_target (widget, context, NULL);
+  tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
 
-  if (target == GDK_NONE)
-    gtk_drag_finish (context, FALSE, FALSE, time);
+  if (target == tab_target)
+    {
+      gtk_drag_get_data (widget, context, target, time);
+      return TRUE;
+    }
 
-  return TRUE;
+  return FALSE;
 }
 
 static void
@@ -3189,8 +3647,8 @@ do_detach_tab (GtkNotebook     *from,
   gtk_container_remove (GTK_CONTAINER (from), child);
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (to);
-  priv->mouse_x = x;
-  priv->mouse_y = y;
+  priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
+  priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
 
   element = get_drop_position (to, tab_pack);
   page_num = g_list_position (to->children, element);
@@ -3222,40 +3680,18 @@ gtk_notebook_drag_data_get (GtkWidget        *widget,
                            guint             info,
                            guint             time)
 {
-  GtkNotebook *dest_notebook, *notebook;
   GtkNotebookPrivate *priv;
 
-  if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
-      (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
-       !window_creation_hook))
-    return;
-
-  notebook = GTK_NOTEBOOK (widget);
-  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-
   if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
     {
+      priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+
       gtk_selection_data_set (data,
                              data->target,
                              8,
                              (void*) &priv->detached_tab->child,
                              sizeof (gpointer));
     }
-  else
-    {
-      GdkDisplay *display;
-      gint x, y;
-
-      display = gtk_widget_get_display (widget);
-      gdk_display_get_pointer (display, NULL, &x, &y, NULL);
-
-      dest_notebook = (* window_creation_hook) (notebook,
-                                               priv->detached_tab->child,
-                                               x, y,
-                                               window_creation_hook_data);
-      if (dest_notebook)
-       do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
-    }
 }
 
 static void
@@ -3395,7 +3831,7 @@ gtk_notebook_get_child_property (GtkContainer    *container,
     case CHILD_PROP_TAB_LABEL:
       label = gtk_notebook_get_tab_label (notebook, child);
 
-      if (label && GTK_IS_LABEL (label))
+      if (GTK_IS_LABEL (label))
        g_value_set_string (value, GTK_LABEL (label)->label);
       else
        g_value_set_string (value, NULL);
@@ -3403,7 +3839,7 @@ gtk_notebook_get_child_property (GtkContainer    *container,
     case CHILD_PROP_MENU_LABEL:
       label = gtk_notebook_get_menu_label (notebook, child);
 
-      if (label && GTK_IS_LABEL (label))
+      if (GTK_IS_LABEL (label))
        g_value_set_string (value, GTK_LABEL (label)->label);
       else
        g_value_set_string (value, NULL);
@@ -3444,8 +3880,6 @@ static void
 gtk_notebook_add (GtkContainer *container,
                  GtkWidget    *widget)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-
   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
                                 NULL, NULL, -1);
 }
@@ -3459,9 +3893,6 @@ gtk_notebook_remove (GtkContainer *container,
   GList *children;
   gint page_num = 0;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-  g_return_if_fail (widget != NULL);
-
   notebook = GTK_NOTEBOOK (container);
 
   children = notebook->children;
@@ -3518,17 +3949,30 @@ focus_tabs_move (GtkNotebook     *notebook,
 
   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
                                       search_direction, TRUE);
+  if (!new_page)
+    {
+      gboolean wrap_around;
+
+      g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
+                    "gtk-keynav-wrap-around", &wrap_around,
+                    NULL);
+
+      if (wrap_around)
+        new_page = gtk_notebook_search_page (notebook, NULL,
+                                             search_direction, TRUE);
+    }
+
   if (new_page)
     gtk_notebook_switch_focus_tab (notebook, new_page);
   else
-    gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
-  
+    gtk_widget_error_bell (GTK_WIDGET (notebook));
+
   return TRUE;
 }
 
 static gboolean
-focus_child_in (GtkNotebook     *notebook,
-               GtkDirectionType direction)
+focus_child_in (GtkNotebook      *notebook,
+               GtkDirectionType  direction)
 {
   if (notebook->cur_page)
     return gtk_widget_child_focus (notebook->cur_page->child, direction);
@@ -3536,24 +3980,52 @@ focus_child_in (GtkNotebook     *notebook,
     return FALSE;
 }
 
+static gboolean
+focus_action_in (GtkNotebook      *notebook,
+                 gint              action,
+                 GtkDirectionType  direction)
+{
+  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+  if (priv->action_widget[action] &&
+      GTK_WIDGET_VISIBLE (priv->action_widget[action]))
+    return gtk_widget_child_focus (priv->action_widget[action], direction);
+  else
+    return FALSE;
+}
+
 /* Focus in the notebook can either be on the pages, or on
- * the tabs.
+ * the tabs or on the action_widgets.
  */
 static gint
 gtk_notebook_focus (GtkWidget        *widget,
                    GtkDirectionType  direction)
 {
+  GtkNotebookPrivate *priv;
   GtkWidget *old_focus_child;
   GtkNotebook *notebook;
   GtkDirectionType effective_direction;
+  gint first_action;
+  gint last_action;
 
   gboolean widget_is_focus;
   GtkContainer *container;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-
   container = GTK_CONTAINER (widget);
   notebook = GTK_NOTEBOOK (container);
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+  if (notebook->tab_pos == GTK_POS_TOP ||
+      notebook->tab_pos == GTK_POS_LEFT)
+    {
+      first_action = ACTION_WIDGET_START;
+      last_action = ACTION_WIDGET_END;
+    }
+  else
+    {
+      first_action = ACTION_WIDGET_END;
+      last_action = ACTION_WIDGET_START;
+    }
 
   if (notebook->focus_out)
     {
@@ -3562,42 +4034,104 @@ gtk_notebook_focus (GtkWidget        *widget,
     }
 
   widget_is_focus = gtk_widget_is_focus (widget);
-  old_focus_child = container->focus_child; 
+  old_focus_child = container->focus_child;
 
   effective_direction = get_effective_direction (notebook, direction);
 
-  if (old_focus_child)         /* Focus on page child */
+  if (old_focus_child)         /* Focus on page child or action widget */
     {
       if (gtk_widget_child_focus (old_focus_child, direction))
         return TRUE;
-      
-      switch (effective_direction)
+
+      if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
        {
-       case GTK_DIR_TAB_BACKWARD:
-       case GTK_DIR_UP:
-         /* Focus onto the tabs */
-         return focus_tabs_in (notebook);
-       case GTK_DIR_DOWN:
-       case GTK_DIR_TAB_FORWARD:
-       case GTK_DIR_LEFT:
-       case GTK_DIR_RIGHT:
-         return FALSE;
+         switch (effective_direction)
+           {
+           case GTK_DIR_DOWN:
+              return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+           case GTK_DIR_RIGHT:
+             return focus_tabs_in (notebook);
+           case GTK_DIR_LEFT:
+              return FALSE;
+           case GTK_DIR_UP:
+             return FALSE;
+            default:
+              switch (direction)
+                {
+               case GTK_DIR_TAB_FORWARD:
+                  if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
+                      focus_child_in (notebook, direction))
+                    return TRUE;
+                 return focus_tabs_in (notebook);
+                case GTK_DIR_TAB_BACKWARD:
+                  return FALSE;
+                default:
+                  g_assert_not_reached ();
+                }
+           }
+       }
+      else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
+       {
+         switch (effective_direction)
+           {
+           case GTK_DIR_DOWN:
+              return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+           case GTK_DIR_RIGHT:
+              return FALSE;
+           case GTK_DIR_LEFT:
+             return focus_tabs_in (notebook);
+           case GTK_DIR_UP:
+             return FALSE;
+            default:
+              switch (direction)
+                {
+               case GTK_DIR_TAB_FORWARD:
+                  return FALSE;
+                case GTK_DIR_TAB_BACKWARD:
+                  if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
+                      focus_child_in (notebook, direction))
+                    return TRUE;
+                 return focus_tabs_in (notebook);
+                default:
+                  g_assert_not_reached ();
+                }
+           }
+       }
+      else
+       {
+         switch (effective_direction)
+           {
+           case GTK_DIR_TAB_BACKWARD:
+           case GTK_DIR_UP:
+             /* Focus onto the tabs */
+             return focus_tabs_in (notebook);
+           case GTK_DIR_DOWN:
+           case GTK_DIR_LEFT:
+           case GTK_DIR_RIGHT:
+             return FALSE;
+           case GTK_DIR_TAB_FORWARD:
+              return focus_action_in (notebook, last_action, direction);
+           }
        }
     }
   else if (widget_is_focus)    /* Focus was on tabs */
     {
       switch (effective_direction)
        {
-       case GTK_DIR_TAB_BACKWARD:
-       case GTK_DIR_UP:
+        case GTK_DIR_TAB_BACKWARD:
+              return focus_action_in (notebook, first_action, direction);
+        case GTK_DIR_UP:
          return FALSE;
-       case GTK_DIR_TAB_FORWARD:
+        case GTK_DIR_TAB_FORWARD:
+          if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
+            return TRUE;
+          return focus_action_in (notebook, last_action, direction);
        case GTK_DIR_DOWN:
          /* We use TAB_FORWARD rather than direction so that we focus a more
           * predictable widget for the user; users may be using arrow focusing
           * in this situation even if they don't usually use arrow focusing.
           */
-         return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+          return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
        case GTK_DIR_LEFT:
          return focus_tabs_move (notebook, direction, STEP_PREV);
        case GTK_DIR_RIGHT:
@@ -3610,18 +4144,25 @@ gtk_notebook_focus (GtkWidget        *widget,
        {
        case GTK_DIR_TAB_FORWARD:
        case GTK_DIR_DOWN:
+          if (focus_action_in (notebook, first_action, direction))
+            return TRUE;
          if (focus_tabs_in (notebook))
            return TRUE;
+          if (focus_action_in (notebook, last_action, direction))
+            return TRUE;
          if (focus_child_in (notebook, direction))
            return TRUE;
          return FALSE;
        case GTK_DIR_TAB_BACKWARD:
-       case GTK_DIR_UP:
+          if (focus_action_in (notebook, last_action, direction))
+            return TRUE;
          if (focus_child_in (notebook, direction))
            return TRUE;
          if (focus_tabs_in (notebook))
            return TRUE;
-         return FALSE;
+          if (focus_action_in (notebook, first_action, direction))
+            return TRUE;
+       case GTK_DIR_UP:
        case GTK_DIR_LEFT:
        case GTK_DIR_RIGHT:
          return focus_child_in (notebook, direction);
@@ -3630,7 +4171,7 @@ gtk_notebook_focus (GtkWidget        *widget,
 
   g_assert_not_reached ();
   return FALSE;
-}  
+}
 
 static void
 gtk_notebook_set_focus_child (GtkContainer *container,
@@ -3646,7 +4187,7 @@ gtk_notebook_set_focus_child (GtkContainer *container,
    */
 
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
-  if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
+  if (toplevel && gtk_widget_is_toplevel (toplevel))
     {
       page_child = GTK_WINDOW (toplevel)->focus_widget; 
       while (page_child)
@@ -3692,6 +4233,8 @@ gtk_notebook_set_focus_child (GtkContainer *container,
            }
        }
     }
+  else
+    notebook->child_has_focus = FALSE;
 
   GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
 }
@@ -3702,13 +4245,13 @@ gtk_notebook_forall (GtkContainer *container,
                     GtkCallback   callback,
                     gpointer      callback_data)
 {
+  GtkNotebookPrivate *priv;
   GtkNotebook *notebook;
   GList *children;
-
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-  g_return_if_fail (callback != NULL);
+  gint i;
 
   notebook = GTK_NOTEBOOK (container);
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
 
   children = notebook->children;
   while (children)
@@ -3725,6 +4268,14 @@ gtk_notebook_forall (GtkContainer *container,
            (* callback) (page->tab_label, callback_data);
        }
     }
+
+  if (include_internals) {
+    for (i = 0; i < N_ACTION_WIDGETS; i++)
+      {
+        if (priv->action_widget[i])
+          (* callback) (priv->action_widget[i], callback_data);
+      }
+  }
 }
 
 static GType
@@ -3759,7 +4310,7 @@ page_visible_cb (GtkWidget  *page,
         }
 
       if (next)
-        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
+        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
     }
 }
 
@@ -3773,28 +4324,11 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   GtkNotebookPage *page;
   gint nchildren;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
-  g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
-  g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
-  g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
-
   gtk_widget_freeze_child_notify (child);
-  
-  page = g_new (GtkNotebookPage, 1);
+
+  page = g_slice_new0 (GtkNotebookPage);
   page->child = child;
-  page->last_focus_child = NULL;
-  page->requisition.width = 0;
-  page->requisition.height = 0;
-  page->allocation.x = 0;
-  page->allocation.y = 0;
-  page->allocation.width = 0;
-  page->allocation.height = 0;
-  page->default_menu = FALSE;
-  page->default_tab = FALSE;
-  page->mnemonic_activate_signal = 0;
-  page->reorderable = FALSE;
-  page->detachable = FALSE;
-   
+
   nchildren = g_list_length (notebook->children);
   if ((position < 0) || (position > nchildren))
     position = nchildren;
@@ -3805,7 +4339,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
     {
       page->default_tab = TRUE;
       if (notebook->show_tabs)
-       tab_label = gtk_label_new ("");
+       tab_label = gtk_label_new (NULL);
     }
   page->tab_label = tab_label;
   page->menu_label = menu_label;
@@ -3816,9 +4350,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   if (!menu_label)
     page->default_menu = TRUE;
   else  
-    {
-      g_object_ref_sink (page->menu_label);
-    }
+    g_object_ref_sink (page->menu_label);
 
   if (notebook->menu)
     gtk_notebook_menu_item_create (notebook,
@@ -3834,8 +4366,9 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
     notebook->first_tab = notebook->children;
 
   /* child visible will be turned on by switch_page below */
-  gtk_widget_set_child_visible (child, FALSE);
-  
+  if (notebook->cur_page != page)
+    gtk_widget_set_child_visible (child, FALSE);
+
   if (tab_label)
     {
       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
@@ -3845,7 +4378,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
 
     page->mnemonic_activate_signal =
       g_signal_connect (tab_label,
-                       "mnemonic_activate",
+                       "mnemonic-activate",
                        G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
                        notebook);
     }
@@ -3861,12 +4394,16 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
 
   if (!notebook->cur_page)
     {
-      gtk_notebook_switch_page (notebook, page, 0);
-      gtk_notebook_switch_focus_tab (notebook, NULL);
+      gtk_notebook_switch_page (notebook, page);
+      /* focus_tab is set in the switch_page method */
+      gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
     }
 
   gtk_notebook_update_tab_states (notebook);
 
+  if (notebook->scrollable)
+    gtk_notebook_redraw_arrows (notebook);
+
   gtk_widget_child_notify (child, "tab-expand");
   gtk_widget_child_notify (child, "tab-fill");
   gtk_widget_child_notify (child, "tab-pack");
@@ -3875,7 +4412,8 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   gtk_widget_child_notify (child, "position");
   gtk_widget_thaw_child_notify (child);
 
-  return position;
+  /* The page-added handler might have reordered the pages, re-get the position */
+  return gtk_notebook_page_num (notebook, child);
 }
 
 /* Private GtkNotebook Functions:
@@ -3920,86 +4458,24 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook)
       /* fall through */
     case GTK_POS_TOP:
       redraw_rect.width = widget->allocation.width - 2 * border;
-      redraw_rect.height = page->allocation.height + widget->style->ythickness;
-
-      if (page != notebook->cur_page)
-       redraw_rect.height += widget->style->ythickness;
-      break;
-    case GTK_POS_RIGHT:
-      redraw_rect.x = widget->allocation.width - border -
-       page->allocation.width - widget->style->xthickness;
-
-      if (page != notebook->cur_page)
-       redraw_rect.x -= widget->style->xthickness;
-      /* fall through */
-    case GTK_POS_LEFT:
-      redraw_rect.width = page->allocation.width + widget->style->xthickness;
-      redraw_rect.height = widget->allocation.height - 2 * border;
-
-      if (page != notebook->cur_page)
-       redraw_rect.width += widget->style->xthickness;
-      break;
-    }
-
-  redraw_rect.x += widget->allocation.x;
-  redraw_rect.y += widget->allocation.y;
-
-  gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
-}
-
-static void
-gtk_notebook_redraw_tabs_union (GtkNotebook *notebook)
-{
-  GtkWidget *widget;
-  GtkNotebookPage *page;
-  GdkRectangle redraw_rect;
-  gint border;
-  gint tab_pos = get_effective_tab_pos (notebook);
-
-  widget = GTK_WIDGET (notebook);
-  border = GTK_CONTAINER (notebook)->border_width;
-
-  if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
-    return;
-
-  page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
-
-  redraw_rect.x = border;
-  redraw_rect.y = border;
-
-  switch (tab_pos)
-    {
-    case GTK_POS_TOP:
-      redraw_rect.x = border;
-      redraw_rect.y = page->allocation.height + border;
-      break;
-    case GTK_POS_BOTTOM:
-      redraw_rect.x = border;
-      redraw_rect.y = widget->allocation.height - border -
-       page->allocation.height - widget->style->ythickness;
-      break;
-    case GTK_POS_RIGHT:
-      redraw_rect.x = widget->allocation.width - border -
-       page->allocation.width - widget->style->xthickness;
-      redraw_rect.y = border;
-      break;
-    case GTK_POS_LEFT:
-      redraw_rect.x = page->allocation.width + border;
-      redraw_rect.y = border;
-      break;
-    }
-
-  switch (tab_pos)
-    {
-    case GTK_POS_TOP:
-    case GTK_POS_BOTTOM:
-      redraw_rect.width = widget->allocation.width - 2 * border;
-      redraw_rect.height = widget->style->ythickness;
+      redraw_rect.height = page->allocation.height + widget->style->ythickness;
+
+      if (page != notebook->cur_page)
+       redraw_rect.height += widget->style->ythickness;
       break;
     case GTK_POS_RIGHT:
+      redraw_rect.x = widget->allocation.width - border -
+       page->allocation.width - widget->style->xthickness;
+
+      if (page != notebook->cur_page)
+       redraw_rect.x -= widget->style->xthickness;
+      /* fall through */
     case GTK_POS_LEFT:
-      redraw_rect.width = widget->style->xthickness;
+      redraw_rect.width = page->allocation.width + widget->style->xthickness;
       redraw_rect.height = widget->allocation.height - 2 * border;
+
+      if (page != notebook->cur_page)
+       redraw_rect.width += widget->style->xthickness;
       break;
     }
 
@@ -4035,13 +4511,11 @@ gtk_notebook_redraw_arrows (GtkNotebook *notebook)
     }
 }
 
-static gint
+static gboolean
 gtk_notebook_timer (GtkNotebook *notebook)
 {
   gboolean retval = FALSE;
 
-  GDK_THREADS_ENTER ();
-
   if (notebook->timer)
     {
       gtk_notebook_do_arrow (notebook, notebook->click_child);
@@ -4055,7 +4529,7 @@ gtk_notebook_timer (GtkNotebook *notebook)
           g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
 
          notebook->need_timer = FALSE;
-         notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
+         notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
                                           (GSourceFunc) gtk_notebook_timer,
                                           (gpointer) notebook);
        }
@@ -4063,8 +4537,6 @@ gtk_notebook_timer (GtkNotebook *notebook)
        retval = TRUE;
     }
 
-  GDK_THREADS_LEAVE ();
-
   return retval;
 }
 
@@ -4080,7 +4552,7 @@ gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
 
       g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
 
-      notebook->timer = g_timeout_add (timeout,
+      notebook->timer = gdk_threads_add_timeout (timeout,
                                       (GSourceFunc) gtk_notebook_timer,
                                       (gpointer) notebook);
       notebook->need_timer = TRUE;
@@ -4132,25 +4604,33 @@ static void
 gtk_notebook_real_remove (GtkNotebook *notebook,
                          GList       *list)
 {
+  GtkNotebookPrivate *priv;
   GtkNotebookPage *page;
   GList * next_list;
   gint need_resize = FALSE;
+  GtkWidget *tab_label;
 
   gboolean destroying;
 
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
   destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
   
-  next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
+  next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
   if (!next_list)
-    next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
+    next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
+
+  notebook->children = g_list_remove_link (notebook->children, list);
 
   if (notebook->cur_page == list->data)
     { 
       notebook->cur_page = NULL;
       if (next_list && !destroying)
-       gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
+       gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
     }
 
+  if (priv->detached_tab == list->data)
+    priv->detached_tab = NULL;
+
   if (list == notebook->first_tab)
     notebook->first_tab = next_list;
   if (list == notebook->focus_tab && !destroying)
@@ -4165,8 +4645,16 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
 
   gtk_widget_unparent (page->child);
 
-  gtk_notebook_remove_tab_label (notebook, page);
-  
+  tab_label = page->tab_label;
+  if (tab_label)
+    {
+      g_object_ref (tab_label);
+      gtk_notebook_remove_tab_label (notebook, page);
+      if (destroying)
+        gtk_widget_destroy (tab_label);
+      g_object_unref (tab_label);
+    } 
+
   if (notebook->menu)
     {
       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
@@ -4176,7 +4664,6 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
   if (!page->default_menu)
     g_object_unref (page->menu_label);
   
-  notebook->children = g_list_remove_link (notebook->children, list);
   g_list_free (list);
 
   if (page->last_focus_child)
@@ -4185,7 +4672,7 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
       page->last_focus_child = NULL;
     }
   
-  g_free (page);
+  g_slice_free (GtkNotebookPage, page);
 
   gtk_notebook_update_labels (notebook);
   if (need_resize)
@@ -4200,6 +4687,9 @@ gtk_notebook_update_labels (GtkNotebook *notebook)
   gchar string[32];
   gint page_num = 1;
 
+  if (!notebook->show_tabs && !notebook->menu)
+    return;
+
   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
        list;
        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
@@ -4229,9 +4719,9 @@ gtk_notebook_update_labels (GtkNotebook *notebook)
        }
       if (notebook->menu && page->default_menu)
        {
-         if (page->tab_label && GTK_IS_LABEL (page->tab_label))
+         if (GTK_IS_LABEL (page->tab_label))
            gtk_label_set_text (GTK_LABEL (page->menu_label),
-                          GTK_LABEL (page->tab_label)->label);
+                                GTK_LABEL (page->tab_label)->label);
          else
            gtk_label_set_text (GTK_LABEL (page->menu_label), string);
        }
@@ -4245,9 +4735,6 @@ gtk_notebook_real_page_position (GtkNotebook *notebook,
   GList *work;
   gint count_start;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
-  g_return_val_if_fail (list != NULL, -1);
-
   for (work = notebook->children, count_start = 0;
        work && work != list; work = work->next)
     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
@@ -4272,8 +4759,6 @@ gtk_notebook_search_page (GtkNotebook *notebook,
   GList *old_list = NULL;
   gint flag = 0;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
-
   switch (direction)
     {
     case STEP_PREV:
@@ -4352,9 +4837,6 @@ gtk_notebook_paint (GtkWidget    *widget,
   gboolean is_rtl;
   gint tab_pos;
    
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-  g_return_if_fail (area != NULL);
-
   if (!GTK_WIDGET_DRAWABLE (widget))
     return;
 
@@ -4384,8 +4866,7 @@ gtk_notebook_paint (GtkWidget    *widget,
   if (!notebook->first_tab)
     notebook->first_tab = notebook->children;
 
-  if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
-      !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
+  if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
     page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
   else
     page = notebook->cur_page;
@@ -4409,10 +4890,8 @@ gtk_notebook_paint (GtkWidget    *widget,
   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
       !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
     {
-      gtk_paint_box (widget->style, widget->window,
-                    GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                    area, widget, "notebook",
-                    x, y, width, height);
+      gap_x = 0;
+      gap_width = 0;
     }
   else
     {
@@ -4439,13 +4918,12 @@ gtk_notebook_paint (GtkWidget    *widget,
          step = STEP_PREV;
          break;
        }
-
-      gtk_paint_box_gap (widget->style, widget->window,
-                        GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                        area, widget, "notebook",
-                        x, y, width, height,
-                        tab_pos, gap_x, gap_width);
     }
+  gtk_paint_box_gap (widget->style, widget->window,
+                    GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+                    area, widget, "notebook",
+                    x, y, width, height,
+                    tab_pos, gap_x, gap_width);
 
   showarrow = FALSE;
   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
@@ -4489,10 +4967,6 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
   GdkWindow *window;
   GtkWidget *widget;
   
-  g_return_if_fail (notebook != NULL);
-  g_return_if_fail (page != NULL);
-  g_return_if_fail (area != NULL);
-
   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
       !GTK_WIDGET_MAPPED (page->tab_label) ||
       (page->allocation.width == 0) || (page->allocation.height == 0))
@@ -4526,37 +5000,6 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
                           page_area.x, page_area.y,
                           page_area.width, page_area.height,
                           gap_side);
-
-      if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
-         notebook->focus_tab && (notebook->focus_tab->data == page))
-       {
-          gint focus_width;
-
-         gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
-
-         gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
-                          area, widget, "tab",
-                          page->tab_label->allocation.x - focus_width,
-                          page->tab_label->allocation.y - focus_width,
-                          page->tab_label->allocation.width + 2 * focus_width,
-                          page->tab_label->allocation.height + 2 * focus_width);
-       }
-
-      if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
-          GTK_WIDGET_DRAWABLE (page->tab_label))
-        {
-          GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
-
-          /* This is a lame hack since all this code needs rewriting anyhow */
-          expose_event->expose.window = g_object_ref (page->tab_label->window);
-          expose_event->expose.area = child_area;
-          expose_event->expose.region = gdk_region_rectangle (&child_area);
-          expose_event->expose.send_event = TRUE;
-          expose_event->expose.count = 0;
-
-         gtk_widget_send_expose (page->tab_label, expose_event);
-         gdk_event_free (expose_event);
-       }
     }
 }
 
@@ -4571,20 +5014,20 @@ gtk_notebook_draw_arrow (GtkNotebook      *notebook,
   GtkArrowType arrow;
   gboolean is_rtl, left;
 
-  gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
-
-  widget = GTK_WIDGET (notebook);
-
-  is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-  left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
-         (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
-
   if (GTK_WIDGET_DRAWABLE (notebook))
     {
       gint scroll_arrow_hlength;
       gint scroll_arrow_vlength;
       gint arrow_size;
 
+      gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
+
+      widget = GTK_WIDGET (notebook);
+
+      is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+      left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
+             (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
+
       gtk_widget_style_get (widget,
                             "scroll-arrow-hlength", &scroll_arrow_hlength,
                             "scroll-arrow-vlength", &scroll_arrow_vlength,
@@ -4607,7 +5050,7 @@ gtk_notebook_draw_arrow (GtkNotebook      *notebook,
 
       if (notebook->focus_tab &&
          !gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                     left? STEP_PREV : STEP_NEXT, TRUE))
+                                    left ? STEP_PREV : STEP_NEXT, TRUE))
        {
          shadow_type = GTK_SHADOW_ETCHED_IN;
          state_type = GTK_STATE_INSENSITIVE;
@@ -4624,7 +5067,7 @@ gtk_notebook_draw_arrow (GtkNotebook      *notebook,
           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
           arrow_size = scroll_arrow_hlength;
         }
-      
+     
       gtk_paint_arrow (widget->style, widget->window, state_type, 
                       shadow_type, NULL, widget, "notebook",
                       arrow, TRUE, arrow_rect.x, arrow_rect.y, 
@@ -4650,17 +5093,19 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
 {
   GtkNotebookPrivate *priv;
   GtkWidget *widget;
-  GtkNotebookPage *page;
   GList *children;
   gint tab_pos = get_effective_tab_pos (notebook);
   gint tab_overlap;
   gint arrow_spacing;
   gint scroll_arrow_hlength;
   gint scroll_arrow_vlength;
+  gboolean is_rtl;
+  gint i;
 
   widget = GTK_WIDGET (notebook);
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
   children = notebook->children;
+  is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
 
   gtk_widget_style_get (GTK_WIDGET (notebook),
                         "arrow-spacing", &arrow_spacing,
@@ -4675,8 +5120,22 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
       *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
       *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
 
+      for (i = 0; i < N_ACTION_WIDGETS; i++)
+        {
+          if (priv->action_widget[i])
+            {
+              if ((i == ACTION_WIDGET_START && !is_rtl) ||
+                  (i == ACTION_WIDGET_END && is_rtl))
+                *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
+              else
+                *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
+            }
+        }
+
       while (children)
        {
+          GtkNotebookPage *page;
+
          page = children->data;
          children = children->next;
 
@@ -4690,8 +5149,21 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
       *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
       *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
 
+      for (i = 0; i < N_ACTION_WIDGETS; i++)
+        {
+          if (priv->action_widget[i])
+            {
+              if (i == ACTION_WIDGET_START)
+                *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
+              else
+                *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
+            }
+        }
+
       while (children)
        {
+          GtkNotebookPage *page;
+
          page = children->data;
          children = children->next;
 
@@ -4715,11 +5187,9 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
          if (*tab_space > *max - *min - tab_overlap)
            {
              *show_arrows = TRUE;
-             page = notebook->focus_tab->data;
 
              /* take arrows into account */
-             *tab_space = widget->allocation.width - tab_overlap -
-               2 * GTK_CONTAINER (notebook)->border_width;
+             *tab_space = *max - *min - tab_overlap;
 
              if (notebook->has_after_previous)
                {
@@ -4751,11 +5221,9 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
          if (*tab_space > *max - *min - tab_overlap)
            {
              *show_arrows = TRUE;
-             page = notebook->focus_tab->data;
 
              /* take arrows into account */
-             *tab_space = widget->allocation.height -
-               tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
+             *tab_space = *max - *min - tab_overlap;
 
              if (notebook->has_after_previous || notebook->has_after_next)
                {
@@ -4807,13 +5275,16 @@ gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
                                  &(notebook->focus_tab),
                                  remaining_space, STEP_NEXT);
        }
-      
-      if (*remaining_space <= 0)
+
+      if (tab_space <= 0 || *remaining_space < 0)
        {
          /* show 1 tab */
          notebook->first_tab = notebook->focus_tab;
          *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
                                                  STEP_NEXT, TRUE);
+          page = notebook->first_tab->data;
+          *remaining_space = tab_space - page->requisition.width;
+          *n = 1;
        }
       else
        {
@@ -4851,7 +5322,7 @@ gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
                                    &(notebook->first_tab), remaining_space,
                                    STEP_PREV);
 
-         if (*remaining_space <= 0)
+         if (*remaining_space < 0)
            {
              notebook->first_tab =
                gtk_notebook_search_page (notebook, notebook->first_tab,
@@ -4883,34 +5354,39 @@ gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
                {
                  *last_child = NULL;
                  children = NULL;
+
                  gtk_notebook_calc_tabs (notebook,
                                          gtk_notebook_search_page (notebook,
                                                                    notebook->first_tab,
                                                                    STEP_PREV,
                                                                    TRUE),
                                          &children, remaining_space, STEP_PREV);
-                 notebook->first_tab = gtk_notebook_search_page(notebook,
-                                                                children,
-                                                                STEP_NEXT,
-                                                                TRUE);
+
+                 if (*remaining_space == 0)
+                   notebook->first_tab = children;
+                 else
+                   notebook->first_tab = gtk_notebook_search_page(notebook,
+                                                                  children,
+                                                                  STEP_NEXT,
+                                                                  TRUE);
                }
            }
-       }
 
-      if (*remaining_space < 0) 
-       {
-         /* calculate number of tabs */
-         *remaining_space = - (*remaining_space);
-         *n = 0;
-
-         for (children = notebook->first_tab;
-              children && children != *last_child;
-              children = gtk_notebook_search_page (notebook, children,
-                                                   STEP_NEXT, TRUE))
-           (*n)++;
-       }
-      else 
-       *remaining_space = 0;
+          if (*remaining_space < 0)
+            {
+              /* calculate number of tabs */
+              *remaining_space = - (*remaining_space);
+              *n = 0;
+
+              for (children = notebook->first_tab;
+                   children && children != *last_child;
+                   children = gtk_notebook_search_page (notebook, children,
+                                                        STEP_NEXT, TRUE))
+                (*n)++;
+           }
+          else
+           *remaining_space = 0;
+        }
 
       /* unmap all non-visible tabs */
       for (children = gtk_notebook_search_page (notebook, NULL,
@@ -4993,7 +5469,7 @@ get_allocate_at_bottom (GtkWidget *widget,
   return FALSE;
 }
 
-static gboolean
+static void
 gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
                                        GList       **children,
                                        GList        *last_child,
@@ -5011,9 +5487,9 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
   gboolean allocate_at_bottom;
   gint tab_overlap, tab_pos, tab_extra_space;
   gint left_x, right_x, top_y, bottom_y, anchor;
+  gint xthickness, ythickness;
   gboolean gap_left, packing_changed;
   GtkAllocation child_allocation = { 0, };
-  gboolean allocation_changed = FALSE;
 
   widget = GTK_WIDGET (notebook);
   container = GTK_CONTAINER (notebook);
@@ -5026,6 +5502,9 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
   child_allocation.x = widget->allocation.x + container->border_width;
   child_allocation.y = widget->allocation.y + container->border_width;
 
+  xthickness = widget->style->xthickness;
+  ythickness = widget->style->ythickness;
+
   switch (tab_pos)
     {
     case GTK_POS_BOTTOM:
@@ -5049,9 +5528,9 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
       break;
     }
 
-  left_x   = CLAMP (widget->allocation.x + priv->mouse_x - notebook->cur_page->allocation.width / 2,
+  left_x   = CLAMP (priv->mouse_x - priv->drag_offset_x,
                    min, max - notebook->cur_page->allocation.width);
-  top_y    = CLAMP (widget->allocation.y + priv->mouse_y - notebook->cur_page->allocation.height / 2,
+  top_y    = CLAMP (priv->mouse_y - priv->drag_offset_y,
                    min, max - notebook->cur_page->allocation.height);
   right_x  = left_x + notebook->cur_page->allocation.width;
   bottom_y = top_y + notebook->cur_page->allocation.height;
@@ -5196,23 +5675,35 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
          break;
        }
 
-      if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
-         (page->allocation.x != child_allocation.x ||
-          page->allocation.y != child_allocation.y ||
-          page->allocation.width != child_allocation.width ||
-          page->allocation.height != child_allocation.height))
-       allocation_changed = TRUE;
-
       page->allocation = child_allocation;
 
-      if (priv->operation == DRAG_OPERATION_REORDER &&
-         page == notebook->cur_page)
+      if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
+         (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
        {
          /* needs to be allocated at 0,0
           * to be shown in the drag window */
          page->allocation.x = 0;
          page->allocation.y = 0;
        }
+      
+      if (page != notebook->cur_page)
+       {
+         switch (tab_pos)
+           {
+           case GTK_POS_TOP:
+             page->allocation.y += ythickness;
+             /* fall through */
+           case GTK_POS_BOTTOM:
+             page->allocation.height = MAX (1, page->allocation.height - ythickness);
+             break;
+           case GTK_POS_LEFT:
+             page->allocation.x += xthickness;
+             /* fall through */
+           case GTK_POS_RIGHT:
+             page->allocation.width = MAX (1, page->allocation.width - xthickness);
+             break;
+           }
+       }
 
       /* calculate whether to leave a gap based on reorder operation or not */
       switch (tab_pos)
@@ -5304,8 +5795,6 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
          break;
        }
     }
-
-  return allocation_changed;
 }
 
 static void
@@ -5316,7 +5805,7 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook)
   gboolean showarrow = FALSE;
   gint tab_space, min, max, remaining_space;
   gint expanded_tabs, operation;
-  gboolean changed;
+  gboolean tab_allocations_changed = FALSE;
 
   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
     return;
@@ -5332,22 +5821,23 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook)
                                     &expanded_tabs, &remaining_space);
 
   children = notebook->first_tab;
-  changed = gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
-                                                   showarrow, STEP_NEXT,
-                                                   &remaining_space, &expanded_tabs, min, max);
+  gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
+                                         showarrow, STEP_NEXT,
+                                         &remaining_space, &expanded_tabs, min, max);
   if (children && children != last_child)
     {
       children = notebook->children;
-      changed |= gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
-                                                        showarrow, STEP_PREV,
-                                                        &remaining_space, &expanded_tabs, min, max);
+      gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
+                                             showarrow, STEP_PREV,
+                                             &remaining_space, &expanded_tabs, min, max);
     }
 
   children = notebook->children;
 
   while (children)
     {
-      gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
+      if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
+       tab_allocations_changed = TRUE;
       children = children->next;
     }
 
@@ -5356,13 +5846,11 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook)
   if (!notebook->first_tab)
     notebook->first_tab = notebook->children;
 
-  if (changed || operation != DRAG_OPERATION_REORDER)
+  if (tab_allocations_changed)
     gtk_notebook_redraw_tabs (notebook);
-  else if (!changed)
-    gtk_notebook_redraw_tabs_union (notebook);
 }
 
-static void
+static gboolean
 gtk_notebook_page_allocate (GtkNotebook     *notebook,
                            GtkNotebookPage *page)
 {
@@ -5375,9 +5863,16 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
   gint focus_width;
   gint tab_curvature;
   gint tab_pos = get_effective_tab_pos (notebook);
+  gboolean tab_allocation_changed;
+  gboolean was_visible = page->tab_allocated_visible;
 
-  if (!page->tab_label)
-    return;
+  if (!page->tab_label ||
+      !GTK_WIDGET_VISIBLE (page->tab_label) ||
+      !gtk_widget_get_child_visible (page->tab_label))
+    {
+      page->tab_allocated_visible = FALSE;
+      return was_visible;
+    }
 
   xthickness = widget->style->xthickness;
   ythickness = widget->style->ythickness;
@@ -5442,7 +5937,20 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
       break;
     }
 
+  tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
+                           child_allocation.y != page->tab_label->allocation.y ||
+                           child_allocation.width != page->tab_label->allocation.width ||
+                           child_allocation.height != page->tab_label->allocation.height);
+
   gtk_widget_size_allocate (page->tab_label, &child_allocation);
+
+  if (!was_visible)
+    {
+      page->tab_allocated_visible = TRUE;
+      tab_allocation_changed = TRUE;
+    }
+
+  return tab_allocation_changed;
 }
 
 static void 
@@ -5455,8 +5963,10 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
   GtkNotebookPage *page = NULL;
   GList *children;
   GList *last_list = NULL;
+  GList *last_calculated_child = NULL;
   gboolean pack;
   gint tab_pos = get_effective_tab_pos (notebook);
+  guint real_direction;
 
   if (!start)
     return;
@@ -5464,7 +5974,9 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
   children = start;
   pack = GTK_NOTEBOOK_PAGE (start)->pack;
   if (pack == GTK_PACK_END)
-    direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
+    real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
+  else
+    real_direction = direction;
 
   while (1)
     {
@@ -5487,14 +5999,20 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
                            {
                              *tab_space = - (*tab_space +
                                              page->requisition.width);
+
+                             if (*tab_space == 0 && direction == STEP_PREV)
+                               children = last_calculated_child;
+
                              *end = children;
                            }
                          return;
                        }
+
+                     last_calculated_child = children;
                    }
                  last_list = children;
                }
-             if (direction == STEP_NEXT)
+             if (real_direction == STEP_NEXT)
                children = children->next;
              else
                children = children->prev;
@@ -5517,24 +6035,30 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
                            {
                              *tab_space = - (*tab_space +
                                              page->requisition.height);
+
+                             if (*tab_space == 0 && direction == STEP_PREV)
+                               children = last_calculated_child;
+
                              *end = children;
                            }
                          return;
                        }
+
+                     last_calculated_child = children;
                    }
                  last_list = children;
                }
-             if (direction == STEP_NEXT)
+             if (real_direction == STEP_NEXT)
                children = children->next;
              else
                children = children->prev;
            }
          break;
        }
-      if (direction == STEP_PREV)
+      if (real_direction == STEP_PREV)
        return;
       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
-      direction = STEP_PREV;
+      real_direction = STEP_PREV;
       children = last_list;
     }
 }
@@ -5567,15 +6091,17 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
                               GtkNotebookPage *page,
                               guint            page_num)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (page != NULL);
+  gboolean child_has_focus;
 
   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
     return;
 
+  /* save the value here, changing visibility changes focus */
+  child_has_focus = notebook->child_has_focus;
+
   if (notebook->cur_page)
     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
-  
+
   notebook->cur_page = page;
 
   if (!notebook->focus_tab ||
@@ -5589,7 +6115,7 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
    * element on the new page, if possible, or if not, to the
    * notebook itself.
    */
-  if (notebook->child_has_focus)
+  if (child_has_focus)
     {
       if (notebook->cur_page->last_focus_child &&
          gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
@@ -5613,17 +6139,14 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
  */
 static void
 gtk_notebook_switch_page (GtkNotebook     *notebook,
-                         GtkNotebookPage *page,
-                         gint             page_num)
+                         GtkNotebookPage *page)
 { 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (page != NULL);
+  guint page_num;
+
   if (notebook->cur_page == page)
     return;
 
-  if (page_num < 0)
-    page_num = g_list_index (notebook->children, page);
+  page_num = g_list_index (notebook->children, page);
 
   g_signal_emit (notebook,
                 notebook_signals[SWITCH_PAGE],
@@ -5640,13 +6163,11 @@ gtk_notebook_page_select (GtkNotebook *notebook,
   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
   gint tab_pos = get_effective_tab_pos (notebook);
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
-
   if (!notebook->focus_tab)
     return FALSE;
 
   page = notebook->focus_tab->data;
-  gtk_notebook_switch_page (notebook, page, -1);
+  gtk_notebook_switch_page (notebook, page);
 
   if (move_focus)
     {
@@ -5679,8 +6200,6 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
   GList *old_child;
   GtkNotebookPage *page;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->focus_tab == new_child)
     return;
 
@@ -5698,9 +6217,8 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
     gtk_notebook_redraw_tabs (notebook);
   else
     gtk_notebook_pages_allocate (notebook);
-  
-  gtk_notebook_switch_page (notebook, page,
-                           g_list_index (notebook->children, page));
+
+  gtk_notebook_switch_page (notebook, page);
 }
 
 static void
@@ -5711,9 +6229,6 @@ gtk_notebook_menu_switch_page (GtkWidget       *widget,
   GList *children;
   guint page_num;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (page != NULL);
-
   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
                           (GTK_MENU (widget->parent)));
 
@@ -5751,7 +6266,7 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook,
   page = list->data;
   if (page->default_menu)
     {
-      if (page->tab_label && GTK_IS_LABEL (page->tab_label))
+      if (GTK_IS_LABEL (page->tab_label))
        page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
       else
        page->menu_label = gtk_label_new ("");
@@ -5783,8 +6298,6 @@ gtk_notebook_menu_detacher (GtkWidget *widget,
 {
   GtkNotebook *notebook;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
 
@@ -5802,8 +6315,6 @@ static void
 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
                                            gboolean     homogeneous)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (homogeneous == notebook->homogeneous)
     return;
 
@@ -5817,8 +6328,6 @@ static void
 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
                                      guint        border_width)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   notebook->tab_hborder = border_width;
   notebook->tab_vborder = border_width;
 
@@ -5835,8 +6344,6 @@ static void
 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
                                       guint        tab_hborder)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->tab_hborder == tab_hborder)
     return;
 
@@ -5852,8 +6359,6 @@ static void
 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
                                       guint        tab_vborder)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->tab_vborder == tab_vborder)
     return;
 
@@ -5879,9 +6384,9 @@ gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
  * gtk_notebook_append_page:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
- * 
+ *
  * Appends a page to @notebook.
  *
  * Return value: the index (starting from 0) of the appended
@@ -5903,9 +6408,9 @@ gtk_notebook_append_page (GtkNotebook *notebook,
  * gtk_notebook_append_page_menu:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
- * @menu_label: the widget to use as a label for the page-switch
+ * @menu_label: (allow-none): the widget to use as a label for the page-switch
  *              menu, if that is enabled. If %NULL, and @tab_label
  *              is a #GtkLabel or %NULL, then the menu label will be
  *              a newly created label with the same text as @tab_label;
@@ -5936,7 +6441,7 @@ gtk_notebook_append_page_menu (GtkNotebook *notebook,
  * gtk_notebook_prepend_page:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
  *
  * Prepends a page to @notebook.
@@ -5960,9 +6465,9 @@ gtk_notebook_prepend_page (GtkNotebook *notebook,
  * gtk_notebook_prepend_page_menu:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
- * @menu_label: the widget to use as a label for the page-switch
+ * @menu_label: (allow-none): the widget to use as a label for the page-switch
  *              menu, if that is enabled. If %NULL, and @tab_label
  *              is a #GtkLabel or %NULL, then the menu label will be
  *              a newly created label with the same text as @tab_label;
@@ -5993,11 +6498,11 @@ gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
  * gtk_notebook_insert_page:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
  * @position: the index (starting at 0) at which to insert the page,
  *            or -1 to append the page after all other pages.
- * 
+ *
  * Insert a page into @notebook at the given position.
  *
  * Return value: the index (starting from 0) of the inserted
@@ -6039,7 +6544,7 @@ gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
       GtkNotebookPage *page = list->data;
 
       gtk_widget_grab_focus (GTK_WIDGET (notebook));   /* Do this first to avoid focusing new page */
-      gtk_notebook_switch_page (notebook, page,  -1);
+      gtk_notebook_switch_page (notebook, page);
       focus_tabs_in (notebook);
     }
 
@@ -6050,9 +6555,9 @@ gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
  * gtk_notebook_insert_page_menu:
  * @notebook: a #GtkNotebook
  * @child: the #GtkWidget to use as the contents of the page.
- * @tab_label: the #GtkWidget to be used as the label for the page,
+ * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
  *             or %NULL to use the default label, 'page N'.
- * @menu_label: the widget to use as a label for the page-switch
+ * @menu_label: (allow-none): the widget to use as a label for the page-switch
  *              menu, if that is enabled. If %NULL, and @tab_label
  *              is a #GtkLabel or %NULL, then the menu label will be
  *              a newly created label with the same text as @tab_label;
@@ -6145,12 +6650,12 @@ gtk_notebook_get_current_page (GtkNotebook *notebook)
 /**
  * gtk_notebook_get_nth_page:
  * @notebook: a #GtkNotebook
- * @page_num: the index of a page in the noteobok, or -1
+ * @page_num: the index of a page in the notebook, or -1
  *            to get the last page.
  * 
  * Returns the child widget contained in page number @page_num.
- * 
- * Return value: the child widget, or %NULL if @page_num is
+ *
+ * Return value: (transfer none): the child widget, or %NULL if @page_num is
  * out of bounds.
  **/
 GtkWidget*
@@ -6238,8 +6743,13 @@ gtk_notebook_page_num (GtkNotebook      *notebook,
  *            than the number of pages in the notebook, nothing
  *            will be done.
  *                
- * Switches to the page number @page_num.
- **/
+ * Switches to the page number @page_num. 
+ *
+ * Note that due to historical reasons, GtkNotebook refuses
+ * to switch to a page unless the child widget is visible. 
+ * Therefore, it is recommended to show child widgets before
+ * adding them to a notebook. 
+ */
 void
 gtk_notebook_set_current_page (GtkNotebook *notebook,
                               gint         page_num)
@@ -6248,15 +6758,12 @@ gtk_notebook_set_current_page (GtkNotebook *notebook,
 
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  if (page_num >= 0)
-    list = g_list_nth (notebook->children, page_num);
-  else
-    list = g_list_last (notebook->children);
-
-  page_num = g_list_index (notebook->children, list);
+  if (page_num < 0)
+    page_num = g_list_length (notebook->children) - 1;
 
+  list = g_list_nth (notebook->children, page_num);
   if (list)
-    gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
+    gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /**
@@ -6281,7 +6788,7 @@ gtk_notebook_next_page (GtkNotebook *notebook)
   if (!list)
     return;
 
-  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
+  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /**
@@ -6306,7 +6813,7 @@ gtk_notebook_prev_page (GtkNotebook *notebook)
   if (!list)
     return;
 
-  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
+  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /* Public GtkNotebook/Tab Style Functions
@@ -6666,8 +7173,8 @@ gtk_notebook_popup_disable  (GtkNotebook *notebook)
  * Returns the tab label widget for the page @child. %NULL is returned
  * if @child is not in @notebook or if no tab label has specifically
  * been set for @child.
- * 
- * Return value: the tab label
+ *
+ * Return value: (transfer none): the tab label
  **/
 GtkWidget *
 gtk_notebook_get_tab_label (GtkNotebook *notebook,
@@ -6692,9 +7199,9 @@ gtk_notebook_get_tab_label (GtkNotebook *notebook,
  * gtk_notebook_set_tab_label:
  * @notebook: a #GtkNotebook
  * @child: the page
- * @tab_label: the tab label widget to use, or %NULL for default tab
+ * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
  *             label.
- * 
+ *
  * Changes the tab label for @child. If %NULL is specified
  * for @tab_label, then the page will have the label 'page N'.
  **/
@@ -6749,7 +7256,7 @@ gtk_notebook_set_tab_label (GtkNotebook *notebook,
   if (page->tab_label)
     page->mnemonic_activate_signal =
       g_signal_connect (page->tab_label,
-                       "mnemonic_activate",
+                       "mnemonic-activate",
                        G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
                        notebook);
 
@@ -6795,10 +7302,10 @@ gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
  * Retrieves the text of the tab label for the page containing
  *    @child.
  *
- * Returns value: the text of the tab label, or %NULL if the
- *                tab label widget is not a #GtkLabel. The
- *                string is owned by the widget and must not
- *                be freed.
+ * Return value: the text of the tab label, or %NULL if the
+ *               tab label widget is not a #GtkLabel. The
+ *               string is owned by the widget and must not
+ *               be freed.
  **/
 G_CONST_RETURN gchar *
 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
@@ -6811,7 +7318,7 @@ gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
 
   tab_label = gtk_notebook_get_tab_label (notebook, child);
 
-  if (tab_label && GTK_IS_LABEL (tab_label))
+  if (GTK_IS_LABEL (tab_label))
     return gtk_label_get_text (GTK_LABEL (tab_label));
   else
     return NULL;
@@ -6851,9 +7358,9 @@ gtk_notebook_get_menu_label (GtkNotebook *notebook,
  * gtk_notebook_set_menu_label:
  * @notebook: a #GtkNotebook
  * @child: the child widget
- * @menu_label: the menu label, or NULL for default
- * 
- * Changes the menu label for the page containing @child. 
+ * @menu_label: (allow-none): the menu label, or NULL for default
+ *
+ * Changes the menu label for the page containing @child.
  **/
 void
 gtk_notebook_set_menu_label (GtkNotebook *notebook,
@@ -6913,7 +7420,10 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
   if (menu_text)
-    menu_label = gtk_label_new (menu_text);
+    {
+      menu_label = gtk_label_new (menu_text);
+      gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
+    }
   gtk_notebook_set_menu_label (notebook, child, menu_label);
   gtk_widget_child_notify (child, "menu-label");
 }
@@ -6926,11 +7436,11 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
  * Retrieves the text of the menu label for the page containing
  *    @child.
  *
- * Returns value: the text of the tab label, or %NULL if the
- *                widget does not have a menu label other than
- *                the default menu label, or the menu label widget
- *                is not a #GtkLabel. The string is owned by
- *                the widget and must not be freed.
+ * Return value: the text of the tab label, or %NULL if the
+ *               widget does not have a menu label other than
+ *               the default menu label, or the menu label widget
+ *               is not a #GtkLabel. The string is owned by
+ *               the widget and must not be freed.
  **/
 G_CONST_RETURN gchar *
 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
@@ -6943,7 +7453,7 @@ gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
  
   menu_label = gtk_notebook_get_menu_label (notebook, child);
 
-  if (menu_label && GTK_IS_LABEL (menu_label))
+  if (GTK_IS_LABEL (menu_label))
     return gtk_label_get_text (GTK_LABEL (menu_label));
   else
     return NULL;
@@ -6976,10 +7486,13 @@ gtk_notebook_child_reordered (GtkNotebook     *notebook,
  * @expand: whether to expand the bookmark or not
  * @fill: whether the bookmark should fill the allocated area or not
  * @pack_type: the position of the bookmark
- * 
+ *
  * Sets the packing parameters for the tab label of the page
  * containing @child. See gtk_box_pack_start() for the exact meaning
  * of the parameters.
+ *
+ * Deprecated: 2.20: Modify the "tab-expand" and "tab-fill" child
+ *   properties instead.
  **/
 void
 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
@@ -7031,6 +7544,9 @@ gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
  * 
  * Query the packing attributes for the tab label of the page
  * containing @child.
+ *
+ * Deprecated: 2.20: Modify the "tab-expand" and "tab-fill" child
+ *   properties instead.
  **/
 void
 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
@@ -7126,8 +7642,9 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
 
 /**
  * gtk_notebook_set_window_creation_hook:
- * @func: the #GtkNotebookWindowCreationFunc, or NULL
- * @data: user data for @func.
+ * @func: the #GtkNotebookWindowCreationFunc, or %NULL
+ * @data: user data for @func
+ * @destroy: Destroy notifier for @data, or %NULL
  *
  * Installs a global function used to create a window
  * when a detached tab is dropped in an empty area.
@@ -7136,10 +7653,15 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
  **/
 void
 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
-                                      gpointer                       data)
+                                      gpointer                       data,
+                                       GDestroyNotify                 destroy)
 {
+  if (window_creation_hook_destroy)
+    window_creation_hook_destroy (window_creation_hook_data);
+
   window_creation_hook = func;
   window_creation_hook_data = data;
+  window_creation_hook_destroy = destroy;
 }
 
 /**
@@ -7153,10 +7675,36 @@ gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
  * not be able to exchange tabs with any other notebook.
  * 
  * Since: 2.10
- **/
+ * Deprecated: 2.12: use gtk_notebook_set_group() instead.
+ */
 void
 gtk_notebook_set_group_id (GtkNotebook *notebook,
                           gint         group_id)
+{
+  gpointer group;
+
+  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+  /* add 1 to get rid of the -1/NULL difference */
+  group = GINT_TO_POINTER (group_id + 1);
+  gtk_notebook_set_group (notebook, group);
+}
+
+/**
+ * gtk_notebook_set_group:
+ * @notebook: a #GtkNotebook
+ * @group: a pointer to identify the notebook group, or %NULL to unset it
+ *
+ * Sets a group identificator pointer for @notebook, notebooks sharing
+ * the same group identificator pointer will be able to exchange tabs
+ * via drag and drop. A notebook with a %NULL group identificator will
+ * not be able to exchange tabs with any other notebook.
+ * 
+ * Since: 2.12
+ */
+void
+gtk_notebook_set_group (GtkNotebook *notebook,
+                       gpointer     group)
 {
   GtkNotebookPrivate *priv;
 
@@ -7164,10 +7712,11 @@ gtk_notebook_set_group_id (GtkNotebook *notebook,
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
 
-  if (priv->group_id != group_id)
+  if (priv->group != group)
     {
-      priv->group_id = group_id;
+      priv->group = group;
       g_object_notify (G_OBJECT (notebook), "group-id");
+      g_object_notify (G_OBJECT (notebook), "group");
     }
 }
 
@@ -7180,7 +7729,8 @@ gtk_notebook_set_group_id (GtkNotebook *notebook,
  * Return Value: the group identificator, or -1 if none is set.
  *
  * Since: 2.10
- **/
+ * Deprecated: 2.12: use gtk_notebook_get_group() instead.
+ */
 gint
 gtk_notebook_get_group_id (GtkNotebook *notebook)
 {
@@ -7189,7 +7739,30 @@ gtk_notebook_get_group_id (GtkNotebook *notebook)
   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  return priv->group_id;
+
+  /* substract 1 to get rid of the -1/NULL difference */
+  return GPOINTER_TO_INT (priv->group) - 1;
+}
+
+/**
+ * gtk_notebook_get_group:
+ * @notebook: a #GtkNotebook
+ * 
+ * Gets the current group identificator pointer for @notebook.
+ * 
+ * Return Value: the group identificator, or %NULL if none is set.
+ *
+ * Since: 2.12
+ **/
+gpointer
+gtk_notebook_get_group (GtkNotebook *notebook)
+{
+  GtkNotebookPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+  return priv->group;
 }
 
 /**
@@ -7296,8 +7869,7 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
  * will fill the selection with a GtkWidget** pointing to the child
  * widget that corresponds to the dropped tab.
- *
- * <informalexample><programlisting>
+ * |[
  *  static void
  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
  *                                   GdkDragContext   *context,
@@ -7317,7 +7889,7 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
  *    process_widget (*child);
  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
  *  }
- * </programlisting></informalexample>
+ * ]|
  *
  * If you want a notebook to accept drags from other widgets,
  * you will have to set your own DnD code to do it.
@@ -7345,5 +7917,73 @@ gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
     }
 }
 
+/**
+ * gtk_notebook_get_action_widget:
+ * @notebook: a #GtkNotebook
+ * @pack_type: pack type of the action widget to receive
+ *
+ * Gets one of the action widgets. See gtk_notebook_set_action_widget().
+ *
+ * Returns: The action widget with the given @pack_type or
+ *     %NULL when this action widget has not been set
+ *
+ * Since: 2.20
+ */
+GtkWidget*
+gtk_notebook_get_action_widget (GtkNotebook *notebook,
+                                GtkPackType  pack_type)
+{
+  GtkNotebookPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+  return priv->action_widget[pack_type];
+}
+
+/**
+ * gtk_notebook_set_action_widget:
+ * @notebook: a #GtkNotebook
+ * @widget: a #GtkWidget
+ * @pack_type: pack type of the action widget
+ *
+ * Sets @widget as one of the action widgets. Depending on the pack type
+ * the widget will be placed before or after the tabs. You can use
+ * a #GtkBox if you need to pack more than one widget on the same side.
+ *
+ * Note that action widgets are "internal" children of the notebook and thus
+ * not included in the list returned from gtk_container_foreach().
+ *
+ * Since: 2.20
+ */
+void
+gtk_notebook_set_action_widget (GtkNotebook *notebook,
+                               GtkWidget   *widget,
+                                GtkPackType  pack_type)
+{
+  GtkNotebookPrivate *priv;
+
+  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
+  g_return_if_fail (!widget || widget->parent == NULL);
+
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+  if (priv->action_widget[pack_type])
+    gtk_widget_unparent (priv->action_widget[pack_type]);
+
+  priv->action_widget[pack_type] = widget;
+
+  if (widget)
+    {
+      gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
+
+      if (GTK_WIDGET_REALIZED (GTK_WIDGET (notebook)))
+       gtk_widget_realize (widget);
+    }
+
+  gtk_widget_queue_resize (GTK_WIDGET (notebook));
+}
+
 #define __GTK_NOTEBOOK_C__
 #include "gtkaliasdef.c"