Commit 7f374a74 authored by Michael Natterer's avatar Michael Natterer Committed by Michael Natterer

Add new infrastructure for notifications of failed keyboard navigation and

2006-11-16  Michael Natterer  <mitch@imendio.com>

	Add new infrastructure for notifications of failed keyboard
	navigation and navigation with restricted set of keys.

	The patch handles configurable beeping, navigating the GUI with
	cursor keys only (as in phone environments), and configurable
	wrap-around. Fixes bugs #322640, #70986, #318827, #334726, #334742
	and #309291.

	* gtk/gtksettings.c: added properties gtk-keynav-cursor-only,
	gtk-keynav-wrap-around and gtk-error-bell.

	* gtk/gtkwidget.[ch]: added new signal "keynav-failed" and public
	API to emit it. Added New function gtk_widget_error_bell() which
	looks at the gtk-error-bell setting and calls gdk_window_beep()
	accordingly.

	* gtk/gtk.symbols: add the new widget symbols.

	* gtk/gtkcellrendereraccel.c
	* gtk/gtkimcontextsimple.c
	* gtk/gtkmenu.c
	* gtk/gtknotebook.c: use gtk_widget_error_bell() or look at the
	gtk-error-bell setting instead of calling gdk_display_beep()
	unconditionally.

	* gtk/gtkcombobox.c
	* gtk/gtkentry.c
	* gtk/gtkiconview.c
	* gtk/gtklabel.c
	* gtk/gtkmenushell.c
	* gtk/gtkspinbutton.c
	* gtk/gtktextview.c
	* gtk/gtktreeview.c: call gtk_widget_error_bell() on failed keynav.

	* gtk/gtkentry.c
	* gtk/gtklabel.c
	* gtk/gtkrange.c
	* gtk/gtktextview.c: consult gtk_widget_keynav_failed() on failed
	cursor navigation and leave the widget if it returns FALSE.

	* gtk/gtkmenushell.c
	* gtk/gtknotebook.c: only wrap around if gtk-keynav-wrap-around
	is TRUE.

	* gtk/gtkradiobutton.c: ask gtk_widget_keynav_failed() to decide
	whether to to wrap-around, and don't select active items on cursor
	navigation if gtk-keynav-cursor-only is TRUE. Should look at
	gtk-keynav-wrap-around too, will look into that.
