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 765595 - Modal popover does not close when focus leaves it
Modal popover does not close when focus leaves it
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: GtkPopover
3.20.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2016-04-26 10:44 UTC by Phillip Wood
Modified: 2016-06-06 10:22 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fix hiding popover when focus moves outside (2.04 KB, patch)
2016-04-26 10:45 UTC, Phillip Wood
none Details | Review
test program (2.93 KB, text/x-python)
2016-04-26 11:29 UTC, Phillip Wood
  Details
Thanks for your comments Carlos, I've updated the patch as you (2.10 KB, patch)
2016-04-30 13:29 UTC, Phillip Wood
committed Details | Review

Description Phillip Wood 2016-04-26 10:44:27 UTC
If the focus leaves a modal popover for a popover or widget that is not related to it it should close. At the moment this is not the case. The program attached demonstrates this. If you run it and press ‘0’ to activate the first row a popover appears. If you then press ‘2’ another popover appears, the first one does not close. Now press ‘9’ to focus the last listbox row - both the popovers remain open the movement keys move the focus within the listbox. If you activate a single row and then press ‘Alt-P’ and then ‘Alt-R’ both the menu-buttons in the popover open their popovers, when the popover belonging to the second menu-button opens it should close the first one. This is fallout from bug 750741
Comment 1 Phillip Wood 2016-04-26 10:45:24 UTC
Created attachment 326747 [details] [review]
Fix hiding popover when focus moves outside

Commit a01fe14 changed the behaviour of popovers when the focus leaves
them to stop child popovers being hidden when the focus leaves their
parent. However they are now a bit too reluctant to hide - if the
focus passes to an unrelated popover the first popover is not
hidden. Also if the focus passes to another widget that does not
perform a gtk grab then the popover isn't hidden until the user
presses a non-movement key or clicks outside the popover.

The solution is to go back to checking if the focused widget is a
descendant of the popover, but to include popovers and their related
widgets in the ancestry chain.
Comment 2 Phillip Wood 2016-04-26 11:29:47 UTC
Created attachment 326748 [details]
test program

Sorry I forgot to actually attach the test program to comment 1
Comment 3 Phillip Wood 2016-04-26 13:23:09 UTC
Review of attachment 326747 [details] [review]:

::: gtk/gtkpopover.c
@@ +443,3 @@
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
+  if (!priv->modal || !widget)

It should check if the popover is drawable here

@@ +455,2 @@
     }
+  gtk_widget_hide (popover);

It should probably do something about clearing the saved focus widget here, as the focus goes back to the old focus row rather than the newly focused row it the test program
Comment 4 Matthias Clasen 2016-04-26 14:10:33 UTC
(In reply to Phillip Wood from comment #0)
> If the focus leaves a modal popover for a popover or widget that is not
> related to it it should close.

Thats a bit of an unsubstantiated assertion.
Comment 5 Phillip Wood 2016-04-26 15:11:49 UTC
(In reply to Matthias Clasen from comment #4)
> (In reply to Phillip Wood from comment #0)
> > If the focus leaves a modal popover for a popover or widget that is not
> > related to it it should close.
> 
> Thats a bit of an unsubstantiated assertion.

It's based on
commit 43e88528292b9c786be3de04cdd8b2a6fc8266dd
Author: Carlos Garnacho <carlosg@gnome.org>
Date:   Thu Mar 6 16:58:06 2014 +0100

    popover: Track toplevel's focus widget when visible
    
    If the toplevel focus widget is forced out of the popover (eg. through
    gtk_widget_grab_focus() anywhere else), then dismiss the popover.


If you do 'git log -L :window_set_focus:gtk/gtkpopover.c' you'll see the commit messages are all about hiding the popover if the focus escapes to an unrelated widget.

As it stands if you open a popover from a menu button and then activate another unrelated menu button with a mnemonic the first popover does not close even though the second menu has nothing to do with the first - is this actually the intended behaviour?

The patch is based on the suggestion from Carlos Garnacho in comment 6 in bug 750741 [1]

[1] https://bugzilla.gnome.org/show_bug.cgi?id=750741#c6
Comment 6 Matthias Clasen 2016-04-26 15:41:09 UTC
Fair enough. Lets see what Carlos thinks
Comment 7 Carlos Garnacho 2016-04-26 17:55:28 UTC
Review of attachment 326747 [details] [review]:

Thanks for the patch, the approach makes sense.

::: gtk/gtkpopover.c
@@ +439,3 @@
 window_set_focus (GtkWindow  *window,
                   GtkWidget  *widget,
+                  gpointer    popover)

I understand gpointer is convenient here, although I'd prefer to keep some typing here, IMO it'd be better to settle with GtkWidget or GtkPopover.

@@ +448,2 @@
+  while (widget &&
+         (widget = gtk_widget_get_ancestor (widget, GTK_TYPE_POPOVER)))

These inline assignments are IMO too easy to go unnoticed when later revisiting the code... I'd prefer having it further explicit with a (...) != NULL check, or doing this (plus the "if null, break" check) inside the while statement.

@@ +455,2 @@
     }
+  gtk_widget_hide (popover);

Right, probably just needs a prior call to popover_unset_prev_focus()
Comment 8 Carlos Garnacho 2016-04-26 17:56:49 UTC
(In reply to Carlos Garnacho from comment #7)
> @@ +455,2 @@
>      }
> +  gtk_widget_hide (popover);
> 
> Right, probably just needs a prior call to popover_unset_prev_focus()

This was meant to be a reply to:

(In reply to Phillip Wood from comment #3)
> @@ +455,2 @@
>      }
> +  gtk_widget_hide (popover);
> 
> It should probably do something about clearing the saved focus widget here,
> as the focus goes back to the old focus row rather than the newly focused
> row it the test program
Comment 9 Phillip Wood 2016-04-30 13:29:19 UTC
Created attachment 327073 [details] [review]
Thanks for your comments Carlos, I've updated the patch as you

suggested
 - popover is now GtkPopover* rather than gpointer
 - the assignment is now in the body of the while loop
 - it calls popover_unset_prev_focus() before hiding

One thing I've noticed while testing the patch is that the Tab key
behaves differently depending on how many widgets there are in the
popover. With only one widget pressing Tab moves the focus to the
first widget in the window containing the popover (and so closes the
popover with this patch applied). If there is more than one widget
then the focus cycles between them so it cannot escape from the
popover. It might be better if the single widget case either trapped
the focus or focused priv->prev_focus_widget instead. I can open
another bug if you think it's worth changing it.
Comment 10 Daniel Boles 2016-06-06 10:22:32 UTC
Out of interest, I've always wondered: what is an example use-case for not closing the Popover when focus leaves it? Are people using DND onto Popovers or something else? Just curious as personally I've always expected Popovers to close right away and not found a case where I need them to stay open. (In fact, it's meant I've had to do some creative workarounds when handling window events)