]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtknotebook.c
Stop scrolling when the widget is unmapped. (#168791, Ryan Lortie)
[~andy/gtk] / gtk / gtknotebook.c
index 962e7f3df56bf38308742c86984620b10ec7961e..0c42e2003b658c2098939b47701cf8fd00b208cf 100644 (file)
@@ -24,8 +24,8 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include <config.h>
 #include "gtknotebook.h"
-#include "gtksignal.h"
 #include "gtkmain.h"
 #include "gtkmenu.h"
 #include "gtkmenuitem.h"
@@ -35,6 +35,8 @@
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkbindings.h"
+#include "gtkprivate.h"
+#include "gtkalias.h"
 
 
 #define TAB_OVERLAP    2
@@ -50,6 +52,7 @@ enum {
   FOCUS_TAB,
   SELECT_PAGE,
   CHANGE_CURRENT_PAGE,
+  MOVE_FOCUS_OUT,
   LAST_SIGNAL
 };
 
@@ -58,6 +61,18 @@ enum {
   STEP_NEXT
 };
 
+typedef enum
+{
+  ARROW_NONE,
+  ARROW_LEFT_BEFORE,
+  ARROW_RIGHT_BEFORE,
+  ARROW_LEFT_AFTER,
+  ARROW_RIGHT_AFTER
+} GtkNotebookArrow;
+
+#define ARROW_IS_LEFT(arrow)  ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
+#define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
+
 enum {
   PROP_0,
   PROP_TAB_POS,
@@ -115,13 +130,14 @@ struct _GtkNotebookPage
 static void gtk_notebook_class_init          (GtkNotebookClass *klass);
 static void gtk_notebook_init                (GtkNotebook      *notebook);
 
-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,
-                                             gint               offset);
-
+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,
+                                                 gint              offset);
+static void     gtk_notebook_move_focus_out      (GtkNotebook      *notebook,
+                                                 GtkDirectionType  direction_type);
 
 /*** GtkObject Methods ***/
 static void gtk_notebook_destroy             (GtkObject        *object);
@@ -145,6 +161,8 @@ static void gtk_notebook_size_allocate       (GtkWidget        *widget,
                                              GtkAllocation    *allocation);
 static gint gtk_notebook_expose              (GtkWidget        *widget,
                                              GdkEventExpose   *event);
+static gboolean gtk_notebook_scroll          (GtkWidget        *widget,
+                                              GdkEventScroll   *event);
 static gint gtk_notebook_button_press        (GtkWidget        *widget,
                                              GdkEventButton   *event);
 static gint gtk_notebook_button_release      (GtkWidget        *widget,
@@ -157,9 +175,17 @@ static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
                                              GdkEventMotion   *event);
 static gint gtk_notebook_focus_in            (GtkWidget        *widget,
                                              GdkEventFocus    *event);
+static gint gtk_notebook_focus_out           (GtkWidget        *widget,
+                                             GdkEventFocus    *event);
+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 gint gtk_notebook_focus               (GtkWidget        *widget,
                                              GtkDirectionType  direction);
+static void gtk_notebook_style_set           (GtkWidget        *widget,
+                                             GtkStyle         *previous);
 
 /*** GtkContainer Methods ***/
 static void gtk_notebook_set_child_property  (GtkContainer     *container,
@@ -178,7 +204,7 @@ static void gtk_notebook_remove              (GtkContainer     *container,
                                              GtkWidget        *widget);
 static void gtk_notebook_set_focus_child     (GtkContainer     *container,
                                              GtkWidget        *child);
-static GtkType gtk_notebook_child_type       (GtkContainer     *container);
+static GType gtk_notebook_child_type       (GtkContainer     *container);
 static void gtk_notebook_forall              (GtkContainer     *container,
                                              gboolean          include_internals,
                                              GtkCallback       callback,
@@ -187,10 +213,9 @@ static void gtk_notebook_forall              (GtkContainer     *container,
 /*** GtkNotebook Private Functions ***/
 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
-static void gtk_notebook_focus_changed       (GtkNotebook      *notebook,
-                                             GtkNotebookPage  *old_page);
 static void gtk_notebook_real_remove         (GtkNotebook      *notebook,
-                                             GList            *list);
+                                             GList            *list,
+                                             gboolean          destroying);
 static void gtk_notebook_update_labels       (GtkNotebook      *notebook);
 static gint gtk_notebook_timer               (GtkNotebook      *notebook);
 static gint gtk_notebook_page_compare        (gconstpointer     a,
@@ -212,7 +237,7 @@ static void gtk_notebook_draw_tab            (GtkNotebook      *notebook,
                                              GtkNotebookPage  *page,
                                              GdkRectangle     *area);
 static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
-                                             guint             arrow);
+                                             GtkNotebookArrow  arrow);
 
 /*** GtkNotebook Size Allocate Functions ***/
 static void gtk_notebook_pages_allocate      (GtkNotebook      *notebook);
@@ -249,35 +274,81 @@ static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
 static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
                                              GtkMenu          *menu);
 
+/*** GtkNotebook Private Setters ***/
+static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
+                                                       gboolean     homogeneous);
+static void gtk_notebook_set_tab_border_internal       (GtkNotebook *notebook,
+                                                       guint        border_width);
+static void gtk_notebook_set_tab_hborder_internal      (GtkNotebook *notebook,
+                                                       guint        tab_hborder);
+static void gtk_notebook_set_tab_vborder_internal      (GtkNotebook *notebook,
+                                                       guint        tab_vborder);
+
+static gboolean focus_tabs_in  (GtkNotebook      *notebook);
+static gboolean focus_child_in (GtkNotebook      *notebook,
+                               GtkDirectionType  direction);
+
+static void stop_scrolling (GtkNotebook *notebook);
+
 
 static GtkContainerClass *parent_class = NULL;
 static guint notebook_signals[LAST_SIGNAL] = { 0 };
 
-GtkType
+GType
 gtk_notebook_get_type (void)
 {
-  static GtkType notebook_type = 0;
+  static GType notebook_type = 0;
 
   if (!notebook_type)
     {
-      static const GtkTypeInfo notebook_info =
+      static const GTypeInfo notebook_info =
       {
-       "GtkNotebook",
-       sizeof (GtkNotebook),
        sizeof (GtkNotebookClass),
-       (GtkClassInitFunc) gtk_notebook_class_init,
-       (GtkObjectInitFunc) gtk_notebook_init,
-       /* reserved_1 */ NULL,
-        /* reserved_2 */ NULL,
-        (GtkClassInitFunc) NULL,
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) gtk_notebook_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (GtkNotebook),
+       0,              /* n_preallocs */
+       (GInstanceInitFunc) gtk_notebook_init,
       };
 
-      notebook_type = gtk_type_unique (gtk_container_get_type (), &notebook_info);
+      notebook_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkNotebook",
+                                             &notebook_info, 0);
     }
 
   return notebook_type;
 }
 
