GNOME Bugzilla – Bug 693050
GtkTextView focus handler doesn't honor can-focus property
Last modified: 2013-02-03 20:51:34 UTC
No matter wether clearing or setting the can-focus property of a GtkTextView, the focus handler will alwas return TRUE, thus preventing the focus to move on to the next focussable widget. Steps to reproduce ------------------ - put 3 instances of GtkTextView in a GtkVBox - clear the can-focus property of the middle GtkTextView - place focus on the first GtkTextView - hit TAB -> nothing happens, the focus will stay on the first GtkTextView We've discovered this bug in Gtk+ 2.24.4, but it is still present in the latest release 3.7.x. Original Code (wrong): --------------------- static gboolean gtk_text_view_focus (GtkWidget *widget, GtkDirectionType direction) { GtkContainer *container; gboolean result; container = GTK_CONTAINER (widget); if (!gtk_widget_is_focus (widget) && container->focus_child == NULL) { gtk_widget_grab_focus (widget); return TRUE; /* <---- here's the problem */ } else { /* * Unset CAN_FOCUS flag so that gtk_container_focus() allows * children to get the focus */ gtk_widget_set_can_focus (widget, FALSE); result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction); gtk_widget_set_can_focus (widget, TRUE); return result; } } Proposed Fix: ------------- static gboolean gtk_text_view_focus(GtkWidget *widget, GtkDirectionType direction) { GtkContainer *container; gboolean result; container = GTK_CONTAINER(widget); if (!gtk_widget_is_focus(widget) && container->focus_child == NULL) { if (gtk_widget_get_can_focus (widget)) /* 02.02.13/fp */ { gtk_widget_grab_focus(widget); return TRUE; } return FALSE; /* 02.02.13/fp */ } else { /* * Unset CAN_FOCUS flag so that gtk_container_focus() allows * children to get the focus */ gtk_widget_set_can_focus (widget, FALSE); result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction); gtk_widget_set_can_focus (widget, TRUE); return result; } } The Fix was tested on 64-Bit Linux and 32-Bit Windows MinGW and reported to work. fp
I don't think you analysis is entirely right, but it is hard to say without a test program that shows what you are trying to achieve. A few considerations: 1) GtkTextView will insert the tab as content, unless you set accepts-tab to FALSE 2) the code in gtk_text_view_focus clearly shows that GtkTextView is not prepared to have can-focus set to FALSE - it always resets the can-focus to TRUE in the else clause of that function. 3) Maybe you rather want editable = FALSE ? 4) You could try setting a focus chain on the container instead. Why do you want to make it impossible to focus that middle text view in the first place ?
1) You're right. I forgot to mention that the 'accepts-tab' was set to FALSE. There should always be a possibility to navigate through a user interface by keyboard, without having to touch the mouse. We could also use some modified arrow keys for navigation, but the problem remains as described. 2) The else part will only be executed if the wiget has focus or has any childs, which is necessary focus on the childs. It is acceptable to set 'can-focus' to TRUE in that case, because otherwise you cannot access the childs. Maybe we should be more precise and set the 'can-focus' flag to TRUE only iff there really are any childs attached. Generally widgets should not modify 'can-focus', except to restore correct focus chain operation. 3) We're using the middle TextView to display some readonly information between two editable fields. We cannot use 'sensitive' = FALSE because the user would no longer be able to select and copy the information with the mouse. 4) Removing the middle TextView out of the focus chain works, but forces us to keep two copies of the focus chains in memory. One inactive copy for the widget order and another active copy to fix correct focus chain behaviour for GtkTextView. All other widgets obey to the 'can-focus' setting, only GtkTextView does not. --- The proposed fix doesn't do any harm for existing applications. It only fixes the broken focus chain for GtkTextView. It allows you to move on to the next focussable widget. The focus signal handler should return FALSE if the focus can not be moved within the widget or it's decendants. Returning FALSE will allow the parent container to try the next widget in the focus chain. Have a look at gtk_container_focus_move(). fp
ok, pushed a fix like this