Index: gtk/gtksettings.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtksettings.c,v
retrieving revision 1.95
diff -u -p -r1.95 gtksettings.c
--- gtk/gtksettings.c	2 May 2006 23:56:42 -0000	1.95
+++ gtk/gtksettings.c	11 May 2006 14:15:53 -0000
@@ -92,6 +92,7 @@ enum {
   PROP_COLOR_SCHEME,
   PROP_ENABLE_ANIMATIONS,
   PROP_TOUCHSCREEN_MODE,
+  PROP_CURSOR_ONLY_FOCUS,
   PROP_COLOR_HASH
 };
 
@@ -492,6 +493,25 @@ gtk_settings_class_init (GtkSettingsClas
                                              NULL);
 
   g_assert (result == PROP_TOUCHSCREEN_MODE);
+
+  /**
+   * GtkSettings:gtk-cursor-only-focus:
+   *
+   * When TRUE, keyboard navigation should be able to reach all widgets
+   * by using the cursor keys only. Tab, Shift etc. keys can't be expected
+   * to be present on the used input device.
+   *
+   * Since: 2.10
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-cursor-only-focus",
+                                                                   P_("Cursor Only Focus"),
+                                                                   P_("When TRUE, there are only cursor keys available to navigate widgets"),
+                                                                   FALSE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+
+  g_assert (result == PROP_CURSOR_ONLY_FOCUS);
 
   /**
    * GtkSettings:color-hash:
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.436
diff -u -p -r1.436 gtkwidget.c
--- gtk/gtkwidget.c	10 May 2006 14:02:20 -0000	1.436
+++ gtk/gtkwidget.c	11 May 2006 14:15:54 -0000
@@ -122,6 +122,7 @@ enum {
   CAN_ACTIVATE_ACCEL,
   GRAB_BROKEN,
   COMPOSITED_CHANGED,
+  KEYNAV_FAILED,
   LAST_SIGNAL
 };
 
@@ -202,6 +203,8 @@ static gboolean		gtk_widget_real_focus_o
 								 GdkEventFocus    *event);
 static gboolean		gtk_widget_real_focus			(GtkWidget        *widget,
 								 GtkDirectionType  direction);
+static gboolean		gtk_widget_real_keynav_failed		(GtkWidget        *widget,
+								 GtkDirectionType  direction);
 static PangoContext*	gtk_widget_peek_pango_context		(GtkWidget	  *widget);
 static void     	gtk_widget_update_pango_context		(GtkWidget	  *widget);
 static void		gtk_widget_propagate_state		(GtkWidget	  *widget,
@@ -363,6 +366,7 @@ gtk_widget_class_init (GtkWidgetClass *k
   klass->screen_changed = NULL;
   klass->can_activate_accel = gtk_widget_real_can_activate_accel;
   klass->grab_broken_event = NULL;
+  klass->keynav_failed = gtk_widget_real_keynav_failed;
 
   klass->show_help = gtk_widget_real_show_help;
   
@@ -756,6 +760,15 @@ gtk_widget_class_init (GtkWidgetClass *k
 		  NULL, NULL,
 		  _gtk_marshal_VOID__VOID,
 		  G_TYPE_NONE, 0);
+  widget_signals[KEYNAV_FAILED] =
+    g_signal_new (I_("keynav-failed"),
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GtkWidgetClass, keynav_failed),
+		  _gtk_boolean_handled_accumulator, NULL,
+		  _gtk_marshal_BOOLEAN__ENUM,
+		  G_TYPE_BOOLEAN, 1,
+		  GTK_TYPE_DIRECTION_TYPE);
 
 /**
  * GtkWidget::delete-event:
@@ -4195,6 +4208,34 @@ gtk_widget_real_focus (GtkWidget        
     return FALSE;
 }
 
+static gboolean
+gtk_widget_real_keynav_failed (GtkWidget        *widget,
+                               GtkDirectionType  direction)
+{
+  GtkSettings *settings = gtk_widget_get_settings (widget);
+  gboolean     cursor_only_focus;
+
+  g_object_get (settings, "gtk-cursor-only-focus", &cursor_only_focus, NULL);
+
+  switch (direction)
+    {
+    case GTK_DIR_TAB_FORWARD:
+    case GTK_DIR_TAB_BACKWARD:
+      return FALSE;
+
+    case GTK_DIR_UP:
+    case GTK_DIR_DOWN:
+    case GTK_DIR_LEFT:
+    case GTK_DIR_RIGHT:
+      if (cursor_only_focus)
+        return FALSE;
+    }
+
+  gdk_beep ();
+
+  return TRUE;
+}
+
 /**
  * gtk_widget_is_focus:
  * @widget: a #GtkWidget
@@ -5763,6 +5804,20 @@ gtk_widget_child_focus (GtkWidget       
   g_signal_emit (widget,
 		 widget_signals[FOCUS],
 		 0,
+		 direction, &return_val);
+
+  return return_val;
+}
+
+gboolean
+gtk_widget_keynav_failed (GtkWidget        *widget,
+                          GtkDirectionType  direction)
+{
+  gboolean return_val;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  g_signal_emit (widget, widget_signals[KEYNAV_FAILED], 0,
 		 direction, &return_val);
 
   return return_val;
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.159
diff -u -p -r1.159 gtkwidget.h
--- gtk/gtkwidget.h	25 Apr 2006 14:27:31 -0000	1.159
+++ gtk/gtkwidget.h	11 May 2006 14:15:54 -0000
@@ -408,9 +408,11 @@ struct _GtkWidgetClass
                                  GdkEventGrabBroken  *event);
 
   void         (* composited_changed) (GtkWidget *widget);
-	
+
+  gboolean     (* keynav_failed)      (GtkWidget        *widget,
+                                       GtkDirectionType  direction);
+
   /* Padding for future expansion */