+static void
+add_tab_bindings (GtkBindingSet    *binding_set,
+                 GdkModifierType   modifiers,
+                 GtkDirectionType  direction)
+{
+  gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
+                                "move_focus_out", 1,
+                                GTK_TYPE_DIRECTION_TYPE, direction);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
+                                "move_focus_out", 1,
+                                GTK_TYPE_DIRECTION_TYPE, direction);
+}
+
+static void
+add_arrow_bindings (GtkBindingSet    *binding_set,
+                   guint             keysym,
+                   GtkDirectionType  direction)
+{
+  guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
+  
+  gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
+                                "move_focus_out", 1,
+                                GTK_TYPE_DIRECTION_TYPE, direction);
+  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
+                                "move_focus_out", 1,
+                                GTK_TYPE_DIRECTION_TYPE, direction);
+}
+
 static void
 gtk_notebook_class_init (GtkNotebookClass *class)
 {
@@ -300,13 +371,18 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   widget_class->size_request = gtk_notebook_size_request;
   widget_class->size_allocate = gtk_notebook_size_allocate;
   widget_class->expose_event = gtk_notebook_expose;
+  widget_class->scroll_event = gtk_notebook_scroll;
   widget_class->button_press_event = gtk_notebook_button_press;
   widget_class->button_release_event = gtk_notebook_button_release;
   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;
+  widget_class->state_changed = gtk_notebook_state_changed;
   widget_class->focus_in_event = gtk_notebook_focus_in;
+  widget_class->focus_out_event = gtk_notebook_focus_out;
   widget_class->focus = gtk_notebook_focus;
+  widget_class->style_set = gtk_notebook_style_set;
   
   container_class->add = gtk_notebook_add;
   container_class->remove = gtk_notebook_remove;
@@ -321,139 +397,219 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   class->focus_tab = gtk_notebook_focus_tab;
   class->select_page = gtk_notebook_select_page;
   class->change_current_page = gtk_notebook_change_current_page;
+  class->move_focus_out = gtk_notebook_move_focus_out;
   
   g_object_class_install_property (gobject_class,
                                   PROP_PAGE,
                                   g_param_spec_int ("page",
-                                                    _("Page"),
-                                                    _("The index of the current page"),
+                                                    P_("Page"),
+                                                    P_("The index of the current page"),
                                                     0,
                                                     G_MAXINT,
                                                     0,
-                                                    G_PARAM_READWRITE));
+                                                    GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_POS,
-                                  g_param_spec_enum ("tab_pos",
-                                                     _("Tab Position"),
-                                                     _("Which side of the notebook holds the tabs"),
+                                  g_param_spec_enum ("tab-pos",
+                                                     P_("Tab Position"),
+                                                     P_("Which side of the notebook holds the tabs"),
                                                      GTK_TYPE_POSITION_TYPE,
                                                      GTK_POS_TOP,
-                                                     G_PARAM_READWRITE));
+                                                     GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_BORDER,
-                                  g_param_spec_uint ("tab_border",
-                                                     _("Tab Border"),
-                                                     _("Width of the border around the tab labels"),
+                                  g_param_spec_uint ("tab-border",
+                                                     P_("Tab Border"),
+                                                     P_("Width of the border around the tab labels"),
                                                      0,
                                                      G_MAXUINT,
                                                      2,
-                                                     G_PARAM_WRITABLE));
+                                                     GTK_PARAM_WRITABLE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_HBORDER,
-                                  g_param_spec_uint ("tab_hborder",
-                                                     _("Horizontal Tab Border"),
-                                                     _("Width of the horizontal border of tab labels"),
+                                  g_param_spec_uint ("tab-hborder",
+                                                     P_("Horizontal Tab Border"),
+                                                     P_("Width of the horizontal border of tab labels"),
                                                      0,
                                                      G_MAXUINT,
                                                      2,
-                                                     G_PARAM_READWRITE));
+                                                     GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_VBORDER,
-                                  g_param_spec_uint ("tab_vborder",
-                                                     _("Vertical Tab Border"),
-                                                     _("Width of the vertical border of tab labels"),
+                                  g_param_spec_uint ("tab-vborder",
+                                                     P_("Vertical Tab Border"),
+                                                     P_("Width of the vertical border of tab labels"),
                                                      0,
                                                      G_MAXUINT,
                                                      2,
-                                                     G_PARAM_READWRITE));
+                                                     GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_SHOW_TABS,
-                                  g_param_spec_boolean ("show_tabs",
-                                                        _("Show Tabs"),
-                                                        _("Whether tabs should be shown or not"),
+                                  g_param_spec_boolean ("show-tabs",
+                                                        P_("Show Tabs"),
+                                                        P_("Whether tabs should be shown or not"),
                                                         TRUE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_SHOW_BORDER,
-                                  g_param_spec_boolean ("show_border",
-                                                        _("Show Border"),
-                                                        _("Whether the border should be shown or not"),
+                                  g_param_spec_boolean ("show-border",
+                                                        P_("Show Border"),
+                                                        P_("Whether the border should be shown or not"),
                                                         TRUE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_SCROLLABLE,
                                   g_param_spec_boolean ("scrollable",
-                                                        _("Scrollable"),
-                                                        _("If TRUE, scroll arrows are added if there are to many tabs to fit"),
+                                                        P_("Scrollable"),
+                                                        P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
                                                         FALSE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_ENABLE_POPUP,
-                                  g_param_spec_boolean ("enable_popup",
-                                                        _("Enable Popup"),
-                                                        _("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
+                                  g_param_spec_boolean ("enable-popup",
+                                                        P_("Enable Popup"),
+                                                        P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
                                                         FALSE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_HOMOGENEOUS,
                                   g_param_spec_boolean ("homogeneous",
-                                                        _("Homogeneous"),
-                                                        _("Whether tabs should have homogeneous sizes"),
+                                                        P_("Homogeneous"),
+                                                        P_("Whether tabs should have homogeneous sizes"),
                                                         FALSE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
 
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_LABEL,
-                                             g_param_spec_string ("tab_label", NULL, NULL,
+                                             g_param_spec_string ("tab-label", 
+                                                                  P_("Tab label"),
+                                                                  P_("The string displayed on the child's tab label"),
                                                                   NULL,
-                                                                  G_PARAM_READWRITE));
+                                                                  GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_MENU_LABEL,
-                                             g_param_spec_string ("menu_label", NULL, NULL,
+                                             g_param_spec_string ("menu-label", 
+                                                                  P_("Menu label"), 
+                                                                  P_("The string displayed in the child's menu entry"),
                                                                   NULL,
-                                                                  G_PARAM_READWRITE));
+                                                                  GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_POSITION,
-                                             g_param_spec_int ("position", NULL, NULL,
+                                             g_param_spec_int ("position", 
+                                                               P_("Position"), 
+                                                               P_("The index of the child in the parent"),
                                                                -1, G_MAXINT, 0,
-                                                               G_PARAM_READWRITE));
+                                                               GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_EXPAND,
-                                             g_param_spec_boolean ("tab_expand", NULL, NULL,
+                                             g_param_spec_boolean ("tab-expand", 
+                                                                   P_("Tab expand"), 
+                                                                   P_("Whether to expand the child's tab or not"),
                                                                    TRUE,
-                                                                   G_PARAM_READWRITE));
+                                                                   GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_FILL,
-                                             g_param_spec_boolean ("tab_fill", NULL, NULL,
+                                             g_param_spec_boolean ("tab-fill", 
+                                                                   P_("Tab fill"), 
+                                                                   P_("Whether the child's tab should fill the allocated area or not"),
                                                                    TRUE,
-                                                                   G_PARAM_READWRITE));
+                                                                   GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_PACK,
-                                             g_param_spec_enum ("tab_pack", NULL, NULL,
+                                             g_param_spec_enum ("tab-pack", 
+                                                                P_("Tab pack type"),
+                                                                P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
                                                                 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
-                                                                G_PARAM_READWRITE));
-  
+                                                                GTK_PARAM_READWRITE));
+
+/**
+ * GtkNotebook:has-secondary-backward-stepper:
+ *
+ * The "has-secondary-backward-stepper" property determines whether 
+ * a second backward arrow button is displayed on the opposite end 
+ * of the tab area.
+ *
+ * Since: 2.4
+ */  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has-secondary-backward-stepper",
+                                                                P_("Secondary backward stepper"),
+                                                                P_("Display a second backward arrow button on the opposite end of the tab area"),
+                                                                FALSE,
+                                                                
+                                                                GTK_PARAM_READABLE));
+
+/**
+ * GtkNotebook:has-secondary-forward-stepper:
+ *
+ * The "has-secondary-forward-stepper" property determines whether 
+ * a second forward arrow button is displayed on the opposite end 
+ * of the tab area.
+ *
+ * Since: 2.4
+ */  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has-secondary-forward-stepper",
+                                                                P_("Secondary forward stepper"),
+                                                                P_("Display a second forward arrow button on the opposite end of the tab area"),
+                                                                FALSE,
+                                                                
+                                                                GTK_PARAM_READABLE));
+
+/**
+ * GtkNotebook:has-backward-stepper:
+ *
+ * The "has-backward-stepper" property determines whether 
+ * the standard backward arrow button is displayed.
+ *
+ * Since: 2.4
+ */  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has-backward-stepper",
+                                                                P_("Backward stepper"),
+                                                                P_("Display the standard backward arrow button"),
+                                                                TRUE,
+                                                                
+                                                                   GTK_PARAM_READABLE));
+
+/**
+ * GtkNotebook:has-forward-stepper:
+ *
+ * The "has-forward-stepper" property determines whether 
+ * the standard forward arrow button is displayed.
+ *
+ * Since: 2.4
+ */  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has-forward-stepper",
+                                                                P_("Forward stepper"),
+                                                                P_("Display the standard forward arrow button"),
+                                                                TRUE,
+                                                                
+                                                                   GTK_PARAM_READABLE));
+
   notebook_signals[SWITCH_PAGE] =
-    gtk_signal_new ("switch_page",
-                   GTK_RUN_LAST,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkNotebookClass, switch_page),
-                   _gtk_marshal_VOID__POINTER_UINT,
-                   GTK_TYPE_NONE, 2,
-                   GTK_TYPE_POINTER,
-                   GTK_TYPE_UINT);
+    g_signal_new ("switch_page",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__POINTER_UINT,
+                 G_TYPE_NONE, 2,
+                 G_TYPE_POINTER,
+                 G_TYPE_UINT);
   notebook_signals[FOCUS_TAB] = 
     g_signal_new ("focus_tab",
-                  G_TYPE_FROM_CLASS (object_class),
+                  G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
                   NULL, NULL,
                   _gtk_marshal_BOOLEAN__ENUM,
-                  G_TYPE_NONE, 1,
+                  G_TYPE_BOOLEAN, 1,
                   GTK_TYPE_NOTEBOOK_TAB);
   notebook_signals[SELECT_PAGE] = 
     g_signal_new ("select_page",
-                  G_TYPE_FROM_CLASS (object_class),
+                  G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, select_page),
                   NULL, NULL,
@@ -462,23 +618,25 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                   G_TYPE_BOOLEAN);
   notebook_signals[CHANGE_CURRENT_PAGE] = 
     g_signal_new ("change_current_page",
-                  G_TYPE_FROM_CLASS (object_class),
+                  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_BOOLEAN, 1,
+                  _gtk_marshal_VOID__INT,
+                  G_TYPE_NONE, 1,
                   G_TYPE_INT);
+  notebook_signals[MOVE_FOCUS_OUT] =
+    g_signal_new ("move_focus_out",
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
+                  NULL, NULL,
+                  _gtk_marshal_VOID__ENUM,
+                  G_TYPE_NONE, 1,
+                  GTK_TYPE_DIRECTION_TYPE);
   
-  binding_set = gtk_binding_set_by_class (object_class);
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_Return, 0,
-                                "select_page", 1, 
-                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_KP_Enter, 0,
-                                "select_page", 1, 
-                                G_TYPE_BOOLEAN, TRUE);
+  
+  binding_set = gtk_binding_set_by_class (class);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_space, 0,
                                 "select_page", 1, 
@@ -513,12 +671,29 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                                 GDK_Page_Down, GDK_CONTROL_MASK,
                                 "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,
+                                G_TYPE_INT, -1);
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
+                                "change_current_page", 1,
+                                G_TYPE_INT, 1);
+
+  add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
+  add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
+  add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
+  add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
+
+  add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
+  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
 }
 
 static void
 gtk_notebook_init (GtkNotebook *notebook)
 {
-  GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
+  GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
   GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
 
   notebook->cur_page = NULL;
@@ -541,6 +716,12 @@ gtk_notebook_init (GtkNotebook *notebook)
   notebook->need_timer = 0;
   notebook->child_has_focus = FALSE;
   notebook->have_visible_child = FALSE;
+  notebook->focus_out = FALSE;
+
+  notebook->has_before_previous = 1;
+  notebook->has_before_next     = 0;
+  notebook->has_after_previous  = 0;
+  notebook->has_after_next      = 1;
 }
 
 static gboolean
