GNOME Bugzilla – Bug 781811
mutter not emitting `configure` events during `resize` of a GUI application (whereas weston does)
Last modified: 2017-06-07 02:04:20 UTC
I'm having an issue where a GUI application I'm working on is working correctly when I run it in weston 2.0.0, but when I run it with gnome-terminal 3.24.1 it does not receive `configure` events during resize, resulting in not being able to resize the window. By using `WAYLAND_DEBUG=1` I can see the resize event occuring: ``` [392175.083] -> zxdg_toplevel_v6@21.resize(wl_seat@10, 239276, 10) ``` However the application doesn't receive any `configure` events afterwards. Curiously, `configure` events are emitted when losing or gaining focus of the window, just not during resize from what I can tell. I originally thought the problem might be that the library I'm using only supports `wl_shell`, however after updating it to use the `zxdg_shell_v6` I'm still getting the exact same behaviour. You can find the pull request I submitted for this change [here](https://github.com/vberger/wayland-window/pull/17). I decided to run the GUI application on both mutter and wayland to compare the output of `WAYLAND_DEBUG=1` to see if I could spot any differences. The only difference I could see was in the globals registered at startup. They were all the same, other than weston registering "xdg_shell", "weston_desktop_shell" and "weston_screenshooter" whereas mutter does not, but did register "gtk_shell1". I guess these are expected differences though? Here is the output of the startup registry global stage for both compositors: **weston** ``` [3812751.543] wl_registry@2.global(1, "wl_compositor", 4) [3812751.554] wl_registry@2.global(2, "wl_subcompositor", 1) [3812751.561] wl_registry@2.global(3, "wp_viewporter", 1) [3812751.568] wl_registry@2.global(4, "wp_presentation", 1) [3812751.584] wl_registry@2.global(5, "zwp_relative_pointer_manager_v1", 1) [3812751.593] wl_registry@2.global(6, "zwp_pointer_constraints_v1", 1) [3812751.602] wl_registry@2.global(7, "wl_data_device_manager", 3) [3812751.612] wl_registry@2.global(8, "wl_shm", 1) [3812751.623] wl_registry@2.global(9, "wl_seat", 5) [3812751.637] wl_registry@2.global(10, "wl_drm", 2) [3812751.647] wl_registry@2.global(11, "zwp_linux_dmabuf_v1", 1) [3812751.658] wl_registry@2.global(12, "wl_output", 3) [3812751.668] wl_registry@2.global(13, "zwp_input_panel_v1", 1) [3812751.679] wl_registry@2.global(14, "zwp_input_method_v1", 1) [3812751.691] wl_registry@2.global(15, "zwp_text_input_manager_v1", 1) [3812751.702] wl_registry@2.global(16, "zxdg_shell_v6", 1) [3812751.714] -> wl_registry@2.bind(1, "wl_compositor", 4, new id [unknown]@4) [3812751.749] -> wl_registry@2.bind(2, "wl_subcompositor", 1, new id [unknown]@5) [3812751.762] -> wl_registry@2.bind(8, "wl_shm", 1, new id [unknown]@6) [3812751.771] -> wl_registry@2.bind(16, "zxdg_shell_v6", 1, new id [unknown]@7) [3812751.798] wl_registry@2.global(17, "xdg_shell", 1) [3812751.805] wl_registry@2.global(18, "wl_shell", 1) [3812751.811] wl_registry@2.global(19, "weston_desktop_shell", 1) [3812751.818] wl_registry@2.global(20, "weston_screenshooter", 1) ``` **mutter** ``` [2095686.583] wl_registry@2.global(1, "wl_drm", 2) [2095686.598] wl_registry@2.global(2, "wl_compositor", 3) [2095686.606] wl_registry@2.global(3, "wl_shm", 1) [2095686.616] wl_registry@2.global(5, "wl_output", 2) [2095686.640] wl_registry@2.global(6, "wl_data_device_manager", 3) [2095686.652] wl_registry@2.global(7, "gtk_primary_selection_device_manager", 1) [2095686.662] wl_registry@2.global(8, "zxdg_shell_v6", 1) [2095686.675] wl_registry@2.global(9, "wl_shell", 1) [2095686.687] wl_registry@2.global(10, "gtk_shell1", 1) [2095686.699] wl_registry@2.global(11, "wl_subcompositor", 1) [2095686.715] -> wl_registry@2.bind(2, "wl_compositor", 3, new id [unknown]@4) [2095686.728] -> wl_registry@2.bind(11, "wl_subcompositor", 1, new id [unknown]@5) [2095686.746] -> wl_registry@2.bind(3, "wl_shm", 1, new id [unknown]@6) [2095686.758] -> wl_registry@2.bind(8, "zxdg_shell_v6", 1, new id [unknown]@7) [2095686.774] wl_registry@2.global(12, "zwp_pointer_gestures_v1", 1) [2095686.784] wl_registry@2.global(13, "zwp_tablet_manager_v2", 1) [2095686.792] wl_registry@2.global(14, "wl_seat", 5) [2095686.800] wl_registry@2.global(15, "zwp_relative_pointer_manager_v1", 1) [2095686.810] wl_registry@2.global(16, "zwp_pointer_constraints_v1", 1) [2095686.819] wl_registry@2.global(17, "zxdg_exporter_v1", 1) [2095686.826] wl_registry@2.global(18, "zxdg_importer_v1", 1) ``` In case it helps, Here is an annotated log from the moment I press the left mouse button and begin the attempt to resize from the right edge of the window with the mutter compositor: Press the resizable edge: ``` [814139.649] wl_pointer@21.button(20109, 10070859, 272, 1) [814139.727] -> wl_shell_surface@20.resize(wl_seat@10, 20109, 8) ``` Drag the resizable edge to the right, attempting to make it wider (window desn't actually resize): ``` [815561.237] wl_pointer@21.motion(10072280, 4.179688, 85.035156) [815578.364] wl_pointer@21.motion(10072295, 4.351562, 85.035156) [815593.633] wl_pointer@21.motion(10072311, 4.527344, 85.035156) [815610.814] wl_pointer@21.motion(10072326, 4.710938, 85.035156) [815627.786] wl_pointer@21.motion(10072342, 4.894531, 85.035156) [815644.873] wl_pointer@21.motion(10072357, 5.085938, 85.035156) [815660.386] wl_pointer@21.motion(10072372, 5.277344, 85.035156) [815680.182] wl_pointer@21.motion(10072395, 5.613281, 85.035156) [815695.733] wl_pointer@21.motion(10072411, 5.968750, 85.035156) [815712.571] wl_pointer@21.motion(10072426, 6.324219, 85.035156) [815728.408] wl_pointer@21.motion(10072441, 6.496094, 85.035156) [815746.070] wl_pointer@21.motion(10072464, 7.011719, 85.035156) [815761.964] wl_pointer@21.motion(10072480, 7.355469, 85.035156) [815780.930] wl_pointer@21.motion(10072488, 7.527344, 85.203125) [815796.711] wl_pointer@21.motion(10072511, 7.527344, 85.367188) [815870.186] wl_pointer@21.motion(10072587, 7.675781, 85.367188) [817066.688] wl_pointer@21.motion(10073786, 7.785156, 85.367188) [817765.569] wl_pointer@21.motion(10074484, 7.867188, 85.367188) [818236.053] wl_pointer@21.motion(10074953, 7.953125, 85.367188) ``` Release the mouse button: ``` [818401.878] wl_pointer@21.button(20110, 10075122, 272, 0) [818420.178] wl_pointer@21.leave(20111, wl_surface@13) [818420.266] -> wl_surface@23.attach(wl_buffer@34, 0, 0) [818420.282] -> wl_surface@23.damage(0, 0, 24, 24) [818420.290] -> wl_surface@23.commit() [818420.294] -> wl_pointer@21.set_cursor(20111, wl_surface@23, 4, 4) ``` Alt-tab back to the Terminal ``` [826417.962] wl_shell_surface@20.configure(0, 272, 152) [826418.011] -> wl_buffer@40.destroy() [826418.018] -> wl_buffer@41.destroy() [826418.022] -> wl_buffer@42.destroy() [826418.025] -> wl_buffer@43.destroy() [826434.931] -> wl_shm_pool@11.create_buffer(new id wl_buffer@46, 0, 272, 24, 1088, 0) [826435.139] -> wl_surface@12.attach(wl_buffer@46, 0, 0) [826435.171] -> wl_subsurface@16.set_position(-8, -24) [826435.185] -> wl_shm_pool@11.create_buffer(new id wl_buffer@47, 0, 8, 120, 32, 0) [826435.210] -> wl_surface@13.attach(wl_buffer@47, 0, 0) [826435.230] -> wl_subsurface@17.set_position(256, 0) [826435.245] -> wl_shm_pool@11.create_buffer(new id wl_buffer@48, 0, 272, 8, 1088, 0) [826435.278] -> wl_surface@14.attach(wl_buffer@48, 0, 0) [826435.288] -> wl_subsurface@18.set_position(-8, 120) [826435.294] -> wl_shm_pool@11.create_buffer(new id wl_buffer@49, 0, 8, 120, 32, 0) [826435.318] -> wl_surface@15.attach(wl_buffer@49, 0, 0) [826435.327] -> wl_subsurface@19.set_position(-8, 0) [826435.335] -> wl_surface@12.commit() [826435.339] -> wl_surface@13.commit() [826435.341] -> wl_surface@14.commit() [826435.343] -> wl_surface@15.commit() [826435.350] -> wl_buffer@44.destroy() [826435.356] -> wl_shm_pool@8.create_buffer(new id wl_buffer@50, 0, 256, 120, 1024, 0) [826435.373] -> wl_surface@3.attach(wl_buffer@50, 0, 0) [826435.382] -> wl_surface@3.commit() ``` Any advice on what might be going on here would be greatly appreciated! I'm running Arch Linux with gnome-shell 3.24.1 in the default wayland mode.
(I'm the maintainer of wayland-window, the project on which this bug occured.) It appears the issue is that the pointer grab associated with the serial was from a subsurface, while the resize/move request are sent on the parent surface. (the wayland-window crate uses subsurfaces to draw its decorations). Weston allows this, but apparently mutter refuses it, because the grab and the request are not associated with the same surface, if I'm correctly understanding the meta_wayland_pointer_can_grab_surface function.
It seems that the correct fix for this would be to have `meta_wayland_pointer_can_grab_surface` return `true` if either `pointer->focus_surface == surface` **or** if `pointer->focus_surface` is equal to any of the `surface`'s subsurfaces. Could any of the mutter devs comment on whether this sounds correct or not?
(In reply to mindtree from comment #2) > It seems that the correct fix for this would be to have > `meta_wayland_pointer_can_grab_surface` return `true` if either > `pointer->focus_surface == surface` **or** if `pointer->focus_surface` is > equal to any of the `surface`'s subsurfaces. Could any of the mutter devs > comment on whether this sounds correct or not? This sounds reasonable. Same would apply for touch too.
mindtree, are you working on a fix for this?
Jonas Ådahl, I had planned to however it looks like I won't have time at least for a couple weeks. I'm also not familiar with the gnome/mutter build system so it would likely take me a lot longer than somebody already familiar with mutter. If you (or anyone else) would like to go ahead and make the fix that would be greatly appreciated! I'd also be more than happy to help test the fix if necessary.
Has there been any progress on this issue? If not, does anyone have plans to address it?
(In reply to mindtree from comment #6) > Has there been any progress on this issue? If not, does anyone have plans to > address it? I don't know about others, but I haven't to it yet. If you want to work on this, please feel free to do so.
Hey Jonas, I had a go at getting this working but couldn't quite get a local build of mutter to run correctly. This is the final error that I ran into before running out of time: ``` (mutter:11472): Gdk-CRITICAL **: gdk_screen_get_setting: assertion 'GDK_IS_SCREEN (screen)' failed (mutter:11472): mutter-ERROR **: Failed to spawn Xwayland: Failed to execute child process “/home/mindtree/jhbuild/install/bin/Xwayland” (No such file or directory) Trace/breakpoint trap (core dumped) ``` The command used to try and run mutter is as follows ``` jhbuild run mutter --nested --wayland ``` I rebuilt mutter as you suggested on IRC after running `./configure` and passing the xwayland path argument as you suggested and it seemed to complete successfully, however the error above continued to occur when I tried running it again. It seems like I might not have time to get back to this for a while so please feel free to take this on. Would be much appreciated!
(In reply to mindtree from comment #8) > (mutter:11472): mutter-ERROR **: Failed to spawn Xwayland: Failed to execute > child process “/home/mindtree/jhbuild/install/bin/Xwayland” (No such file or > directory) > Trace/breakpoint trap (core dumped) This means you don't have Xwayland in your jhbuild prefix. Something like module_autogenargs['mutter']='--with-xwayland-path=/usr/bin/Xwayland' in ~/.config/jhbuildrc should get you past that error (after rebuilding mutter of course).
(In reply to Florian Müllner from comment #9) > (In reply to mindtree from comment #8) > > > (mutter:11472): mutter-ERROR **: Failed to spawn Xwayland: Failed to execute > > child process “/home/mindtree/jhbuild/install/bin/Xwayland” (No such file or > > directory) > > Trace/breakpoint trap (core dumped) > > This means you don't have Xwayland in your jhbuild prefix. Something like > > module_autogenargs['mutter']='--with-xwayland-path=/usr/bin/Xwayland' > > in ~/.config/jhbuildrc should get you past that error (after rebuilding > mutter of course). Thanks for your suggestion, it worked! I think I've successfully managed to build and run an instance of mutter using jhbuild. I've began implementing this, however I have some questions with regards to how `meta_wayland_pointer_can_grab_surface` should behave: 1. Can a subsurface of a `MetaWaylandSurface` also have its own subsurfaces? 2. If so, when checking subsurfaces, should only the immediate subsurfaces be checked? Or should the entire tree of subsurfaces (including subsurfaces of subsurfaces) be checked in some sort of traversal such as DFS or BFS? 3. If so, how should this be performed? Are there tree traversal utilities included within the repository somewhere? Should the traversal use the call stack via recursion? Or is there a gnome stack type that should be used? Any advice on this appreciated. As a side-note, is there somewhere suitable that I may offer a bounty for solving this issue in the case that I cannot manage to myself?
I decided to implement this conservatively for now so that only the immediate subsurfaces are checked (along with a note above the code explaining this). It works!!! I can now move and resize the window successfully after this patch :) Here is the diff for the patch: - return (pointer->grab_serial == serial && - pointer->focus_surface == surface); + if (pointer->grab_serial == serial) + { + if (pointer->focus_surface == surface) + return true; + + // Check if focus matches any of the subsurfaces. + // NOTE: This only checks the immediate subsurfaces. + // Should we be checking the whole tree using some sort of traversal? + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) + { + MetaWaylandSurface *subsurface = l->data; + if (pointer->focus_surface == subsurface) + return true; + } + } + + return false; Does this look OK? If so, how may I go about submitting a pull request? Any advice appreciated!
For the record, the wayland documentation of the wl_subcompositor: > The root surface in a tree of sub-surfaces is the main > surface. The main surface cannot be a sub-surface, because > sub-surfaces must always have a parent. > > A main surface with its sub-surfaces forms a (compound) window. > For window management purposes, this set of wl_surface objects is > to be considered as a single window, and it should also behave as > such. My understanding here is that the whole tree of subsurfaces is tha "compound window", and as such the logic would require traversal of the entire subsurface tree.
(In reply to mindtree from comment #11) > I decided to implement this conservatively for now so that only the > immediate subsurfaces are checked (along with a note above the code > explaining this). > > It works!!! I can now move and resize the window successfully after this > patch :) > > Here is the diff for the patch: > > > - return (pointer->grab_serial == serial && > - pointer->focus_surface == surface); > + if (pointer->grab_serial == serial) > + { > + if (pointer->focus_surface == surface) > + return true; > + > + // Check if focus matches any of the subsurfaces. > + // NOTE: This only checks the immediate subsurfaces. > + // Should we be checking the whole tree using some sort of traversal? > + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) > + { > + MetaWaylandSurface *subsurface = l->data; > + if (pointer->focus_surface == subsurface) > + return true; > + } > + } > + > + return false; > > > Does this look OK? If so, how may I go about submitting a pull request? Any > advice appreciated! In general yes, though I suggest calling can_grab() recursively on all subsurfaces. That'll also make the code self explanatory, thus no need for any comments. In short, it could for example be something similar to "can_grab(..) { if (pointer->grab_serial != serial) return FALSE; if (pointer->focus_surface == surface) return TRUE; forall (subsurfaces) { if (can_grab(subsurface)) return TRUE; } return FALSE; }" When you have a commit on your local git clone, you can use "git-bz" to upload it as a patch to this bug. Then I can do a real code review. We don't support pull requests anywhere yet. If you want, you can implement the equivalent thing for touch, but I guess that'd require you to have a touch device. Thanks for working on this! (In reply to Levans from comment #12) > For the record, the wayland documentation of the wl_subcompositor: > > > The root surface in a tree of sub-surfaces is the main > > surface. The main surface cannot be a sub-surface, because > > sub-surfaces must always have a parent. > > > > A main surface with its sub-surfaces forms a (compound) window. > > For window management purposes, this set of wl_surface objects is > > to be considered as a single window, and it should also behave as > > such. > > My understanding here is that the whole tree of subsurfaces is tha "compound > window", and as such the logic would require traversal of the entire > subsurface tree. Indeed.
Created attachment 353046 [details] [review] Fix meta_wayland_pointer_can_grab_surface - Bug #781811. Previously, the function only returned `true` if the given surface was equal to the given pointer's focused surface. This changes the behaviour to also return `true` if any of the given surface's subsurfaces are equal to the pointer's focused surface.
Review of attachment 353046 [details] [review]: Looks good, I just have coding style nits. The commit message needs fixing though. To be conformant, it should be something like: wayland/pointer: Handle subsurfaces when grabbing Previously, the function only returned `true` if the given surface was equal to the given pointer's focused surface. This changes the behaviour to also return `true` if any of the given surface's subsurfaces are equal to the pointer's focused surface. https://bugzilla.gnome.org/show_bug.cgi?id=781811. But feel free to come up with a better subject. ::: src/wayland/meta-wayland-pointer.c @@ +1124,3 @@ +{ + if (pointer->focus_surface == surface) + return true; TRUE @@ +1126,3 @@ + return true; + + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) Variable declarations on top. "l != NULL" is usually written as just "l" in these types of loops but doesn't matter. @@ +1128,3 @@ + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) + { + MetaWaylandSurface *subsurface = l->data; Empty line after declarations. @@ +1129,3 @@ + { + MetaWaylandSurface *subsurface = l->data; + if (pointer_can_grab_surface(pointer, subsurface)) Space between function name and ( @@ +1130,3 @@ + MetaWaylandSurface *subsurface = l->data; + if (pointer_can_grab_surface(pointer, subsurface)) + return true; TRUE @@ +1133,3 @@ + } + + return false; FALSE
Created attachment 353047 [details] [review] wayland/pointer: Check for subsurfaces when grabbing Previously, the function only returned `TRUE` if the given surface was equal to the given pointer's focused surface. This changes the behaviour to also return `TRUE` if any of the given surface's subsurfaces are equal to the pointer's focused surface. https://bugzilla.gnome.org/show_bug.cgi?id=781811.
(In reply to Jonas Ådahl from comment #15) > Review of attachment 353046 [details] [review] [review]: > > Looks good, I just have coding style nits. > > The commit message needs fixing though. To be conformant, it should be > something like: > > wayland/pointer: Handle subsurfaces when grabbing > > Previously, the function only returned `true` if the given surface was > equal to the given pointer's focused surface. This changes the behaviour > to also return `true` if any of the given surface's subsurfaces are > equal to the pointer's focused surface. > > https://bugzilla.gnome.org/show_bug.cgi?id=781811. > > > But feel free to come up with a better subject. > > ::: src/wayland/meta-wayland-pointer.c > @@ +1124,3 @@ > +{ > + if (pointer->focus_surface == surface) > + return true; > > TRUE > > @@ +1126,3 @@ > + return true; > + > + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) > > Variable declarations on top. "l != NULL" is usually written as just "l" in > these types of loops but doesn't matter. > > @@ +1128,3 @@ > + for (GList *l = surface->subsurfaces; l != NULL; l = l->next) > + { > + MetaWaylandSurface *subsurface = l->data; > > Empty line after declarations. > > @@ +1129,3 @@ > + { > + MetaWaylandSurface *subsurface = l->data; > + if (pointer_can_grab_surface(pointer, subsurface)) > > Space between function name and ( > > @@ +1130,3 @@ > + MetaWaylandSurface *subsurface = l->data; > + if (pointer_can_grab_surface(pointer, subsurface)) > + return true; > > TRUE > > @@ +1133,3 @@ > + } > + > + return false; > > FALSE Just wanted to say thanks for the feedback - it has been a long time since I've written C! I have attached a new patch including all of your suggested amendments.
Review of attachment 353047 [details] [review]: looks goot to me, thanks!
No problem! Could you possibly give me an indication of how long I can expect to wait for this to land in stable? I'm particularly curious about how long these sorts of changes take to land in the arch repos. Thanks!
I'll go a head and land it in the 3.24 branch and master, so it'll be part of the next release.
Pushed to to gnome-3-24 and master. I noticed you had put a "." after the bugzilla link. That caused git-bz to fail to understand what bug the patch was associated with. So next time, just the link on its own line, without any punctuation, or just use git-bz to do it all automatically. I fixed the link on the gnome-3-24 branch, but on master I discovered it too late, so it'll still have the ".". Attachment 353047 [details] pushed as e22c753 - wayland/pointer: Check for subsurfaces when grabbing