wmww / gtk-layer-shell

A library to create panels and other desktop components for Wayland using the Layer Shell protocol
GNU General Public License v3.0
319 stars 16 forks source link

Events not received during a grab #141

Closed Tamaranch closed 1 year ago

Tamaranch commented 1 year ago

GtkLayerShell 0.8.0 and GTK 3.24.35 on Arch Linux

When a grab takes place from an application whose main window is a layer-shell window (for example when showing a GtkMenu), some events that are well received without layer-shell are not received anymore. I have identified at least two of them:

Here is a minimal reproducer, which works for "button-release-event" regarding the second point. My actual use case is more complex and in this case the problem may change from button-release to button-press, but I think it remains basically the same.

p.c ```c #include #include static gboolean trace_key_press (GtkWidget *widget, GdkEvent *event, gpointer data) { g_printerr ("%s:%s\n", G_STRLOC, G_STRFUNC); return FALSE; } static gboolean trace_button_press (GtkWidget *widget, GdkEvent *event, gpointer data) { g_printerr ("%s:%s\n", G_STRLOC, G_STRFUNC); return FALSE; } static gboolean trace_button_release (GtkWidget *widget, GdkEvent *event, gpointer data) { g_printerr ("%s:%s\n", G_STRLOC, G_STRFUNC); return FALSE; } static gboolean menu_popup (GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { gtk_menu_popup_at_widget (menu, widget, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_SOUTH_WEST, event); return TRUE; } gint main (gint argc, gchar **argv) { GtkWidget *window; GMainLoop *loop; GtkWidget *button; GtkWidget *menu; GtkWidget *item; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); button = gtk_button_new_with_label ("test"); gtk_container_add (GTK_CONTAINER (window), button); menu = gtk_menu_new (); gtk_menu_attach_to_widget (GTK_MENU (menu), button, NULL); item = gtk_menu_item_new_with_label ("test"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (button, "key-press-event", G_CALLBACK (trace_key_press), NULL); g_signal_connect (button, "button-press-event", G_CALLBACK (trace_button_press), NULL); g_signal_connect (button, "button-release-event", G_CALLBACK (trace_button_release), NULL); g_signal_connect (button, "button-press-event", G_CALLBACK (menu_popup), menu); for (gchar **p = argv + 1; *p != NULL; p++) if (g_strcmp0 (*p, "--layer") == 0) gtk_layer_init_for_window (GTK_WINDOW (window)); else if (g_strcmp0 (*p, "--release") == 0) { g_signal_handlers_disconnect_by_func (button, menu_popup, menu); g_signal_connect (button, "button-release-event", G_CALLBACK (menu_popup), menu); } gtk_widget_show (item); gtk_widget_show (button); gtk_widget_show (window); loop = g_main_loop_new (NULL, FALSE); g_signal_connect_swapped (window, "destroy", G_CALLBACK (g_main_loop_quit), loop); g_main_loop_run (loop); g_main_loop_unref (loop); } ```

To build it:

gcc p.c -o p $(pkg-config --cflags --libs gtk+-3.0 gtk-layer-shell-0)

To run it:

./p [--layer] [--release]

where --layer enables layer-shell and --release shows the menu on button-release instead of button-press. Then press the button to show the menu and see if you can hide it by pressing Esc or by clicking the button again.

NB:

wmww commented 1 year ago

Thanks for provided a simple reproducer. I think the problem is probably that keybaord events are not sent to layer shell clients if the keyboard mode is none (default). gtk_layer_set_keyboard_mode (GTK_WINDOW (window), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND); should fix the problem you describe. See this for details.

I noticed another problem though. On Sway (version 1.7 at least) on-demand keyboard interactivity is silently treated as exclusive. The layer shell surface can get keyboard focus, but it can't loose it. this stops Sway claiming it's supported, but that doesn't get us much. I also tested with Mir, where on-demand keyboard interactivity is implemented and works.

TL;DR it may not be possible to fix this without changes to Sway (if that's the Wayland compositor you're using)

Tamaranch commented 1 year ago

I think the problem is probably that keybaord events are not sent to layer shell clients if the keyboard mode is none (default).

Oops sorry, and thanks, I completely missed that one. So sure I had already gone through every aspect of the protocol that I didn't even look it up again :sweat_smile:

I use Labwc and Wayfire and it does solve the problem on both for the keyboard.

wmww commented 1 year ago

I had an idea to automatically switch to exclusive keyboard focus when a grabbing popup appears and automatically switch back when it's dismissed. This, again, works on Mir but seems to have problems on Sway. Though sounds like that might not be needed anymore.

Tamaranch commented 1 year ago

I use Labwc and Wayfire and it does solve the problem on both for the keyboard.

Hmm it seems that for real life apps it is not so simple though. It's probably best to switch between exclusive and none to get a reliable result.

wmww commented 1 year ago

Within your app you might be able to hook up the right callbacks to turn exclusive interactivity on and off as needed. If that proves difficult then it may need to be done from within GTK Layer Shell. I'm not going to implement that right now. PRs welcome, though if it adds significant complexity or only works for/is needed on a single compositor I'm less likely to merge.

Tamaranch commented 1 year ago

In fact it works quite well with Labwc >= 0.5.3, and for Wayfire it was necessary to use git-master >= d296170e. It's not always perfect though and I'd probably have to tweak it a bit more and/or ask for improvements upstream, but it's fine for now.

Do you have any hints for the second point? (toggle effect broken)

Consolatis commented 1 year ago

It works quite well with Labwc >= 0.5.3

Labwc 0.6.0 / master branch differ substantially from 0.5.x. Suggest to always test with at least 0.6.0. Bug reports of us doing something wrong / non-spec-compliant are always welcome.

wmww commented 1 year ago

Not a bug, so closing. New feature proposal in #144.

Tamaranch commented 1 year ago

The second point concerning pointer events is independent of the keyboard though, and has not been addressed (or I missed something...)

wmww commented 1 year ago

I don't fully understand the pointer event problem. I can run the code, but can you describe the expected behavior and actual behavior more clearly?

Tamaranch commented 1 year ago

If you run ./p --layer --release, after showing the menu once on button-release, it remains blocked, the button is no longer clickable. Clicking the button again should hide the menu, just like when it is shown on button-press.

wmww commented 1 year ago

Ok, yeah, that's weird.

spl237 commented 1 year ago

Yes, the problem you describe sounds exactly like the one I report on that issue.

Tamaranch commented 1 year ago

I can confirm it fixes the issue, thanks!