@@ -601,6 +782,85 @@ gtk_notebook_change_current_page (GtkNotebook *notebook,
 
   if (current)
     gtk_notebook_switch_page (notebook, current->data, -1);
+  else
+    gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
+}
+
+static GtkDirectionType
+get_effective_direction (GtkNotebook      *notebook,
+                        GtkDirectionType  direction)
+{
+  /* Remap the directions into the effective direction it would be for a
+   * GTK_POS_TOP notebook
+   */
+
+#define D(rest) GTK_DIR_##rest
+
+  static const GtkDirectionType translate_direction[2][4][6] = {
+    /* LEFT */   {{ D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
+    /* RIGHT */  { D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
+    /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(LEFT), D(RIGHT) },
+    /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(LEFT), D(RIGHT) }},
+    /* LEFT */  {{ D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
+    /* RIGHT */  { D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
+    /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(RIGHT), D(LEFT) },
+    /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(RIGHT), D(LEFT) }},
+  };
+
+#undef D
+
+  int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
+
+  return translate_direction[text_dir][notebook->tab_pos][direction];
+}
+
+static gint
+get_effective_tab_pos (GtkNotebook *notebook)
+{
+  if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
+    {
+      switch (notebook->tab_pos) 
+       {
+       case GTK_POS_LEFT:
+         return GTK_POS_RIGHT;
+       case GTK_POS_RIGHT:
+         return GTK_POS_LEFT;
+       default: ;
+       }
+    }
+
+  return notebook->tab_pos;
+}
+
+static void
+gtk_notebook_move_focus_out (GtkNotebook      *notebook,
+                            GtkDirectionType  direction_type)
+{
+  GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
+  GtkWidget *toplevel;
+  
+  if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
+    if (focus_tabs_in (notebook))
+      return;
+  if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
+    if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
+      return;
+
+  /* At this point, we know we should be focusing out of the notebook entirely. We
+   * 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))
+    return;
+
+  g_object_ref (notebook);
+  
+  notebook->focus_out = TRUE;
+  g_signal_emit_by_name (toplevel, "move_focus", direction_type);
+  notebook->focus_out = FALSE;
+  
+  g_object_unref (notebook);
+
 }
 
 /**
@@ -613,7 +873,7 @@ gtk_notebook_change_current_page (GtkNotebook *notebook,
 GtkWidget*
 gtk_notebook_new (void)
 {
-  return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ()));
+  return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
 }
 
 /* Private GtkObject Methods :
@@ -625,11 +885,21 @@ gtk_notebook_new (void)
 static void
 gtk_notebook_destroy (GtkObject *object)
 {
+  GList *children;
   GtkNotebook *notebook = GTK_NOTEBOOK (object);
   
   if (notebook->menu)
     gtk_notebook_popup_disable (notebook);
 
+  children = notebook->children;
+  while (children)
+    {
+      GList *child = children;
+      children = child->next;
+      
+      gtk_notebook_real_remove (notebook, child, TRUE);
+    }
+  
   GTK_OBJECT_CLASS (parent_class)->destroy (object);
 }
 
@@ -661,7 +931,7 @@ gtk_notebook_set_property (GObject         *object,
        gtk_notebook_popup_disable (notebook);
       break;
     case PROP_HOMOGENEOUS:
-      gtk_notebook_set_homogeneous_tabs (notebook, g_value_get_boolean (value));
+      gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
       break;  
     case PROP_PAGE:
       gtk_notebook_set_current_page (notebook, g_value_get_int (value));
@@ -670,13 +940,13 @@ gtk_notebook_set_property (GObject         *object,
       gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
       break;
     case PROP_TAB_BORDER:
-      gtk_notebook_set_tab_border (notebook, g_value_get_uint (value));
+      gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
       break;
     case PROP_TAB_HBORDER:
-      gtk_notebook_set_tab_hborder (notebook, g_value_get_uint (value));
+      gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
       break;
     case PROP_TAB_VBORDER:
-      gtk_notebook_set_tab_vborder (notebook, g_value_get_uint (value));
+      gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
       break;
     default:
       break;
@@ -736,6 +1006,7 @@ gtk_notebook_get_property (GObject         *object,
  * gtk_notebook_size_request
  * gtk_notebook_size_allocate
  * gtk_notebook_expose
+ * gtk_notebook_scroll
  * gtk_notebook_button_press
  * gtk_notebook_button_release
  * gtk_notebook_enter_notify
@@ -752,30 +1023,41 @@ gtk_notebook_get_event_window_position (GtkNotebook  *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);
 
-  if (notebook->show_tabs && notebook->children)
+  for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
     {
-      if (rectangle)
+      GtkNotebookPage *page = tmp_list->data;
+      if (GTK_WIDGET_VISIBLE (page->child))
        {
-         GtkNotebookPage *page = notebook->children->data;
+         visible_page = page;
+         break;
+       }
+    }
 
+  if (notebook->show_tabs && visible_page)
+    {
+      if (rectangle)
+       {
          rectangle->x = widget->allocation.x + border_width;
          rectangle->y = widget->allocation.y + border_width;
          
-         switch (notebook->tab_pos)
+         switch (tab_pos)
            {
            case GTK_POS_TOP:
            case GTK_POS_BOTTOM:
              rectangle->width = widget->allocation.width - 2 * border_width;
-             rectangle->height = page->requisition.height;
-             if (notebook->tab_pos == GTK_POS_BOTTOM)
+             rectangle->height = visible_page->requisition.height;
+             if (tab_pos == GTK_POS_BOTTOM)
                rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
              break;
            case GTK_POS_LEFT:
            case GTK_POS_RIGHT:
-             rectangle->width = page->requisition.width;
+             rectangle->width = visible_page->requisition.width;
              rectangle->height = widget->allocation.height - 2 * border_width;
-             if (notebook->tab_pos == GTK_POS_RIGHT)
+             if (tab_pos == GTK_POS_RIGHT)
                rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
              break;
            }
@@ -840,6 +1122,8 @@ 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);
 
   gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
@@ -863,7 +1147,7 @@ gtk_notebook_realize (GtkWidget *widget)
   gtk_notebook_get_event_window_position (notebook, &event_window_pos);
   
   widget->window = gtk_widget_get_parent_window (widget);
-  gdk_window_ref (widget->window);
+  g_object_ref (widget->window);
   
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.x = event_window_pos.x;
@@ -872,9 +1156,9 @@ gtk_notebook_realize (GtkWidget *widget)
   attributes.height = event_window_pos.height;
   attributes.wclass = GDK_INPUT_ONLY;
   attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
-                           GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
-
+  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
+                           GDK_SCROLL_MASK);
   attributes_mask = GDK_WA_X | GDK_WA_Y;
 
   notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), 
@@ -1057,7 +1341,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
 
                  if (notebook->scrollable && vis_pages > 1 && 
                      widget->requisition.height < tab_height)
-                   tab_width = MAX (tab_width, ARROW_SPACING +2 * ARROW_SIZE);
+                   tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
 
                  padding = 2 * (TAB_CURVATURE + focus_width +
                                 notebook->tab_vborder) - TAB_OVERLAP;
@@ -1159,6 +1443,7 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   gint vis_pages = 0;
+  gint tab_pos = get_effective_tab_pos (notebook);
 
   widget->allocation = *allocation;
   if (GTK_WIDGET_REALIZED (widget))
@@ -1166,9 +1451,15 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
       GdkRectangle position;
 
       if (gtk_notebook_get_event_window_position (notebook, &position))
-       gdk_window_move_resize (notebook->event_window,
-                               position.x, position.y,
-                               position.width, position.height);
+       {
+         gdk_window_move_resize (notebook->event_window,
+                                 position.x, position.y,
+                                 position.width, position.height);
+         if (GTK_WIDGET_MAPPED (notebook))
+           gdk_window_show_unraised (notebook->event_window);
+       }
+      else
+       gdk_window_hide (notebook->event_window);
     }
 
   if (notebook->children)
@@ -1194,7 +1485,7 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
 
          if (notebook->show_tabs && notebook->children && notebook->cur_page)
            {
-             switch (notebook->tab_pos)
+             switch (tab_pos)
                {
                case GTK_POS_TOP:
                  child_allocation.y += notebook->cur_page->requisition.height;
@@ -1229,13 +1520,6 @@ gtk_notebook_size_allocate (GtkWidget     *widget,
 
       gtk_notebook_pages_allocate (notebook);
     }
-
-  if ((vis_pages != 0) != notebook->have_visible_child)
-    {
-      notebook->have_visible_child = (vis_pages != 0);
-      if (notebook->show_tabs)
-       gtk_widget_queue_draw (widget);
-    }
 }
 
 static gint
@@ -1295,67 +1579,130 @@ gtk_notebook_show_arrows (GtkNotebook *notebook)
 }
 
 static void
-gtk_notebook_get_arrow_rect (GtkNotebook  *notebook,
-                            GdkRectangle *rectangle)
+gtk_notebook_get_arrow_rect (GtkNotebook     *notebook,
+                            GdkRectangle    *rectangle,
+                            GtkNotebookArrow arrow)
 {
   GdkRectangle event_window_pos;
+  gboolean before = ARROW_IS_BEFORE (arrow);
+  gboolean left = ARROW_IS_LEFT (arrow);
 
   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
     {
-      rectangle->width = 2 * ARROW_SIZE + ARROW_SPACING;
+      rectangle->width = ARROW_SIZE;
       rectangle->height = ARROW_SIZE;
 
       switch (notebook->tab_pos)
        {
        case GTK_POS_LEFT:
        case GTK_POS_RIGHT:
+         if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
+             (!before && (notebook->has_after_previous != notebook->has_after_next))) 
          rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
-         rectangle->y = event_window_pos.y + event_window_pos.height - rectangle->height;
+         else if (left)
+           rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
+         else 
+           rectangle->x = event_window_pos.x + event_window_pos.width / 2;
+         rectangle->y = event_window_pos.y;
+         if (!before)
+           rectangle->y += event_window_pos.height - rectangle->height;
          break;
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
-         rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
+         if (before)
+           {
+             if (left || !notebook->has_before_previous)
+               rectangle->x = event_window_pos.x;
+             else
+               rectangle->x = event_window_pos.x + rectangle->width;
+           }
+         else
+           {
+             if (!left || !notebook->has_after_next)
+               rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
+             else
+               rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
+           }
          rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
          break;
        }
     }
 }
 
-static GtkArrowType
+static GtkNotebookArrow
 gtk_notebook_get_arrow (GtkNotebook *notebook,
                        gint         x,
                        gint         y)
 {
   GdkRectangle arrow_rect;
   GdkRectangle event_window_pos;
+  gint i;
+  gint x0, y0;
+  GtkNotebookArrow arrow[4];
+
+  arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
+  arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
+  arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
+  arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
 
   if (gtk_notebook_show_arrows (notebook))
     {
       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
-      gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
+      for (i = 0; i < 4; i++) 
+       { 
+         if (arrow[i] == ARROW_NONE)
+           continue;
       
-      x -= arrow_rect.x;
-      y -= arrow_rect.y;
+         gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
       
-      if (y >= 0 && y < arrow_rect.height)
-       {
-         if (x >= 0 && x < ARROW_SIZE + ARROW_SPACING / 2)
-           return GTK_ARROW_LEFT;
-         else if (x >= ARROW_SIZE + ARROW_SPACING / 2 && x < arrow_rect.width)
-           return GTK_ARROW_RIGHT;
+         x0 = x - arrow_rect.x;
+         y0 = y - arrow_rect.y;
+         
+         if (y0 >= 0 && y0 < arrow_rect.height &&
+             x0 >= 0 && x0 < arrow_rect.width)
+           return arrow[i];
        }
     }
-      
-  return 0;
+
+  return ARROW_NONE;
 }
 
-static gboolean
-gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
-                                GtkArrowType    arrow,
-                                GdkEventButton *event)
+static void
+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;
+  left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
+         (!ARROW_IS_LEFT (arrow) && is_rtl);
   
+  if (!notebook->focus_tab ||
+      gtk_notebook_search_page (notebook, notebook->focus_tab,
+                               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);
+    }
+}
+
+static gboolean
+gtk_notebook_arrow_button_press (GtkNotebook      *notebook,
+                                GtkNotebookArrow  arrow,
+                                GdkEventButton   *event)
+{
+  GtkWidget *widget = GTK_WIDGET (notebook);
+  gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+  gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
+                  (!ARROW_IS_LEFT (arrow) && is_rtl);
+
   if (!GTK_WIDGET_HAS_FOCUS (widget))
     gtk_widget_grab_focus (widget);
   
@@ -1364,25 +1711,13 @@ gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
   
   if (event->button == 1)
     {
-      GtkDirectionType dir;
-      if (!notebook->focus_tab ||
-         gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                   arrow == GTK_ARROW_LEFT ? STEP_PREV : STEP_NEXT,
-                                   TRUE))
-       {
-         if (notebook->tab_pos == GTK_POS_LEFT ||
-             notebook->tab_pos == GTK_POS_RIGHT)
-           dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_UP : GTK_DIR_DOWN;
-         else
-           dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
-         gtk_widget_child_focus (widget, dir);
-       }
+      gtk_notebook_do_arrow (notebook, arrow);
       
       if (!notebook->timer)
        {
-         notebook->timer = gtk_timeout_add 
-           (NOTEBOOK_INIT_SCROLL_DELAY
-            (GtkFunction) gtk_notebook_timer, (gpointer) notebook);
+         notebook->timer = g_timeout_add (NOTEBOOK_INIT_SCROLL_DELAY, 
+                                          (GSourceFunc) gtk_notebook_timer
+                                          (gpointer) notebook);
          notebook->need_timer = TRUE;
        }
     }
@@ -1392,7 +1727,7 @@ gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
     gtk_notebook_switch_focus_tab (notebook,
                                   gtk_notebook_search_page (notebook,
                                                             NULL,
-                                                            arrow == GTK_ARROW_LEFT ? STEP_NEXT : STEP_PREV,
+                                                            left ? STEP_NEXT : STEP_PREV,
                                                             TRUE));
   gtk_notebook_redraw_arrows (notebook);
 
@@ -1433,6 +1768,40 @@ get_widget_coordinates (GtkWidget *widget,
     return FALSE;
 }
 
+static gboolean
+gtk_notebook_scroll (GtkWidget      *widget,
+                     GdkEventScroll *event)
+{
+  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+
+  GtkWidget* child;
+  GtkWidget* originator;
+
+  if (!notebook->cur_page)
+    return FALSE;
+
+  child = notebook->cur_page->child;
+  originator = gtk_get_event_widget ((GdkEvent *)event);
+
+  /* ignore scroll events from the content of the page */
+  if (!originator || gtk_widget_is_ancestor (originator, child))
+    return FALSE;
+  
+  switch (event->direction)
+    {
+    case GDK_SCROLL_RIGHT:
+    case GDK_SCROLL_DOWN:
+      gtk_notebook_next_page (notebook);
+      break;
+    case GDK_SCROLL_LEFT:
+    case GDK_SCROLL_UP:
+      gtk_notebook_prev_page (notebook);
+      break;
+    }
+
+  return TRUE;
+}
+
 static gboolean
 gtk_notebook_button_press (GtkWidget      *widget,
                           GdkEventButton *event)