-  void (*_gtk_reserved4) (void);
   void (*_gtk_reserved5) (void);
   void (*_gtk_reserved6) (void);
   void (*_gtk_reserved7) (void);
@@ -562,6 +564,8 @@ GtkWidget *gtk_widget_get_parent        
 GdkWindow *gtk_widget_get_parent_window	  (GtkWidget	       *widget);
 
 gboolean   gtk_widget_child_focus         (GtkWidget           *widget,
+                                           GtkDirectionType     direction);
+gboolean   gtk_widget_keynav_failed       (GtkWidget           *widget,
                                            GtkDirectionType     direction);
 
 void       gtk_widget_set_size_request    (GtkWidget           *widget,
Index: gtk/gtkradiobutton.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkradiobutton.c,v
retrieving revision 1.61
diff -u -p -r1.61 gtkradiobutton.c
--- gtk/gtkradiobutton.c	2 May 2006 23:56:42 -0000	1.61
+++ gtk/gtkradiobutton.c	11 May 2006 14:15:54 -0000
@@ -491,6 +491,12 @@ gtk_radio_button_focus (GtkWidget       
 
       if (!new_focus)
 	{
+          if (!gtk_widget_keynav_failed (widget, direction))
+            {
+              g_slist_free (focus_list);
+              return FALSE;
+            }
+
 	  tmp_list = focus_list;
 
 	  while (tmp_list)
@@ -511,8 +517,17 @@ gtk_radio_button_focus (GtkWidget       
 
       if (new_focus)
 	{
+          GtkSettings *settings = gtk_widget_get_settings (widget);
+          gboolean     cursor_only_focus;
+
+          g_object_get (settings,
+                        "gtk-cursor-only-focus", &cursor_only_focus,
+                        NULL);
+
 	  gtk_widget_grab_focus (new_focus);
-	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
+
+          if (!cursor_only_focus)
+            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
 	}
 
       return TRUE;
Index: gtk/gtkrange.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrange.c,v
retrieving revision 1.124
diff -u -p -r1.124 gtkrange.c
--- gtk/gtkrange.c	8 May 2006 14:50:33 -0000	1.124
+++ gtk/gtkrange.c	11 May 2006 14:15:55 -0000
@@ -2008,6 +2008,37 @@ static void
 gtk_range_move_slider (GtkRange     *range,
                        GtkScrollType scroll)
 {
+  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (range));
+  gboolean     cursor_only_focus;
+
+  g_object_get (settings, "gtk-cursor-only-focus", &cursor_only_focus, NULL);
+
+  if (cursor_only_focus && GTK_WIDGET (range)->parent)
+    {
+      if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          if (scroll == GTK_SCROLL_STEP_UP ||
+              scroll == GTK_SCROLL_STEP_DOWN)
+            {
+              gtk_widget_child_focus (GTK_WIDGET (range)->parent,
+                                      scroll == GTK_SCROLL_STEP_UP ?
+                                      GTK_DIR_UP : GTK_DIR_DOWN);
+              return;
+            }
+        }
+      else
+        {
+          if (scroll == GTK_SCROLL_STEP_LEFT ||
+              scroll == GTK_SCROLL_STEP_RIGHT)
+            {
+              gtk_widget_child_focus (GTK_WIDGET (range)->parent,
+                                      scroll == GTK_SCROLL_STEP_LEFT ?
+                                      GTK_DIR_LEFT : GTK_DIR_RIGHT);
+              return;
+            }
+        }
+    }
+
   gtk_range_scroll (range, scroll);
 
   /* Policy DELAYED makes sense with key events,
