After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 693050 - GtkTextView focus handler doesn't honor can-focus property
GtkTextView focus handler doesn't honor can-focus property
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: Other
3.7.x
Other All
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2013-02-02 10:44 UTC by Fredy Paquet
Modified: 2013-02-03 20:51 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Fredy Paquet 2013-02-02 10:44:43 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
Comment 1 Matthias Clasen 2013-02-03 00:28:03 UTC
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 ?
Comment 2 Fredy Paquet 2013-02-03 08:46:31 UTC
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
Comment 3 Matthias Clasen 2013-02-03 20:51:34 UTC
ok, pushed a fix like this