@@ -1440,7 +1809,7 @@ gtk_notebook_button_press (GtkWidget      *widget,
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   GtkNotebookPage *page;
   GList *children;
-  GtkArrowType arrow;
+  GtkNotebookArrow arrow;
   gint num;
   gint x, y;
 
@@ -1462,6 +1831,9 @@ gtk_notebook_button_press (GtkWidget      *widget,
       return TRUE;
     }
 
+  if (event->button != 1)
+    return FALSE;
+  
   num = 0;
   children = notebook->children;
   while (children)
@@ -1475,35 +1847,38 @@ gtk_notebook_button_press (GtkWidget      *widget,
          (x <= (page->allocation.x + page->allocation.width)) &&
          (y <= (page->allocation.y + page->allocation.height)))
        {
-         if (page == notebook->cur_page && notebook->focus_tab &&
-             notebook->focus_tab != children &&
-             GTK_WIDGET_HAS_FOCUS (notebook))
-           {
-             GtkNotebookPage *old_page;
-             
-             notebook->child_has_focus = FALSE;
-             old_page = (GtkNotebookPage *)
-               (notebook->focus_tab->data);
-             gtk_notebook_switch_focus_tab (notebook, children);
-             gtk_notebook_focus_changed (notebook, old_page);
-           }
-         else
-           {
-             gtk_notebook_switch_focus_tab (notebook, children);
-             gtk_widget_grab_focus (widget);
-             gtk_notebook_switch_page (notebook, page, num);
-           }
+         gboolean page_changed = page != notebook->cur_page;
+         gboolean was_focus = gtk_widget_is_focus (widget);
+         
+         gtk_notebook_switch_focus_tab (notebook, children);
+         gtk_widget_grab_focus (widget);
+         
+         if (page_changed && !was_focus)
+           gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
+         
          break;
        }
       children = children->next;
       num++;
     }
-  if (!children && !GTK_WIDGET_HAS_FOCUS (widget))
-    gtk_widget_grab_focus (widget);
   
   return TRUE;
 }
 
+static void 
+stop_scrolling (GtkNotebook *notebook)
+{
+  if (notebook->timer)
+    {
+      g_source_remove (notebook->timer);
+      notebook->timer = 0;
+      notebook->need_timer = FALSE;
+    }
+  notebook->click_child = 0;
+  notebook->button = 0;
+  gtk_notebook_redraw_arrows (notebook);
+}
+
 static gint
 gtk_notebook_button_release (GtkWidget      *widget,
                             GdkEventButton *event)
@@ -1520,18 +1895,7 @@ gtk_notebook_button_release (GtkWidget      *widget,
 
   if (event->button == notebook->button)
     {
-      guint click_child;
-
-      if (notebook->timer)
-       {
-         gtk_timeout_remove (notebook->timer);
-         notebook->timer = 0;
-         notebook->need_timer = FALSE;
-       }
-      click_child = notebook->click_child;
-      notebook->click_child = 0;
-      notebook->button = 0;
-      gtk_notebook_redraw_arrows (notebook);
+      stop_scrolling (notebook);
 
       return TRUE;
     }
@@ -1544,7 +1908,7 @@ gtk_notebook_enter_notify (GtkWidget        *widget,
                           GdkEventCrossing *event)
 {
   GtkNotebook *notebook;
-  GtkArrowType arrow;
+  GtkNotebookArrow arrow;
   gint x, y;
 
   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
@@ -1573,7 +1937,7 @@ gtk_notebook_leave_notify (GtkWidget        *widget,
                           GdkEventCrossing *event)
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkArrowType arrow;
+  GtkNotebookArrow arrow;
   gint x, y;
 
   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
@@ -1595,7 +1959,7 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
                            GdkEventMotion *event)
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkArrowType arrow;
+  GtkNotebookArrow arrow;
   gint x, y;
   
   if (notebook->button)
@@ -1615,13 +1979,40 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
   return TRUE;
 }
 
+static void
+gtk_notebook_grab_notify (GtkWidget *widget,
+                         gboolean   was_grabbed)
+{
+  if (!was_grabbed)
+    stop_scrolling (GTK_NOTEBOOK (widget));
+}
+
+static void
+gtk_notebook_state_changed (GtkWidget    *widget,
+                           GtkStateType  previous_state)
+{
+  if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
+    stop_scrolling (GTK_NOTEBOOK (widget));
+}
+
 static gint
 gtk_notebook_focus_in (GtkWidget     *widget,
                       GdkEventFocus *event)
 {
   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
 
-  return (* GTK_WIDGET_CLASS (parent_class)->focus_in_event) (widget, event);
+  gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
+  
+  return FALSE;
+}
+
+static gint
+gtk_notebook_focus_out (GtkWidget     *widget,
+                       GdkEventFocus *event)
+{
+  gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
+
+  return FALSE;
 }
 
 static void
@@ -1649,6 +2040,34 @@ gtk_notebook_draw_focus (GtkWidget *widget)
     }
 }
 
