weird behavior of transient windows in desktop shell in weston

Barry Song 21cnbao at gmail.com
Thu Apr 25 21:53:36 UTC 2019


ping

Barry Song <21cnbao at gmail.com> 于2019年4月17日周三 下午10:19写道:
>
> Hi guys,
>
> I got some very weird result while using transient window in weston.
> Let's start from a simplest qt program:
>
> int main(int argc, char *argv[])
> {
>     QApplication a(argc, argv);
>     MainWindow w;
>     w.show();
>
>     QDialog d1(&w)
>     d1.setWindowTitle("transient& non toplevel dialog d1");
>     d1.show();
>
>     return a.exec();
> }
> Under x11 or mutter wayland compositor, D1 transient window will
> always be on the top of Mainwindow W. But under weston desktop shell,
> if we click mainwindow, d1 will be covered by mainwindow W.
>
> I tried to read source code to figure out why and found weston will
> only think WL_SHELL_SURFACE_TRANSIENT_INACTIVE transient windows as
> "TRANSIENT", otherwise it will think it as "TOPLEVEL" window.
> code path: libweston-desktop/wl-shell.c
>
> static void
> weston_desktop_wl_shell_surface_protocol_set_transient(struct
> wl_client *wl_client,
>                                                        struct
> wl_resource *resource,
>                                                        struct
> wl_resource *parent_resource,
>                                                        int32_t x, int32_t y,
>                                                        enum
> wl_shell_surface_transient flags)
> {
>         struct weston_desktop_surface *dsurface =
>                 wl_resource_get_user_data(resource);
>         struct weston_surface *wparent =
>                 wl_resource_get_user_data(parent_resource);
>         struct weston_desktop_surface *parent;
>         struct weston_desktop_wl_shell_surface *surface =
>                 weston_desktop_surface_get_implementation_data(dsurface);
>
>         if (!weston_surface_is_desktop_surface(wparent))
>                 return;
>
>         parent = weston_surface_get_desktop_surface(wparent);
>         if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
>                 weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
>                                                      x, y);
>         } else {
>                 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
>                                                      0, 0);
>                 surface->parent = parent;
>                 weston_desktop_api_set_parent(surface->desktop,
>                                               surface->surface, parent);
>         }
> }
>
> Actually WL_SHELL_SURFACE_TRANSIENT_INACTIVE is pretty difficult to be
> true unless we put Qt::WindowTransparentForInput or Qt::ToolTip for a
> qt window.
>
> On the other hand, mutter doesn't check this flag at all:
>
> code path: mutter/src/wayland/meta-wayland-wl-shell.c
> static void
> wl_shell_surface_set_transient (struct wl_client   *client,
>                                 struct wl_resource *resource,
>                                 struct wl_resource *parent_resource,
>                                 int32_t             x,
>                                 int32_t             y,
>                                 uint32_t            flags)
> {
>   MetaWaylandWlShellSurface *wl_shell_surface =
>     META_WAYLAND_WL_SHELL_SURFACE (wl_resource_get_user_data (resource));
>   MetaWaylandSurface *surface =
>     surface_from_wl_shell_surface_resource (resource);
>   MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
>
>   wl_shell_surface_set_state (surface,
>                               META_WL_SHELL_SURFACE_STATE_TRANSIENT);
>
>   set_wl_shell_surface_parent (surface, parent_surf);
>   wl_shell_surface->x = x;
>   wl_shell_surface->y = y;
>
>   if (surface->window && parent_surf->window)
>     sync_wl_shell_parent_relationship (surface, parent_surf);
> }
>
> I seem mutter is doing right things just like a typical x11 window manager.
>
> On the other hand, the code path of
> WL_SHELL_SURFACE_TRANSIENT_INACTIVE can easily crash as I have sent
> the patch yesterday:
> commit e87c23ffcf3dc209cb8e7f24c3087636b8db3f53 (HEAD -> 6.0)
> Author: Barry Song <barry.song at navico.com>
> Date:   Mon Apr 15 11:28:07 2019 +1200
>
>     desktop-shell: fix the crash while clicking TRANSIENT_INACTIVE window
>
>     It is pretty easy to replicate this bug by involving a Qt Window with
>     Qt::WindowTransparentForInput flag.
>
>     int main(int argc, char *argv[])
>     {
>         QApplication a(argc, argv);
>         MainWindow w;
>         w.show();
>
>         QDialog d1(&w, Qt::WindowTransparentForInput);
>         d1.show();
>
>         return a.exec();
>     }
>
>     Click d1 dialog, weston will crash.
>
>     Signed-off-by: Barry Song <barry.song at navico.com>
>
> diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
> index 93b1c70b..9473bac1 100644
> --- a/desktop-shell/shell.c
> +++ b/desktop-shell/shell.c
> @@ -2697,11 +2697,16 @@ desktop_surface_move(struct
> weston_desktop_surface *desktop_surface,
>         struct weston_touch *touch = weston_seat_get_touch(seat);
>         struct shell_surface *shsurf =
>                 weston_desktop_surface_get_user_data(desktop_surface);
> -       struct weston_surface *surface =
> -               weston_desktop_surface_get_surface(shsurf->desktop_surface);
> -       struct wl_resource *resource = surface->resource;
> +       struct weston_surface *surface;
> +       struct wl_resource *resource;
>         struct weston_surface *focus;
>
> +       if (!shsurf)
> +               return;
> +
> +       surface = weston_desktop_surface_get_surface(shsurf->desktop_surface);
> +       resource = surface->resource;
> +
>         if (pointer &&
>             pointer->focus &&
>             pointer->button_count > 0 &&
>
> I am also trying to figure out a possible way to make weston do same
> work as mutter, and a possible way is adding set_parent() callback and
> maintaining the relationship of so-called "TOPLEVEL" transient windows
> in set_parent():
> diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
> index 9473bac1..9b4cf46c 100644
> --- a/desktop-shell/shell.c
> +++ b/desktop-shell/shell.c
> @@ -2689,6 +2689,13 @@ set_fullscreen(struct shell_surface *shsurf,
> bool fullscreen,
>         weston_desktop_surface_set_size(desktop_surface, width, height);
>  }
>
> +static void
> +desktop_surface_set_parent(struct weston_desktop_surface *surface,
> +                            struct weston_desktop_surface *parent,
> +                            void *user_data)
> +{
> +}
> +
>  static void
>  desktop_surface_move(struct weston_desktop_surface *desktop_surface,
>                      struct weston_seat *seat, uint32_t serial, void *shell)
> @@ -2933,6 +2940,7 @@ static const struct weston_desktop_api
> shell_desktop_api = {
>         .surface_removed = desktop_surface_removed,
>         .committed = desktop_surface_committed,
>         .move = desktop_surface_move,
> +       .set_parent = desktop_surface_set_parent,
>         .resize = desktop_surface_resize,
>         .fullscreen_requested = desktop_surface_fullscreen_requested,
>         .maximized_requested = desktop_surface_maximized_requested,
> @@ -3817,7 +3825,7 @@ activate(struct desktop_shell *shell, struct
> weston_view *view,
>
> I'd like to get some comment from weston maintainers. Is looking
> transient window as toplevel window the expected behavior in weston?
> Or it is better to maintain the layer relationship of transient window
> just like a typical X11 window manager?
>
> Thanks
> Barry


More information about the wayland-devel mailing list