parent af6b361d
2006-11-16 Michael Natterer <mitch@imendio.com>
Add new infrastructure for notifications of failed keyboard
navigation and navigation with restricted set of keys.
The patch handles configurable beeping, navigating the GUI with
cursor keys only (as in phone environments), and configurable
wrap-around. Fixes bugs #322640, #70986, #318827, #334726, #334742
and #309291.
* gtk/gtksettings.c: added properties gtk-keynav-cursor-only,
gtk-keynav-wrap-around and gtk-error-bell.
* gtk/gtkwidget.[ch]: added new signal "keynav-failed" and public
API to emit it. Added New function gtk_widget_error_bell() which
looks at the gtk-error-bell setting and calls gdk_window_beep()
accordingly.
* gtk/gtk.symbols: add the new widget symbols.
* gtk/gtkcellrendereraccel.c
* gtk/gtkimcontextsimple.c
* gtk/gtkmenu.c
* gtk/gtknotebook.c: use gtk_widget_error_bell() or look at the
gtk-error-bell setting instead of calling gdk_display_beep()
unconditionally.
* gtk/gtkcombobox.c
* gtk/gtkentry.c
* gtk/gtkiconview.c
* gtk/gtklabel.c
* gtk/gtkmenushell.c
* gtk/gtkspinbutton.c
* gtk/gtktextview.c
* gtk/gtktreeview.c: call gtk_widget_error_bell() on failed keynav.
* gtk/gtkentry.c
* gtk/gtklabel.c
* gtk/gtkrange.c
* gtk/gtktextview.c: consult gtk_widget_keynav_failed() on failed
cursor navigation and leave the widget if it returns FALSE.
* gtk/gtkmenushell.c
* gtk/gtknotebook.c: only wrap around if gtk-keynav-wrap-around
is TRUE.
* gtk/gtkradiobutton.c: ask gtk_widget_keynav_failed() to decide
whether to to wrap-around, and don't select active items on cursor
navigation if gtk-keynav-cursor-only is TRUE. Should look at
gtk-keynav-wrap-around too, will look into that.
2006-11-16 Emmanuele Bassi <ebassi@gnome.org>
* gtk/gtkrecentmanager.c:
......
......@@ -4470,6 +4470,7 @@ gtk_widget_create_pango_layout
gtk_widget_destroy
gtk_widget_destroyed
gtk_widget_ensure_style
gtk_widget_error_bell
gtk_widget_event
gtk_widget_freeze_child_notify
gtk_widget_get_accessible
......@@ -4511,6 +4512,7 @@ gtk_widget_hide_on_delete
gtk_widget_intersect
gtk_widget_is_ancestor
gtk_widget_is_focus
gtk_widget_keynav_failed
gtk_widget_list_accel_closures
gtk_widget_list_mnemonic_labels
gtk_widget_map
......
......@@ -456,7 +456,7 @@ grab_key_callback (GtkWidget *widget,
{
if (!gtk_accelerator_valid (accel_key, accel_mods))
{
gdk_display_beep (display);
gtk_widget_error_bell (widget);
return TRUE;
}
......
......@@ -4978,7 +4978,10 @@ gtk_combo_box_real_move_active (GtkComboBox *combo_box,
gboolean found;
if (!combo_box->priv->model)
return;
{
gtk_widget_error_bell (GTK_WIDGET (combo_box));
return;
}
active_iter = gtk_combo_box_get_active_iter (combo_box, &iter);
......@@ -5024,28 +5027,28 @@ gtk_combo_box_real_move_active (GtkComboBox *combo_box,
return;
}
if (found)
if (found && active_iter)
{
if (active_iter)
{
GtkTreePath *old_path;
GtkTreePath *new_path;
GtkTreePath *old_path;
GtkTreePath *new_path;
old_path = gtk_tree_model_get_path (combo_box->priv->model, &iter);
new_path = gtk_tree_model_get_path (combo_box->priv->model, &new_iter);
old_path = gtk_tree_model_get_path (combo_box->priv->model, &iter);
new_path = gtk_tree_model_get_path (combo_box->priv->model, &new_iter);
if (gtk_tree_path_compare (old_path, new_path) == 0)
found = FALSE;
if (gtk_tree_path_compare (old_path, new_path) == 0)
found = FALSE;
gtk_tree_path_free (old_path);
gtk_tree_path_free (new_path);
}
gtk_tree_path_free (old_path);
gtk_tree_path_free (new_path);
}
if (found)
{
gtk_combo_box_set_active_iter (combo_box, &new_iter);
return;
}
if (found)
{
gtk_combo_box_set_active_iter (combo_box, &new_iter);
}
else
{
gtk_widget_error_bell (GTK_WIDGET (combo_box));
}
}
......
......@@ -1709,12 +1709,18 @@ gtk_entry_button_press (GtkWidget *widget,
return TRUE;
}
else if (event->button == 2 && event->type == GDK_BUTTON_PRESS && entry->editable)
else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
{
priv->insert_pos = tmp_pos;
gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
return TRUE;
if (entry->editable)
{
priv->insert_pos = tmp_pos;
gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
return TRUE;
}
else
{
gtk_widget_error_bell (widget);
}
}
else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
{
......@@ -1976,6 +1982,9 @@ gtk_entry_key_press (GtkWidget *widget,
*/
return TRUE;
if (!entry->editable && event->length)
gtk_widget_error_bell (widget);
return FALSE;
}
......@@ -2329,7 +2338,7 @@ gtk_entry_real_insert_text (GtkEditable *editable,
n_chars = g_utf8_strlen (new_text, new_text_length);
if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
{
gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (entry)));
gtk_widget_error_bell (GTK_WIDGET (entry));
n_chars = entry->text_max_length - entry->text_length;
new_text_length = g_utf8_offset_to_pointer (new_text, n_chars) - new_text;
}
......@@ -2535,7 +2544,6 @@ gtk_entry_move_cursor (GtkEntry *entry,
new_pos = current_x < bound_x ? entry->current_pos : entry->selection_bound;
else
new_pos = current_x > bound_x ? entry->current_pos : entry->selection_bound;
break;
}
case GTK_MOVEMENT_LOGICAL_POSITIONS:
......@@ -2566,6 +2574,27 @@ gtk_entry_move_cursor (GtkEntry *entry,
break;
case GTK_MOVEMENT_VISUAL_POSITIONS:
new_pos = gtk_entry_move_visually (entry, new_pos, count);
if (entry->current_pos == new_pos)
{
if (!extend_selection)
{
if (!gtk_widget_keynav_failed (GTK_WIDGET (entry),
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT))
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
if (toplevel)
gtk_widget_child_focus (toplevel,
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT);
}
}
else
{
gtk_widget_error_bell (GTK_WIDGET (entry));
}
}
break;
case GTK_MOVEMENT_WORDS:
while (count > 0)
......@@ -2578,11 +2607,15 @@ gtk_entry_move_cursor (GtkEntry *entry,
new_pos = gtk_entry_move_backward_word (entry, new_pos, FALSE);
count++;
}
if (entry->current_pos == new_pos)
gtk_widget_error_bell (GTK_WIDGET (entry));
break;
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
new_pos = count < 0 ? 0 : entry->text_length;
if (entry->current_pos == new_pos)
gtk_widget_error_bell (GTK_WIDGET (entry));
break;
case GTK_MOVEMENT_DISPLAY_LINES:
case GTK_MOVEMENT_PARAGRAPHS:
......@@ -2624,11 +2657,15 @@ gtk_entry_delete_from_cursor (GtkEntry *entry,
GtkEditable *editable = GTK_EDITABLE (entry);
gint start_pos = entry->current_pos;
gint end_pos = entry->current_pos;
gint old_n_bytes = entry->n_bytes;
_gtk_entry_reset_im_context (entry);
if (!entry->editable)
return;
{
gtk_widget_error_bell (GTK_WIDGET (entry));
return;
}
if (entry->selection_bound != entry->current_pos)
{
......@@ -2685,7 +2722,10 @@ gtk_entry_delete_from_cursor (GtkEntry *entry,
gtk_entry_delete_whitespace (entry);
break;
}
if (entry->n_bytes == old_n_bytes)
gtk_widget_error_bell (GTK_WIDGET (entry));
gtk_entry_pend_cursor_blink (entry);
}
......@@ -2698,7 +2738,10 @@ gtk_entry_backspace (GtkEntry *entry)
_gtk_entry_reset_im_context (entry);
if (!entry->editable || !entry->text)
return;
{
gtk_widget_error_bell (GTK_WIDGET (entry));
return;
}
if (entry->selection_bound != entry->current_pos)
{
......@@ -2751,6 +2794,10 @@ gtk_entry_backspace (GtkEntry *entry)
g_free (log_attrs);
}
else
{
gtk_widget_error_bell (GTK_WIDGET (entry));
}
gtk_entry_pend_cursor_blink (entry);
}
......@@ -2784,6 +2831,10 @@ gtk_entry_cut_clipboard (GtkEntry *entry)
if (gtk_editable_get_selection_bounds (editable, &start, &end))
gtk_editable_delete_text (editable, start, end);
}
else
{
gtk_widget_error_bell (GTK_WIDGET (entry));
}
}
static void
......@@ -2791,6 +2842,8 @@ gtk_entry_paste_clipboard (GtkEntry *entry)
{
if (entry->editable)
gtk_entry_paste (entry, GDK_NONE);
else
gtk_widget_error_bell (GTK_WIDGET (entry));
}
static void
......
......@@ -3796,7 +3796,10 @@ gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
}
if (!item)
return;
{
gtk_widget_error_bell (GTK_WIDGET (icon_view));
return;
}
if (icon_view->priv->ctrl_pressed ||
!icon_view->priv->shift_pressed ||
......@@ -3847,6 +3850,9 @@ gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
icon_view->priv->cursor_item,
count);
if (item == icon_view->priv->cursor_item)
gtk_widget_error_bell (GTK_WIDGET (icon_view));
if (!item)
return;
......@@ -3915,7 +3921,10 @@ gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
}
if (!item)
return;
{
gtk_widget_error_bell (GTK_WIDGET (icon_view));
return;
}
if (icon_view->priv->ctrl_pressed ||
!icon_view->priv->shift_pressed ||
......@@ -3958,6 +3967,9 @@ gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
item = list ? list->data : NULL;
if (item == icon_view->priv->cursor_item)
gtk_widget_error_bell (GTK_WIDGET (icon_view));
if (!item)
return;
......
......@@ -23,6 +23,8 @@
#include <gdk/gdkkeysyms.h>
#include "gtkaccelgroup.h"
#include "gtkimcontextsimple.h"
#include "gtksettings.h"
#include "gtkwidget.h"
#include "gtkintl.h"
#include "gtkalias.h"
......@@ -1175,6 +1177,31 @@ check_hex (GtkIMContextSimple *context_simple,
return TRUE;
}
static void
beep_window (GdkWindow *window)
{
GtkWidget *widget;
gdk_window_get_user_data (window, &widget);
if (GTK_IS_WIDGET (widget))
{
gtk_widget_error_bell (widget);
}
else
{
GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
gboolean beep;
g_object_get (gtk_settings_get_for_screen (screen),
"gtk-error-bell", &beep,
NULL);
if (beep)
gdk_window_beep (window);
}
}
static gboolean
no_sequence_matches (GtkIMContextSimple *context_simple,
gint n_compose,
......@@ -1212,7 +1239,7 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
context_simple->compose_buffer[0] = 0;
if (n_compose > 1) /* Invalid sequence */
{
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
return TRUE;
}
......@@ -1317,7 +1344,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
else
{
/* invalid hex sequence */
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
context_simple->tentative_match = 0;
context_simple->in_hex_sequence = FALSE;
......@@ -1403,7 +1430,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
{
/* invalid hex sequence */
if (n_compose > 0)
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
context_simple->tentative_match = 0;
context_simple->in_hex_sequence = FALSE;
......@@ -1438,7 +1465,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
else if (!is_hex_end)
{
/* non-hex character in hex sequence */
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
return TRUE;
}
......@@ -1465,7 +1492,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
else
{
/* invalid hex sequence */
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
context_simple->tentative_match = 0;
context_simple->in_hex_sequence = FALSE;
......@@ -1473,7 +1500,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
}
}
else if (!check_hex (context_simple, n_compose))
gdk_display_beep (gdk_drawable_get_display (event->window));
beep_window (event->window);
g_signal_emit_by_name (context_simple, "preedit_changed");
......
......@@ -891,8 +891,8 @@ gtk_label_mnemonic_activate (GtkWidget *widget,
/* barf if there was nothing to activate */
g_warning ("Couldn't find a target for a mnemonic activation.");
gdk_display_beep (gtk_widget_get_display (widget));
gtk_widget_error_bell (widget);
return FALSE;
}
......@@ -3871,12 +3871,13 @@ gtk_label_move_cursor (GtkLabel *label,
gint count,
gboolean extend_selection)
{
gint old_pos;
gint new_pos;
if (label->select_info == NULL)
return;
new_pos = label->select_info->selection_end;
old_pos = new_pos = label->select_info->selection_end;
if (label->select_info->selection_end != label->select_info->selection_anchor &&
!extend_selection)
......@@ -3901,7 +3902,6 @@ gtk_label_move_cursor (GtkLabel *label,
new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
else
new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
break;
}
case GTK_MOVEMENT_LOGICAL_POSITIONS:
......@@ -3933,6 +3933,27 @@ gtk_label_move_cursor (GtkLabel *label,
break;
case GTK_MOVEMENT_VISUAL_POSITIONS:
new_pos = gtk_label_move_visually (label, new_pos, count);
if (new_pos == old_pos)
{
if (!extend_selection)
{
if (!gtk_widget_keynav_failed (GTK_WIDGET (label),
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT))
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
if (toplevel)
gtk_widget_child_focus (toplevel,
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT);
}
}
else
{
gtk_widget_error_bell (GTK_WIDGET (label));
}
}
break;
case GTK_MOVEMENT_WORDS:
while (count > 0)
......@@ -3945,12 +3966,16 @@ gtk_label_move_cursor (GtkLabel *label,
new_pos = gtk_label_move_backward_word (label, new_pos);
count++;
}
if (new_pos == old_pos)
gtk_widget_error_bell (GTK_WIDGET (label));
break;
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
/* FIXME: Can do better here */
new_pos = count < 0 ? 0 : strlen (label->text);
if (new_pos == old_pos)
gtk_widget_error_bell (GTK_WIDGET (label));
break;
case GTK_MOVEMENT_DISPLAY_LINES:
case GTK_MOVEMENT_PARAGRAPHS:
......
......@@ -2756,7 +2756,7 @@ gtk_menu_key_press (GtkWidget *widget,
* (basically, those items are accelerator-locked).
*/
/* g_print("item has no path or is locked, menu prefix: %s\n", menu->accel_path); */
gdk_display_beep (display);
gtk_widget_error_bell (widget);
}
else
{
......@@ -2785,7 +2785,7 @@ gtk_menu_key_press (GtkWidget *widget,
* locked already
*/
/* g_print("failed to change\n"); */
gdk_display_beep (display);
gtk_widget_error_bell (widget);
}
}
}
......
......@@ -1044,17 +1044,27 @@ gtk_menu_shell_move_selected (GtkMenuShell *menu_shell,
GList *node = g_list_find (menu_shell->children,
menu_shell->active_menu_item);
GList *start_node = node;
gboolean wrap_around;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
"gtk-keynav-wrap-around", &wrap_around,
NULL);
if (distance > 0)
{
node = node->next;
while (node != start_node &&
(!node || !_gtk_menu_item_is_selectable (node->data)))
{
if (!node)
node = menu_shell->children;
else
if (node)
node = node->next;
else if (wrap_around)
node = menu_shell->children;
else
{
gtk_widget_error_bell (GTK_WIDGET (menu_shell));
break;
}
}
}
else
......@@ -1063,10 +1073,15 @@ gtk_menu_shell_move_selected (GtkMenuShell *menu_shell,
while (node != start_node &&
(!node || !_gtk_menu_item_is_selectable (node->data)))
{
if (!node)
node = g_list_last (menu_shell->children);
else
if (node)
node = node->prev;
else if (wrap_around)
node = g_list_last (menu_shell->children);
else
{
gtk_widget_error_bell (GTK_WIDGET (menu_shell));
break;
}
}
}
......
......@@ -1066,14 +1066,33 @@ gtk_notebook_change_current_page (GtkNotebook *notebook,
while (offset != 0)
{
current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
current = gtk_notebook_search_page (notebook, current,
offset < 0 ? STEP_PREV : STEP_NEXT,
TRUE);
if (!current)
{
gboolean wrap_around;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
"gtk-keynav-wrap-around", &wrap_around,
NULL);
if (wrap_around)
current = gtk_notebook_search_page (notebook, NULL,
offset < 0 ? STEP_PREV : STEP_NEXT,
TRUE);
else
break;
}
offset += offset < 0 ? 1 : -1;
}
if (current)
gtk_notebook_switch_page (notebook, current->data, -1);
else
gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
gtk_widget_error_bell (GTK_WIDGET (notebook));
}
static GtkDirectionType
......@@ -3589,11 +3608,24 @@ focus_tabs_move (GtkNotebook *notebook,
new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
search_direction, TRUE);
if (!new_page)
{
gboolean wrap_around;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
"gtk-keynav-wrap-around", &wrap_around,
NULL);
if (wrap_around)
new_page = gtk_notebook_search_page (notebook, NULL,
search_direction, TRUE);
}
if (new_page)
gtk_notebook_switch_focus_tab (notebook, new_page);
else
gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
gtk_widget_error_bell (GTK_WIDGET (notebook));
return TRUE;
}
......
......@@ -491,6 +491,12 @@ gtk_radio_button_focus (GtkWidget *widget,
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 *widget,
if (new_focus)
{
GtkSettings *settings = gtk_widget_get_settings (widget);
gboolean cursor_only;
g_object_get (settings,
"gtk-keynav-cursor-only", &cursor_only,
NULL);
gtk_widget_grab_focus (new_focus);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
if (!cursor_only)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
}
return TRUE;
......
......@@ -2457,6 +2457,42 @@ static void
gtk_range_move_slider (GtkRange *range,
GtkScrollType scroll)
{
gboolean cursor_only;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (range)),
"gtk-keynav-cursor-only", &cursor_only,
NULL);
if (cursor_only)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (range));
if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
{
if (scroll == GTK_SCROLL_STEP_UP ||
scroll == GTK_SCROLL_STEP_DOWN)
{
if (toplevel)
gtk_widget_child_focus (toplevel,
scroll == GTK_SCROLL_STEP_UP ?
GTK_DIR_UP : GTK_DIR_DOWN);
return;
}
}
else
{
if (scroll == GTK_SCROLL_STEP_LEFT ||
scroll == GTK_SCROLL_STEP_RIGHT)
{
if (toplevel)
gtk_widget_child_focus (toplevel,
scroll == GTK_SCROLL_STEP_LEFT ?
GTK_DIR_LEFT : GTK_DIR_RIGHT);
return;
}
}
}
gtk_range_scroll (range, scroll);
/* Policy DELAYED makes sense with key events,
......
......@@ -93,6 +93,9 @@ enum {
PROP_COLOR_SCHEME,
PROP_ENABLE_ANIMATIONS,
PROP_TOUCHSCREEN_MODE,
PROP_KEYNAV_CURSOR_ONLY,
PROP_KEYNAV_WRAP_AROUND,
PROP_ERROR_BELL,
PROP_COLOR_HASH
};
......@@ -507,7 +510,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
/**
* GtkSettings:gtk-touchscreen-mode:
*
* When TRUE, there are no motion notify events delivered on this screen,
* When %TRUE, there are no motion notify events delivered on this screen,
* and widgets can't use the pointer hovering them for any essential
* functionality.
*
......@@ -523,6 +526,64 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_assert (result == PROP_TOUCHSCREEN_MODE);
/**
* GtkSettings:gtk-keynav-cursor-only:
*
* 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.
*