+static void
+gtk_notebook_style_set  (GtkWidget *widget,
+                        GtkStyle  *previous)
+{
+  GtkNotebook *notebook;
+
+  gboolean has_before_previous;
+  gboolean has_before_next;
+  gboolean has_after_previous;
+  gboolean has_after_next;
+
+  notebook = GTK_NOTEBOOK (widget);
+  
+  gtk_widget_style_get (widget,
+                        "has_backward_stepper", &has_before_previous,
+                        "has_secondary_forward_stepper", &has_before_next,
+                        "has_secondary_backward_stepper", &has_after_previous,
+                        "has_forward_stepper", &has_after_next,
+                        NULL);
+  
+  notebook->has_before_previous = has_before_previous;
+  notebook->has_before_next = has_before_next;
+  notebook->has_after_previous = has_after_previous;
+  notebook->has_after_next = has_after_next;
+  
+  (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
+}
+
 /* Private GtkContainer Methods :
  * 
  * gtk_notebook_set_child_arg
@@ -1804,7 +2223,6 @@ gtk_notebook_remove (GtkContainer *container,
   GtkNotebook *notebook;
   GtkNotebookPage *page;
   GList *children;
-  guint page_num;
 
   g_return_if_fail (GTK_IS_NOTEBOOK (container));
   g_return_if_fail (widget != NULL);
@@ -1812,16 +2230,14 @@ gtk_notebook_remove (GtkContainer *container,
   notebook = GTK_NOTEBOOK (container);
 
   children = notebook->children;
-  page_num = 0;
   while (children)
     {
       page = children->data;
       if (page->child == widget)
        {
-         gtk_notebook_real_remove (notebook, children);
+         gtk_notebook_real_remove (notebook, children, FALSE);
          break;
        }
-      page_num++;
       children = children->next;
     }
 }
@@ -1852,12 +2268,10 @@ focus_tabs_move (GtkNotebook     *notebook,
 
   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
                                       search_direction, TRUE);
-  if (!new_page)
-    new_page = (search_direction == STEP_NEXT) ?
-                 notebook->children :
-                 g_list_last (notebook->children);
-
-  gtk_notebook_switch_focus_tab (notebook, new_page);
+  if (new_page)
+    gtk_notebook_switch_focus_tab (notebook, new_page);
+  else
+    gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
   
   return TRUE;
 }
@@ -1866,7 +2280,10 @@ static gboolean
 focus_child_in (GtkNotebook     *notebook,
                GtkDirectionType direction)
 {
-  return gtk_widget_child_focus (notebook->cur_page->child, direction);
+  if (notebook->cur_page)
+    return gtk_widget_child_focus (notebook->cur_page->child, direction);
+  else
+    return FALSE;
 }
 
 /* Focus in the notebook can either be on the pages, or on
@@ -1880,20 +2297,6 @@ gtk_notebook_focus (GtkWidget        *widget,
   GtkNotebook *notebook;
   GtkDirectionType effective_direction;
 
-  /* Remap the directions into the effective direction it would be for a
-   * GTK_POS_TOP notebook
-   */
-#define D(rest) GTK_DIR_##rest
-
-  static const GtkDirectionType translate_direction[4][6] = {
-    /* LEFT */   { D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
-    /* RIGHT */  { D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
-    /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(LEFT), D(RIGHT) },
-    /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(LEFT), D(RIGHT) },
-  };
-
-#undef D  
-
   gboolean widget_is_focus;
   GtkContainer *container;
 
@@ -1902,10 +2305,16 @@ gtk_notebook_focus (GtkWidget        *widget,
   container = GTK_CONTAINER (widget);
   notebook = GTK_NOTEBOOK (container);
 
+  if (notebook->focus_out)
+    {
+      notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
+      return FALSE;
+    }
+
   widget_is_focus = gtk_widget_is_focus (widget);
   old_focus_child = container->focus_child; 
 
-  effective_direction = translate_direction[notebook->tab_pos][direction];
+  effective_direction = get_effective_direction (notebook, direction);
 
   if (old_focus_child)         /* Focus on page child */
     {
@@ -1934,7 +2343,11 @@ gtk_notebook_focus (GtkWidget        *widget,
          return FALSE;
        case GTK_DIR_TAB_FORWARD:
        case GTK_DIR_DOWN:
-         return focus_child_in (notebook, direction);
+         /* 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);
        case GTK_DIR_LEFT:
          return focus_tabs_move (notebook, direction, STEP_PREV);
        case GTK_DIR_RIGHT:
@@ -1968,7 +2381,7 @@ gtk_notebook_focus (GtkWidget        *widget,
   g_assert_not_reached ();
   return FALSE;
 }  
-  
+
 static void
 gtk_notebook_set_focus_child (GtkContainer *container,
                              GtkWidget    *child)
@@ -1991,15 +2404,18 @@ gtk_notebook_set_focus_child (GtkContainer *container,
          if (page_child->parent == GTK_WIDGET (container))
            {
              GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
-             GtkNotebookPage *page = list->data;
-
-             if (page->last_focus_child)
-               g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
-               
-             page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
-             g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
+             if (list != NULL) 
+               {
+                 GtkNotebookPage *page = list->data;
              
-             break;
+                 if (page->last_focus_child)
+                   g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
+                 
+                 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
+                 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
+             
+                 break;
+               }
            }
 
          page_child = page_child->parent;
@@ -2056,13 +2472,11 @@ gtk_notebook_forall (GtkContainer *container,
        {
          if (page->tab_label)
            (* callback) (page->tab_label, callback_data);
-         if (page->menu_label)
-           (* callback) (page->menu_label, callback_data);
        }
     }
 }
 
-static GtkType
+static GType
 gtk_notebook_child_type (GtkContainer     *container)
 {
   return GTK_TYPE_WIDGET;
@@ -2071,7 +2485,6 @@ gtk_notebook_child_type (GtkContainer     *container)
 /* Private GtkNotebook Functions:
  *
  * gtk_notebook_redraw_tabs
- * gtk_notebook_focus_changed
  * gtk_notebook_real_remove
  * gtk_notebook_update_labels
  * gtk_notebook_timer
@@ -2086,6 +2499,7 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook)
   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;
@@ -2098,7 +2512,7 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook)
   redraw_rect.x = border;
   redraw_rect.y = border;
 
-  switch (notebook->tab_pos)
+  switch (tab_pos)
     {
     case GTK_POS_BOTTOM:
       redraw_rect.y = (widget->allocation.height - border -
@@ -2139,50 +2553,25 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook)
 static void
 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
 {
-  if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
-    {
-      GdkRectangle rect;
-
-      gtk_notebook_get_arrow_rect (notebook, &rect);
-      gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, &rect, FALSE);
-    }
-}
-
-static void
-gtk_notebook_focus_changed (GtkNotebook     *notebook,
-                            GtkNotebookPage *old_page)
-{
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
-  if (GTK_WIDGET_DRAWABLE (notebook) && notebook->show_tabs) 
-    {
-      GdkRectangle area;
-      gint focus_width;
-
-      gtk_widget_style_get (GTK_WIDGET (notebook), "focus-line-width", &focus_width, NULL);
-
-      if (notebook->focus_tab)
-       {
-         GtkNotebookPage *page;
-
-         page = notebook->focus_tab->data;
-
-         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;
+  if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
+    {
+      GdkRectangle rect;
+      gint i;
+      GtkNotebookArrow arrow[4];
 
-         gtk_notebook_draw_tab (notebook, page, &area);
-       }
+      arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
+      arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
+      arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
+      arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
 
-      if (old_page)
+      for (i = 0; i < 4; i++) 
        {
-         area.x = old_page->tab_label->allocation.x - focus_width;
-         area.y = old_page->tab_label->allocation.y - focus_width;
-         area.width = old_page->tab_label->allocation.width + 2 * focus_width;
-         area.height = old_page->tab_label->allocation.height + 2 * focus_width;
-
-         gtk_notebook_draw_tab (notebook, old_page, &area);
+         if (arrow[i] == ARROW_NONE)
+           continue;
+         
+         gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
+         gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, 
+                                     &rect, FALSE);
        }
     }
 }
@@ -2193,29 +2582,17 @@ gtk_notebook_timer (GtkNotebook *notebook)
   gboolean retval = FALSE;
 
   GDK_THREADS_ENTER ();
-  
+
   if (notebook->timer)
     {
-      if (notebook->click_child == GTK_ARROW_LEFT)
-       {
-         if (!notebook->focus_tab ||
-             gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                       STEP_PREV, TRUE))
-           gtk_widget_child_focus (GTK_WIDGET (notebook), GTK_DIR_LEFT);
-       }
-      else if (notebook->click_child == GTK_ARROW_RIGHT)
-       {
-         if (!notebook->focus_tab ||
-             gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                       STEP_NEXT, TRUE))
-           gtk_widget_child_focus (GTK_WIDGET (notebook), GTK_DIR_RIGHT);
-       }
+      gtk_notebook_do_arrow (notebook, notebook->click_child);
+
       if (notebook->need_timer) 
        {
          notebook->need_timer = FALSE;
-         notebook->timer = gtk_timeout_add (NOTEBOOK_SCROLL_DELAY,
-                                            (GtkFunction) gtk_notebook_timer, 
-                                            (gpointer) notebook);
+         notebook->timer = g_timeout_add (NOTEBOOK_SCROLL_DELAY,
+                                          (GSourceFunc) gtk_notebook_timer, 
+                                          (gpointer) notebook);
        }
       else
        retval = TRUE;
@@ -2257,17 +2634,19 @@ gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
   if (page->tab_label)
     {
       if (page->mnemonic_activate_signal)
-       gtk_signal_disconnect (page->tab_label,
-                              page->mnemonic_activate_signal);
+       g_signal_handler_disconnect (page->tab_label,
+                                    page->mnemonic_activate_signal);
       page->mnemonic_activate_signal = 0;
 
+      gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
       gtk_widget_unparent (page->tab_label);
     }
 }
 
 static void
 gtk_notebook_real_remove (GtkNotebook *notebook,
-                         GList       *list)
+                         GList       *list,
+                         gboolean     destroying)
 {
   GtkNotebookPage *page;
   GList * next_list;
@@ -2280,19 +2659,16 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
   if (notebook->cur_page == list->data)
     { 
       notebook->cur_page = NULL;
-      if (next_list)
+      if (next_list && !destroying)
        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
     }
 
   if (list == notebook->first_tab)
     notebook->first_tab = next_list;
-  if (list == notebook->focus_tab)
+  if (list == notebook->focus_tab && !destroying)
     gtk_notebook_switch_focus_tab (notebook, next_list);
 
   page = list->data;
-
-  if (page->last_focus_child)
-    g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
   
   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
     need_resize = TRUE;
@@ -2308,15 +2684,18 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
       gtk_widget_queue_resize (notebook->menu);
     }
   if (!page->default_menu)
-    gtk_widget_unref (page->menu_label);
+    g_object_unref (page->menu_label);
   
   notebook->children = g_list_remove_link (notebook->children, list);
   g_list_free (list);
-  g_free (page);
 
-  if (!notebook->children && notebook->show_tabs &&
-      GTK_WIDGET_MAPPED (notebook))
-    gdk_window_hide (notebook->event_window);
+  if (page->last_focus_child)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
+      page->last_focus_child = NULL;
+    }
+  
+  g_free (page);
 
   gtk_notebook_update_labels (notebook);
   if (need_resize)
@@ -2474,7 +2853,9 @@ gtk_notebook_paint (GtkWidget    *widget,
   gint width, height;
   gint x, y;
   gint border_width = GTK_CONTAINER (widget)->border_width;
-  gint gap_x = 0, gap_width = 0;
+  gint gap_x = 0, gap_width = 0, step = STEP_PREV;
+  gboolean is_rtl;
+  gint tab_pos;
    
   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
   g_return_if_fail (area != NULL);
@@ -2483,6 +2864,8 @@ gtk_notebook_paint (GtkWidget    *widget,
     return;
 
   notebook = GTK_NOTEBOOK (widget);
+  is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+  tab_pos = get_effective_tab_pos (notebook);
 
   if ((!notebook->show_tabs && !notebook->show_border) ||
       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
@@ -2507,7 +2890,7 @@ gtk_notebook_paint (GtkWidget    *widget,
     {
       page = notebook->first_tab->data;
 
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
          y += page->allocation.height + widget->style->ythickness;
@@ -2527,7 +2910,7 @@ gtk_notebook_paint (GtkWidget    *widget,
     }
   else
     {
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
          y += notebook->cur_page->allocation.height;
@@ -2541,33 +2924,35 @@ gtk_notebook_paint (GtkWidget    *widget,
          break;
        }
 
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
          gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
          gap_width = notebook->cur_page->allocation.width;
+         step = is_rtl ? STEP_NEXT : STEP_PREV;
          break;
        case GTK_POS_LEFT:
        case GTK_POS_RIGHT:
          gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
          gap_width = notebook->cur_page->allocation.height;
+         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,
-                       notebook->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_PREV, TRUE);
+  children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
   while (children)
     {
       page = children->data;
       children = gtk_notebook_search_page (notebook, children,
-                                          STEP_PREV, TRUE);
+                                          step, TRUE);
       if (!GTK_WIDGET_VISIBLE (page->child))
        continue;
       if (!GTK_WIDGET_MAPPED (page->tab_label))
@@ -2578,8 +2963,14 @@ gtk_notebook_paint (GtkWidget    *widget,
 
   if (showarrow && notebook->scrollable) 
     {
-      gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT);
-      gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT);
+      if (notebook->has_before_previous)
+       gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
+      if (notebook->has_before_next)
+       gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
+      if (notebook->has_after_previous)
+       gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
+      if (notebook->has_after_next)
+       gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
     }
   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
 }
@@ -2593,6 +2984,7 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
   GdkRectangle page_area;
   GtkStateType state_type;
   GtkPositionType gap_side;
+  gint tab_pos = get_effective_tab_pos (notebook);
   
   g_return_if_fail (notebook != NULL);
   g_return_if_fail (page != NULL);
@@ -2613,7 +3005,7 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
 
       widget = GTK_WIDGET (notebook);
       gap_side = 0;
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
          gap_side = GTK_POS_BOTTOM;
@@ -2656,94 +3048,77 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
           GTK_WIDGET_DRAWABLE (page->tab_label))
         {
-          GdkEventExpose expose_event;
+          GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
 
           /* This is a lame hack since all this code needs rewriting anyhow */
           
-          expose_event.window = page->tab_label->window;
-          expose_event.area = child_area;
-          expose_event.region = gdk_region_rectangle (&child_area);
-          expose_event.send_event = TRUE;
-          expose_event.type = GDK_EXPOSE;
-          expose_event.count = 0;
+          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_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, &expose_event);
+         gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
 
-         gdk_region_destroy (expose_event.region);
+         gdk_event_free (expose_event);
         }
     }
 }
 
 static void
