Label's mnemonic activation doesn't traverse the widget tree to find the first activatable ancestor
Steps to reproduce
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.98"/>
<object class="GtkButton" id="foo">
<property name="valign">center</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label">_TEST</property>
<!-- <property name="mnemonic-widget">foo</property> -->
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="icon-name">jsjdjsdd</property>
</object>
</child>
</object>
</child>
</object>
</interface>
- Save this file in
foo.ui
- Run `gtk4-builder-tool preview --id=foo foo.ui
- Press Alt+t to activate the button
Current behavior
The button isn't activated.
Expected outcome
The documentation states that
If gtk_label_set_mnemonic_widget() is not called, then the first activatable ancestor of the GtkLabel will be chosen as the mnemonic widget. For instance, if the label is inside a button or menu item, the button or menu item will automatically become the mnemonic widget and be activated by the mnemonic.
So here I would expect that activating the "T" mnemonic of the label would have activated the button since it is the first activatable ancestor. Now if you comment out the GtkBox and the GtkImage child, it'll work fine because it is the direct parent of the label. Now if you uncomment them back and uncomment the line that manually sets the mnemonic-widget, it works fine too.
Version information
GTK4, both with the one from the GNOME flatpak SDK and with the Fedora 34 packages.
Additional information
I had a bit a look and it seems like the function that handles the label's mnemonic is gtk_label_mnemonic_activate
in gtk/gtklabel.c
. I didn't actually really debug this but I think the problem is this part of the code:
if (gtk_widget_get_can_focus (parent) ||
(!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
GTK_IS_NOTEBOOK (gtk_widget_get_parent (parent)) ||
GTK_IS_MENU_ITEM (parent))
return gtk_widget_mnemonic_activate (parent, group_cycling);
parent = gtk_widget_get_parent (parent);
So what I think happens is that the first parent of the label, the GtkBox, is can-focus so it tries directly to activate it even though it isn't an activatable widget. So in practice the propagation of mnemonic activation stops here since the box isn't activatable. The comment a few lines above this line in the code states that it "traverses the widget ancestry" but in practice it's not what's happening.
So I think what should be done is that if the widget doesn't have the ->activate_signal vfunc, then a different function should be called that continue traversing the widget tree until an activatable widget or a NULL parent is found.