Focus management needs update after several deprecations
@infapi00
Submitted by Alejandro Piñeiro Link to original bug (#705926)
Description
Several focus related methods has been recently deprecated on atk (see bug 649575 comment 8). Specifically: AtkObject::focus_event atk_add_focus_tracker atk_remove_focus_tracker atk_focus_tracker_init atk_focus_tracker_notify atk_component_add_focus_handler atk_component_remove_focus_handler
That means that, as agreed, the only focus related notification is a proper emission of state-change:focused.
This change was already made on clutter a long time ago (see clutter commit cc126f55eb948a528211bc1649cd20bc7a7c0ed7) and all seems to work nicely. It is also true that gtk accessibility implementation is really more complex than clutter/st one.
In that aspect, I took a look to see if it would be just removing code from gtk, and what I found is the (already familiar) gail nightmare on focus management. As far as I see, the current code:
- AtkObject::focus-event is emitted on a GtkWidget::focus-[in/out]-event callback at gtkwidgetaccessible.
- Then gtkaccessibility.c uses atk_focus_tracker_init, atk_add_focus_tracker, atk_focus_tracker_notify and the respective trackers (and trackers on idles), used for update a gobject data with the quark "gail-focus-object", that in most cases, is the previous focused object.
- Additionally there are another global _focus_widget variable at both gtkwidgetaccessible.c and gtkaccessibility.c. extern at gtkwidgetaccessible, updated at gtkaccessibilty. For any reason, in order to add the focused state at ref_state_set, it is not enough to call gtk_widget_has_focus. And of course a global next_focus_widget, subsequent_focus_widget and focus_before_menu
- Then again at gtkwidgetaccessible.c: AtkObject::focus-event is redefined, and notifies the object state change using the 'gail-focus-object'.
- There are a lot of corner cases contemplated, like this:
/*
- We listen for deactivate signals on menushells to determine
- when the "focus" has left the menus. */ g_signal_add_emission_hook ( g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0, gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
- I also have the feeling that in several cases all the implementation become really nastier because it was forced to emit focus events when just a selection change happened.
I'm tempted to say that all what is needed is:
- Call atk_object_notify_state_change at the callback to GtkWidget::focus-[in/out]-event. In gtk this is easier that in clutter, as we have a focus-in and focus-out event.
- Just add ATK_STATE_FOCUSED if gtk_widget_has_focus returns true at ref_state_set
- Nuke the rest of the focus management code.
That was basically what I did on clutter (in the end some extra checking was needed to avoid emission for destroyed objects).
But, taking into account the overwhelming amount of corner-cases contemplated (so a hypothetical overwhelming amount of regressions), and that we are approaching the end of this cycle, probably it would be better to make the change at the beginning of next cycle in order to catch regressions during all the cycle.
Finally, my plan is still include all the deprecations on next stable release of the current cycle, unless anyone has strong feelings against that.