-gtk_notebook_draw_arrow (GtkNotebook *notebook,
-                        guint        arrow)
+gtk_notebook_draw_arrow (GtkNotebook      *notebook,
+                        GtkNotebookArrow  nbarrow)
 {
   GtkStateType state_type;
   GtkShadowType shadow_type;
   GtkWidget *widget;
   GdkRectangle arrow_rect;
+  GtkArrowType arrow;
+  gboolean is_rtl, left;
 
-  gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
+  gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  widget = GTK_WIDGET (notebook);
 
-  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))
     {
-      if (notebook->in_child == arrow)
+      if (notebook->in_child == nbarrow)
         {
-          if (notebook->click_child == arrow)
+          if (notebook->click_child == nbarrow)
             state_type = GTK_STATE_ACTIVE;
           else
             state_type = GTK_STATE_PRELIGHT;
         }
       else
-        state_type = GTK_STATE_NORMAL;
+        state_type = GTK_WIDGET_STATE (widget);
 
-      if (notebook->click_child == arrow)
+      if (notebook->click_child == nbarrow)
         shadow_type = GTK_SHADOW_IN;
       else
         shadow_type = GTK_SHADOW_OUT;
 
-      if (arrow == GTK_ARROW_LEFT)
+      if (notebook->focus_tab &&
+         !gtk_notebook_search_page (notebook, notebook->focus_tab,
+                                     left? STEP_PREV : STEP_NEXT, TRUE))
        {
-         if (notebook->focus_tab &&
-             !gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                        STEP_PREV, TRUE))
-           {
-             shadow_type = GTK_SHADOW_ETCHED_IN;
-             state_type = GTK_STATE_INSENSITIVE;
-           }
-
-         if (notebook->tab_pos == GTK_POS_LEFT ||
-             notebook->tab_pos == GTK_POS_RIGHT)
-           arrow = GTK_ARROW_UP;
-
-         gtk_paint_arrow (widget->style, widget->window, state_type, 
-                          shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
-                          arrow, TRUE, 
-                          arrow_rect.x, arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
+         shadow_type = GTK_SHADOW_ETCHED_IN;
+         state_type = GTK_STATE_INSENSITIVE;
        }
+      
+      if (notebook->tab_pos == GTK_POS_LEFT ||
+         notebook->tab_pos == GTK_POS_RIGHT)
+       arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
       else
-       {
-         if (notebook->focus_tab &&
-             !gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                        STEP_NEXT, TRUE))
-           {
-             shadow_type = GTK_SHADOW_ETCHED_IN;
-             state_type = GTK_STATE_INSENSITIVE;
-           }
-
-         if (notebook->tab_pos == GTK_POS_LEFT ||
-             notebook->tab_pos == GTK_POS_RIGHT)
-           arrow = GTK_ARROW_DOWN;
-
-          gtk_paint_arrow (widget->style, widget->window, state_type, 
-                           shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
-                           arrow, TRUE, arrow_rect.x + ARROW_SIZE + ARROW_SPACING,
-                           arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
-       }
+       arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
+      
+      gtk_paint_arrow (widget->style, widget->window, state_type, 
+                      shadow_type, NULL, widget, "notebook",
+                      arrow, TRUE, arrow_rect.x, arrow_rect.y, 
+                      ARROW_SIZE, ARROW_SIZE);
     }
 }
 
@@ -2766,12 +3141,14 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
   gboolean showarrow = FALSE;
   gint tab_space = 0; 
   gint delta; 
-  gint x = 0;
-  gint y = 0;
   gint i;
   gint n = 1;
   gint old_fill = 0;
   gint new_fill = 0;
+  gint tab_pos = get_effective_tab_pos (notebook);
+  gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
+                    (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
+  gint memo_x;
 
   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
     return;
@@ -2779,7 +3156,7 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
   child_allocation.x = widget->allocation.x + container->border_width;
   child_allocation.y = widget->allocation.y + container->border_width;
 
-  switch (notebook->tab_pos)
+  switch (tab_pos)
     {
     case GTK_POS_BOTTOM:
       child_allocation.y = (widget->allocation.y +
@@ -2815,7 +3192,7 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
       else
        focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
 
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
@@ -2833,20 +3210,22 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
              showarrow = TRUE;
              page = focus_tab->data; 
 
-             tab_space = (allocation->width - TAB_OVERLAP -
-                          page->requisition.width -
-                          2 * (container->border_width + ARROW_SPACING +
-                               ARROW_SIZE));
-             x = (allocation->width - 2 * ARROW_SIZE - ARROW_SPACING -
-                  container->border_width);
-
-             page = notebook->children->data;
-             if (notebook->tab_pos == GTK_POS_TOP)
-               y = (container->border_width +
-                    (page->requisition.height - ARROW_SIZE) / 2);
-             else
-               y = (allocation->height - container->border_width - 
-                    ARROW_SIZE - (page->requisition.height - ARROW_SIZE) / 2);
+             tab_space = allocation->width - TAB_OVERLAP -
+               page->requisition.width - 2 * container->border_width;
+             if (notebook->has_after_previous)
+               tab_space -= ARROW_SPACING + ARROW_SIZE;
+             if (notebook->has_after_next)
+               tab_space -= ARROW_SPACING + ARROW_SIZE;
+             if (notebook->has_before_previous)
+               {
+                 tab_space -= ARROW_SPACING + ARROW_SIZE;
+                 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
+               }
+             if (notebook->has_before_next)
+               {
+                 tab_space -= ARROW_SPACING + ARROW_SIZE;
+                 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
+               }
            }
          break;
        case GTK_POS_LEFT:
@@ -2864,22 +3243,16 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
            {
              showarrow = TRUE;
              page = focus_tab->data; 
-             tab_space = (allocation->height -
-                          ARROW_SIZE - ARROW_SPACING - TAB_OVERLAP -
-                          2 * container->border_width -
-                          page->requisition.height);
-             y = allocation->height - container->border_width - ARROW_SIZE;  
-
-             page = notebook->children->data;
-             if (notebook->tab_pos == GTK_POS_LEFT)
-               x = (container->border_width +
-                    (page->requisition.width -
-                     (2 * ARROW_SIZE - ARROW_SPACING)) / 2); 
-             else
-               x = (allocation->width - container->border_width -
-                    (2 * ARROW_SIZE - ARROW_SPACING) -
-                    (page->requisition.width -
-                     (2 * ARROW_SIZE - ARROW_SPACING)) / 2);
+             tab_space = allocation->height
+               - TAB_OVERLAP - 2 * container->border_width
+               - page->requisition.height;
+             if (notebook->has_after_previous || notebook->has_after_next)
+               tab_space -= ARROW_SPACING + ARROW_SIZE;
+             if (notebook->has_before_previous || notebook->has_before_next)
+               {
+                 tab_space -= ARROW_SPACING + ARROW_SIZE;
+                 child_allocation.y += ARROW_SPACING + ARROW_SIZE;
+               }
            }
          break;
        }
@@ -3010,7 +3383,7 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
 
       n = 0;
       children = notebook->children;
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
@@ -3055,7 +3428,22 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
     }
   
   children = notebook->first_tab;
-  i = 1;
+  i = 1; 
+
+  memo_x = child_allocation.x;
+  if (notebook->children && is_rtl)
+     {
+      child_allocation.x = (allocation->x + allocation->width -
+                               container->border_width); 
+      if (showarrow) 
+       {
+         if (notebook->has_after_previous)
+           child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
+         if (notebook->has_after_next)
+           child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
+       }
+     }
+
   while (children)
     {
       if (children == last_child)
@@ -3065,7 +3453,7 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
        }
 
       page = children->data;
-      if (!showarrow && page->pack != GTK_PACK_START)
+      if (!showarrow && page->pack != GTK_PACK_START) 
        break;
       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
       
@@ -3077,12 +3465,14 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
          old_fill = new_fill;
        }
       
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
          child_allocation.width = (page->requisition.width +
                                    TAB_OVERLAP + delta);
+          if (is_rtl)
+             child_allocation.x -= child_allocation.width;
          break;
        case GTK_POS_LEFT:
        case GTK_POS_RIGHT:
@@ -3092,12 +3482,15 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
        }
 
       gtk_notebook_page_allocate (notebook, page, &child_allocation);
-         
-      switch (notebook->tab_pos)
+
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
-         child_allocation.x += child_allocation.width - TAB_OVERLAP;
+          if (!is_rtl)
+            child_allocation.x += child_allocation.width - TAB_OVERLAP;
+          else
+             child_allocation.x += TAB_OVERLAP;
          break;
        case GTK_POS_LEFT:
        case GTK_POS_RIGHT:
@@ -3112,12 +3505,16 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
   if (children)
     {
       children = notebook->children;
-      switch (notebook->tab_pos)
+
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
-         child_allocation.x = (allocation->x + allocation->width -
-                               container->border_width);
+          if (!is_rtl)
+            child_allocation.x = (allocation->x + allocation->width -
+                                 container->border_width);
+          else
+             child_allocation.x = memo_x; 
          break;
        case GTK_POS_LEFT:
        case GTK_POS_RIGHT:
@@ -3131,8 +3528,8 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
          page = children->data;
          children = children->next;
 
-         if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
-           continue;
+          if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
+             continue;
 
          delta = 0;
          if (n && (page->expand || notebook->homogeneous))
@@ -3142,13 +3539,14 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
              old_fill = new_fill;
            }
 
-         switch (notebook->tab_pos)
+         switch (tab_pos)
            {
            case GTK_POS_TOP:
            case GTK_POS_BOTTOM:
              child_allocation.width = (page->requisition.width +
                                        TAB_OVERLAP + delta);
-             child_allocation.x -= child_allocation.width;
+              if (!is_rtl)
+                child_allocation.x -= child_allocation.width;
              break;
            case GTK_POS_LEFT:
            case GTK_POS_RIGHT:
@@ -3160,11 +3558,14 @@ gtk_notebook_pages_allocate (GtkNotebook   *notebook)
 
          gtk_notebook_page_allocate (notebook, page, &child_allocation);
 
-         switch (notebook->tab_pos)
+         switch (tab_pos)
            {
            case GTK_POS_TOP:
            case GTK_POS_BOTTOM:
-             child_allocation.x += TAB_OVERLAP;
+              if (!is_rtl)
+                child_allocation.x += TAB_OVERLAP;
+              else
+                 child_allocation.x += child_allocation.width - TAB_OVERLAP;
              break;
            case GTK_POS_LEFT:
            case GTK_POS_RIGHT:
@@ -3193,63 +3594,19 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
   gint ythickness;
   gint padding;
   gint focus_width;
+  gint tab_pos = get_effective_tab_pos (notebook);
 
   gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
   
   xthickness = widget->style->xthickness;
   ythickness = widget->style->ythickness;
 
-  /* If the size of the notebook tabs change, we need to queue
-   * a redraw on the tab area
-   */
-  if ((allocation->width != page->allocation.width) ||
-      (allocation->height != page->allocation.height))
-    {
-      gint x, y, width, height, border_width;
-
-      border_width = GTK_CONTAINER (notebook)->border_width;
-
-      switch (notebook->tab_pos)
-       {
-       case GTK_POS_TOP:
-         width = widget->allocation.width;
-         height = MAX (page->allocation.height, allocation->height) + ythickness;
-         x = 0;                              
-         y = border_width;
-         break;
-
-       case GTK_POS_BOTTOM:
-         width = widget->allocation.width + xthickness;
-         height = MAX (page->allocation.height, allocation->height) + ythickness;
-         x = 0;                              
-         y = widget->allocation.height - height - border_width;
-         break;
-
-       case GTK_POS_LEFT:
-         width = MAX (page->allocation.width, allocation->width) + xthickness;
-         height = widget->allocation.height;
-         x = border_width;
-         y = 0;
-         break;
-
-       case GTK_POS_RIGHT:
-       default:                /* quiet gcc */
-         width = MAX (page->allocation.width, allocation->width) + xthickness;
-         height = widget->allocation.height;
-         x = widget->allocation.width - width - border_width;
-         y = 0;
-         break;
-       }
-
-      gtk_widget_queue_clear_area (widget, x, y, width, height);
-    }
-
   page->allocation = *allocation;
   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
 
   if (notebook->cur_page != page)
     {
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
          page->allocation.y += ythickness;
@@ -3266,7 +3623,7 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
        }
     }
 
-  switch (notebook->tab_pos)
+  switch (tab_pos)
     {
     case GTK_POS_TOP:
     case GTK_POS_BOTTOM:
@@ -3288,7 +3645,7 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
        }
       child_allocation.y = (notebook->tab_vborder + focus_width +
                            page->allocation.y);
-      if (notebook->tab_pos == GTK_POS_TOP)
+      if (tab_pos == GTK_POS_TOP)
        child_allocation.y += ythickness;
       child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
                                         2 * (notebook->tab_vborder + focus_width)));
@@ -3310,7 +3667,7 @@ gtk_notebook_page_allocate (GtkNotebook     *notebook,
          child_allocation.height = tab_requisition.height;
        }
       child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
-      if (notebook->tab_pos == GTK_POS_LEFT)
+      if (tab_pos == GTK_POS_LEFT)
        child_allocation.x += xthickness;
       child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
                                        2 * (notebook->tab_hborder + focus_width)));
@@ -3332,6 +3689,7 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
   GList *children;
   GList *last_list = NULL;
   gboolean pack;
+  gint tab_pos = get_effective_tab_pos (notebook);
 
   if (!start)
     return;
@@ -3343,7 +3701,7 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
 
   while (1)
     {
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
        case GTK_POS_BOTTOM:
@@ -3412,6 +3770,25 @@ gtk_notebook_calc_tabs (GtkNotebook  *notebook,
     }
 }
 
+static void
+gtk_notebook_update_tab_states (GtkNotebook *notebook)
+{
+  GList *list;
+
+  for (list = notebook->children; list != NULL; list = list->next)
+    {
+      GtkNotebookPage *page = list->data;
+      
+      if (page->tab_label)
+       {
+         if (page == notebook->cur_page)
+           gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
+         else
+           gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
+       }
+    }
+}
+
 /* Private GtkNotebook Page Switch Methods:
  *
  * gtk_notebook_real_switch_page
@@ -3453,6 +3830,7 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
          gtk_widget_grab_focus (GTK_WIDGET (notebook));
     }
   
+  gtk_notebook_update_tab_states (notebook);
   gtk_widget_queue_resize (GTK_WIDGET (notebook));
   g_object_notify (G_OBJECT (notebook), "page");
 }
@@ -3478,10 +3856,11 @@ gtk_notebook_switch_page (GtkNotebook     *notebook,
   if (page_num < 0)
     page_num = g_list_index (notebook->children, page);
 
-  gtk_signal_emit (GTK_OBJECT (notebook), 
-                  notebook_signals[SWITCH_PAGE], 
-                  page,
-                  page_num);
+  g_signal_emit (notebook,
+                notebook_signals[SWITCH_PAGE],
+                0,
+                page,
+                page_num);
 }
 
 static gint
@@ -3490,6 +3869,7 @@ gtk_notebook_page_select (GtkNotebook *notebook,
 {
   GtkNotebookPage *page;
   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);
 
@@ -3501,7 +3881,7 @@ gtk_notebook_page_select (GtkNotebook *notebook,
 
   if (move_focus)
     {
-      switch (notebook->tab_pos)
+      switch (tab_pos)
        {
        case GTK_POS_TOP:
          dir = GTK_DIR_DOWN;
@@ -3550,9 +3930,12 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
 
   page = notebook->focus_tab->data;
   if (GTK_WIDGET_MAPPED (page->tab_label))
-    gtk_notebook_focus_changed (notebook, old_page);
+    gtk_notebook_redraw_tabs (notebook);
   else
     gtk_notebook_pages_allocate (notebook);
+  
+  gtk_notebook_switch_page (notebook, page,
+                           g_list_index (notebook->children, page));
 }
 
 static void
@@ -3580,10 +3963,11 @@ gtk_notebook_menu_switch_page (GtkWidget       *widget,
       page_num++;
     }
 
-  gtk_signal_emit (GTK_OBJECT (notebook), 
-                  notebook_signals[SWITCH_PAGE], 
-                  page,
-                  page_num);
+  g_signal_emit (notebook,
+                notebook_signals[SWITCH_PAGE],
+                0,
+                page,
+                page_num);
 }
 
 /* Private GtkNotebook Menu Functions:
@@ -3614,8 +3998,8 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook,
   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
                         gtk_notebook_real_page_position (notebook, list));
-  gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
-                     GTK_SIGNAL_FUNC (gtk_notebook_menu_switch_page), page);
+  g_signal_connect (menu_item, "activate",
+                   G_CALLBACK (gtk_notebook_menu_switch_page), page);
   if (GTK_WIDGET_VISIBLE (page->child))
     gtk_widget_show (menu_item);
 }
@@ -3642,6 +4026,80 @@ gtk_notebook_menu_detacher (GtkWidget *widget,
   notebook->menu = NULL;
 }
 
+/* Private GtkNotebook Setter Functions:
+ *
+ * gtk_notebook_set_homogeneous_tabs_internal
+ * gtk_notebook_set_tab_border_internal
+ * gtk_notebook_set_tab_hborder_internal
+ * gtk_notebook_set_tab_vborder_internal
+ */
+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;
+
+  notebook->homogeneous = homogeneous;
+  gtk_widget_queue_resize (GTK_WIDGET (notebook));
+
+  g_object_notify (G_OBJECT (notebook), "homogeneous");
+}
+
+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;
+
+  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
+    gtk_widget_queue_resize (GTK_WIDGET (notebook));
+
+  g_object_freeze_notify (G_OBJECT (notebook));
+  g_object_notify (G_OBJECT (notebook), "tab_hborder");
+  g_object_notify (G_OBJECT (notebook), "tab_vborder");
+  g_object_thaw_notify (G_OBJECT (notebook));
+}
+
+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;
+
+  notebook->tab_hborder = tab_hborder;
+
+  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
+    gtk_widget_queue_resize (GTK_WIDGET (notebook));
+
+  g_object_notify (G_OBJECT (notebook), "tab_hborder");
+}
+
+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;
+
+  notebook->tab_vborder = tab_vborder;
+
+  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
+    gtk_widget_queue_resize (GTK_WIDGET (notebook));
+
+  g_object_notify (G_OBJECT (notebook), "tab_vborder");
+}
+
 /* Public GtkNotebook Page Insert/Remove Methods :
  *
  * gtk_notebook_append_page
@@ -3660,17 +4118,20 @@ gtk_notebook_menu_detacher (GtkWidget *widget,
  *             or %NULL to use the default label, 'page N'.
  * 
  * Appends a page to @notebook.
+ *
+ * Return value: the index (starting from 0) of the appended
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_append_page (GtkNotebook *notebook,
                          GtkWidget   *child,
                          GtkWidget   *tab_label)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
+  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);
   
-  gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
+  return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
 }
 
 /**
@@ -3688,19 +4149,22 @@ gtk_notebook_append_page (GtkNotebook *notebook,
  * 
  * Appends a page to @notebook, specifying the widget to use as the
  * label in the popup menu.
+ *
+ * Return value: the index (starting from 0) of the appended
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_append_page_menu (GtkNotebook *notebook,
                               GtkWidget   *child,
                               GtkWidget   *tab_label,
                               GtkWidget   *menu_label)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
-  g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
+  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_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
+  return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
 }
 
 /**
@@ -3711,17 +4175,20 @@ gtk_notebook_append_page_menu (GtkNotebook *notebook,
  *             or %NULL to use the default label, 'page N'.
  *
  * Prepends a page to @notebook.
+ *
+ * Return value: the index (starting from 0) of the prepended
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_prepend_page (GtkNotebook *notebook,
                           GtkWidget   *child,
                           GtkWidget   *tab_label)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
+  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);
   
-  gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
+  return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
 }
 
 /**
@@ -3739,19 +4206,22 @@ gtk_notebook_prepend_page (GtkNotebook *notebook,
  * 
  * Prepends a page to @notebook, specifying the widget to use as the
  * label in the popup menu.
+ *
+ * Return value: the index (starting from 0) of the prepended
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
                                GtkWidget   *child,
                                GtkWidget   *tab_label,
                                GtkWidget   *menu_label)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
-  g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
+  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_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
+  return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
 }
 
 /**
@@ -3763,19 +4233,22 @@ gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
  * @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
+ * Insert a page into @notebook at the given position.
+ *
+ * Return value: the index (starting from 0) of the inserted
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_insert_page (GtkNotebook *notebook,
                          GtkWidget   *child,
                          GtkWidget   *tab_label,
                          gint         position)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
+  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);
   
-  gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
+  return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
 }
 
 
@@ -3825,8 +4298,11 @@ gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
  * 
  * Insert a page into @notebook at the given position, specifying
  * the widget to use as the label in the popup menu.
+ *
+ * Return value: the index (starting from 0) of the inserted
+ * page in the notebook, or -1 if function fails
  **/
-void
+gint
 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
                               GtkWidget   *child,
                               GtkWidget   *tab_label,
@@ -3836,10 +4312,10 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook,
   GtkNotebookPage *page;
   gint nchildren;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
-  g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
+  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);
   
@@ -3872,13 +4348,13 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook,
   page->menu_label = menu_label;
   page->expand = FALSE;
   page->fill = TRUE;
-  page->pack = GTK_PACK_START;
+  page->pack = GTK_PACK_START; 
 
   if (!menu_label)
     page->default_menu = TRUE;
   else  
     {
-      gtk_widget_ref (page->menu_label);
+      g_object_ref (page->menu_label);
       gtk_object_sink (GTK_OBJECT (page->menu_label));
     }
 
@@ -3914,15 +4390,14 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook,
       gtk_notebook_switch_focus_tab (notebook, NULL);
     }
 
+  gtk_notebook_update_tab_states (notebook);
+
   if (tab_label)
     page->mnemonic_activate_signal =
-      gtk_signal_connect (GTK_OBJECT (tab_label),
-                         "mnemonic_activate",
-                         (GtkSignalFunc) gtk_notebook_mnemonic_activate_switch_page,
-                         notebook);
-
-  if (notebook->show_tabs && GTK_WIDGET_MAPPED (notebook))
-    gdk_window_show_unraised (notebook->event_window);
+      g_signal_connect (tab_label,
+                       "mnemonic_activate",
+                       G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
+                       notebook);
 
   gtk_widget_child_notify (child, "tab_expand");
   gtk_widget_child_notify (child, "tab_fill");
@@ -3931,6 +4406,8 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook,
   gtk_widget_child_notify (child, "menu_label");
   gtk_widget_child_notify (child, "position");
   gtk_widget_thaw_child_notify (child);
+
+  return position;
 }
 
 /**
@@ -3955,13 +4432,13 @@ gtk_notebook_remove_page (GtkNotebook *notebook,
     {
       list = g_list_nth (notebook->children, page_num);
       if (list)
-       gtk_notebook_real_remove (notebook, list);
+       gtk_notebook_real_remove (notebook, list, FALSE);
     }
   else
     {
       list = g_list_last (notebook->children);
       if (list)
-       gtk_notebook_real_remove (notebook, list);
+       gtk_notebook_real_remove (notebook, list, FALSE);
     }
 }
 
@@ -3996,7 +4473,8 @@ 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
+ * @page_num: the index of a page in the noteobok, or -1
+ *            to get the last page.
  * 
  * Returns the child widget contained in page number @page_num.
  * 
@@ -4008,17 +4486,42 @@ gtk_notebook_get_nth_page (GtkNotebook *notebook,
                           gint         page_num)
 {
   GtkNotebookPage *page;
+  GList *list;
 
   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
 
-  page = g_list_nth_data (notebook->children, page_num);
+  if (page_num >= 0)
+    list = g_list_nth (notebook->children, page_num);
+  else
+    list = g_list_last (notebook->children);
 
-  if (page)
-    return page->child;
+  if (list)
+    {
+      page = list->data;
+      return page->child;
+    }
 
   return NULL;
 }
 
+/**
+ * gtk_notebook_get_n_pages:
+ * @notebook: a #GtkNotebook
+ * 
+ * Gets the number of pages in a notebook.
+ * 
+ * Return value: the number of pages in the notebook.
+ *
+ * Since: 2.2
+ **/
+gint
+gtk_notebook_get_n_pages (GtkNotebook *notebook)
+{
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
+
+  return g_list_length (notebook->children);
+}
+
 /**
  * gtk_notebook_page_num:
  * @notebook: a #GtkNotebook
@@ -4059,8 +4562,9 @@ gtk_notebook_page_num (GtkNotebook      *notebook,
  * gtk_notebook_set_current_page:
  * @notebook: a #GtkNotebook
  * @page_num: index of the page to switch to, starting from 0.
- *            If negative, or greater than the number of pages
- *            in the notebook the last page will be used.
+ *            If negative, the last page will be used. If greater
+ *            than the number of pages in the notebook, nothing
+ *            will be done.
  *                
  * Switches to the page number @page_num.
  **/
@@ -4150,7 +4654,7 @@ gtk_notebook_prev_page (GtkNotebook *notebook)
  * @show_border: %TRUE if a bevel should be drawn around the notebook.
  * 
  * Sets whether a bevel will be drawn around the notebook pages.
- * this is only has an effect when the tabs are not shown.
+ * This only has a visual effect when the tabs are not shown.
  * See gtk_notebook_set_show_tabs().
  **/
 void
@@ -4309,13 +4813,7 @@ gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
 {
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  if (homogeneous == notebook->homogeneous)
-    return;
-
-  notebook->homogeneous = homogeneous;
-  gtk_widget_queue_resize (GTK_WIDGET (notebook));
-
-  g_object_notify (G_OBJECT (notebook), "homogeneous");
+  gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
 }
 
 /**
@@ -4334,17 +4832,7 @@ gtk_notebook_set_tab_border (GtkNotebook *notebook,
 {
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  notebook->tab_hborder = border_width;
-  notebook->tab_vborder = border_width;
-
-  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
-    gtk_widget_queue_resize (GTK_WIDGET (notebook));
-
-  g_object_freeze_notify (G_OBJECT (notebook));
-  g_object_notify (G_OBJECT (notebook), "tab_hborder");
-  g_object_notify (G_OBJECT (notebook), "tab_vborder");
-  g_object_thaw_notify (G_OBJECT (notebook));
-
+  gtk_notebook_set_tab_border_internal (notebook, border_width);
 }
 
 /**
@@ -4360,15 +4848,7 @@ gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
 {
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  if (notebook->tab_hborder == tab_hborder)
-    return;
-
-  notebook->tab_hborder = tab_hborder;
-
-  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
-    gtk_widget_queue_resize (GTK_WIDGET (notebook));
-
-  g_object_notify (G_OBJECT (notebook), "tab_hborder");
+  gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
 }
 
 /**
@@ -4384,15 +4864,7 @@ gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
 {
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  if (notebook->tab_vborder == tab_vborder)
-    return;
-
-  notebook->tab_vborder = tab_vborder;
-
-  if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
-    gtk_widget_queue_resize (GTK_WIDGET (notebook));
-
-  g_object_notify (G_OBJECT (notebook), "tab_vborder");
+  gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
 }
 
 /**
@@ -4600,16 +5072,18 @@ gtk_notebook_set_tab_label (GtkNotebook *notebook,
 
   if (page->tab_label)
     page->mnemonic_activate_signal =
-      gtk_signal_connect (GTK_OBJECT (page->tab_label),
-                         "mnemonic_activate",
-                         (GtkSignalFunc) gtk_notebook_mnemonic_activate_switch_page,
-                         notebook);
+      g_signal_connect (page->tab_label,
+                       "mnemonic_activate",
+                       G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
+                       notebook);
 
   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
     {
       gtk_widget_show (page->tab_label);
       gtk_widget_queue_resize (GTK_WIDGET (notebook));
     }
+
+  gtk_notebook_update_tab_states (notebook);
   gtk_widget_child_notify (child, "tab_label");
 }
 
@@ -4728,13 +5202,13 @@ gtk_notebook_set_menu_label (GtkNotebook *notebook,
                              page->menu_label->parent);
 
       if (!page->default_menu)
-       gtk_widget_unref (page->menu_label);
+       g_object_unref (page->menu_label);
     }
 
   if (menu_label)
     {
       page->menu_label = menu_label;
-      gtk_widget_ref (page->menu_label);
+      g_object_ref (page->menu_label);
       gtk_object_sink (GTK_OBJECT(page->menu_label));
       page->default_menu = FALSE;
     }
@@ -4815,7 +5289,8 @@ gtk_notebook_child_reordered (GtkNotebook     *notebook,
       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
     }
-  
+
+  gtk_notebook_update_tab_states (notebook);
   gtk_notebook_update_labels (notebook);
 }
 
@@ -4910,10 +5385,12 @@ gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
  * gtk_notebook_reorder_child:
  * @notebook: a #GtkNotebook
  * @child: the child to move
- * @position: the new position
+ * @position: the new position, or -1 to move to the end
  * 
  * Reorders the page containing @child, so that it appears in position
- * @position. Out of bounds @position will be clamped.
+ * @position. If @position is greater than or equal to the number of
+ * children in the list or negative, @child will be moved to the end
+ * of the list.
  **/
 void
 gtk_notebook_reorder_child (GtkNotebook *notebook,
@@ -4923,6 +5400,7 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
   GList *list, *new_list;
   GtkNotebookPage *page;
   gint old_pos;
+  gint max_pos;
 
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
   g_return_if_fail (GTK_IS_WIDGET (child));
@@ -4931,6 +5409,10 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
   if (!list)
     return;
 
+  max_pos = g_list_length (notebook->children) - 1;
+  if (position < 0 || position > max_pos)
+    position = max_pos;
+
   old_pos = g_list_position (notebook->children, list);
 
   if (old_pos == position)
@@ -4939,8 +5421,6 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
   page = list->data;
   notebook->children = g_list_delete_link (notebook->children, list);
 
-  position = CLAMP (position, 0, g_list_length (notebook->children));
-
   notebook->children = g_list_insert (notebook->children, page, position);
   new_list = g_list_nth (notebook->children, position);
 
@@ -4952,7 +5432,7 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
 
   gtk_widget_freeze_child_notify (child);
 
-  /* Move around the menu items if necesary */
+  /* Move around the menu items if necessary */
   gtk_notebook_child_reordered (notebook, page);
   gtk_widget_child_notify (child, "tab_pack");
   gtk_widget_child_notify (child, "position");
@@ -4962,3 +5442,6 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
 
   gtk_widget_thaw_child_notify (child);
 }
+
+#define __GTK_NOTEBOOK_C__
+#include "gtkaliasdef.c"