<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Feb 26, 2015 at 12:48 AM, Jonas Ådahl <span dir="ltr"><<a href="mailto:jadahl@gmail.com" target="_blank">jadahl@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Feb 26, 2015 at 09:59:21AM +0200, Pekka Paalanen wrote:<br>
> On Fri, 13 Feb 2015 14:01:58 +0800<br>
> Jonas Ådahl <<a href="mailto:jadahl@gmail.com">jadahl@gmail.com</a>> wrote:<br>
><br>
> > From: "Jasper St. Pierre" <<a href="mailto:jstpierre@mecheye.net">jstpierre@mecheye.net</a>><br>
> ><br>
> > Either in destroy or get_xdg_popup.<br>
> ><br>
> > [jadahl: Verify that the new popup is the top most when mapping instead<br>
> > of creating. Some renaming.]<br>
> > ---<br>
> >  desktop-shell/shell.c  | 58 +++++++++++++++++++++++++++++++++++++++++++++-----<br>
> >  protocol/xdg-shell.xml |  7 ++++++<br>
> >  2 files changed, 60 insertions(+), 5 deletions(-)<br>
> ><br>
> > diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c<br>
> > index 4990c4d..6697222 100644<br>
> > --- a/desktop-shell/shell.c<br>
> > +++ b/desktop-shell/shell.c<br>
> > @@ -3370,12 +3370,40 @@ touch_popup_grab_end(struct weston_touch *touch)<br>
> >     }<br>
> >  }<br>
> ><br>
> > -static void<br>
> > +static struct shell_surface *<br>
> > +get_top_xdg_popup(struct shell_seat *shseat)<br>
> > +{<br>
> > +   struct shell_surface *shsurf;<br>
> > +<br>
> > +   if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {<br>
> > +           return NULL;<br>
> > +   } else {<br>
> > +           shsurf = container_of(shseat->popup_grab.surfaces_list.next,<br>
> > +                                 struct shell_surface,<br>
> > +                                 popup.grab_link);<br>
> > +           assert(shell_surface_is_xdg_popup(shsurf));<br>
><br>
> Hi,<br>
><br>
> are you sure this assert() does not trigger when a client is using<br>
> wl_shell popups?<br>
><br>
> It looks like if a client tried to open a wl_shell popup while one is<br>
> already open, this would explode.<br>
><br>
> map() -> shell_map_popup() -> add_popup_grab() -> get_top_xdg_popup()<br>
><br>
> Am I missing something?<br>
<br>
</div></div>No you are right. If a client mixes both wl_shell and xdg_shell, we'd be<br>
in trouble.<span class=""><br></span></blockquote><div><br></div><div>If a client simply maps two wl_shell popups, then we're also in trouble, since get_top_xdg_popup is called unconditionally by add_popup_grab, which is also called from set_popup.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
><br>
> Maybe the fix is as simple as just checking for both wl_shell and<br>
> xdg_shell popup types and accepting either?<br>
<br>
</span>No, we also need to move the top most verification inside a if<br>
(is_xdg_popup) block, so we don't put unintended restrictions on<br>
wl_shell popups.<br>
<br>
I'll send a v2 that renames back the getter to get_top_popup, removes<br>
the assert and puts the verification in add_popup_grab() inside an if.<br>
<span class="HOEnZb"><font color="#888888"><br>
<br>
Jonas<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
><br>
> Wonder if we have any wl_shell apps that would do sub-menus...<br>
><br>
> > +           return shsurf;<br>
> > +   }<br>
> > +}<br>
> > +<br>
> > +static int<br>
> >  add_popup_grab(struct shell_surface *shsurf,<br>
> >            struct shell_seat *shseat,<br>
> >            int32_t type)<br>
> >  {<br>
> >     struct weston_seat *seat = shseat->seat;<br>
> > +   struct shell_surface *parent, *top_surface;<br>
> > +<br>
> > +   parent = get_shell_surface(shsurf->parent);<br>
> > +   top_surface = get_top_xdg_popup(shseat);<br>
> > +   if ((top_surface == NULL && !shell_surface_is_xdg_surface(parent)) ||<br>
> > +       (top_surface != NULL && parent != top_surface)) {<br>
> > +           wl_resource_post_error(shsurf->owner->resource,<br>
> > +                                  XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,<br>
> > +                                  "xdg_popup was not created on the "<br>
> > +                                  "topmost popup");<br>
> > +           return -1;<br>
> > +   }<br>
> ><br>
> >     if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {<br>
> >             shseat->popup_grab.type = type;<br>
> > @@ -3410,6 +3438,8 @@ add_popup_grab(struct shell_surface *shsurf,<br>
> >             wl_list_insert(&shseat->popup_grab.surfaces_list,<br>
> >                            &shsurf->popup.grab_link);<br>
> >     }<br>
> > +<br>
> > +   return 0;<br>
> >  }<br>
> ><br>
> >  static void<br>
> > @@ -3417,6 +3447,15 @@ remove_popup_grab(struct shell_surface *shsurf)<br>
> >  {<br>
> >     struct shell_seat *shseat = shsurf->popup.shseat;<br>
> ><br>
> > +   if (shell_surface_is_xdg_popup(shsurf) &&<br>
> > +       get_top_xdg_popup(shseat) != shsurf) {<br>
> > +           wl_resource_post_error(shsurf->resource,<br>
> > +                                  XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,<br>
> > +                                  "xdg_popup was destroyed while it was "<br>
> > +                                  "not the topmost popup.");<br>
><br>
> Hmm, I'm confused. What does "top-most popup" mean?<br>
><br>
> If there is a chain of popups because of sub-menus:<br>
><br>
> surface -> popup A -> popup B<br>
><br>
> Then which popup is the top-most? The root of the popup hierarchy or<br>
> the most recently created popup?<br>
><br>
> It seems add_popup_grab() pushes the new popup to the head of the<br>
> popup_grab.surfaces_list, so top-most means the most recently mapped<br>
> popup, right? So that's popup B in the example.<br></div></div></blockquote><div><br></div><div>"Topmost" means the one that's on top of all the others, so, popup B. If you have a better word, feel free to say so! It was the best I could think of.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> You can ignore this question if the documentation rewrite explains<br>
> "top-most".<br>
><br>
> > +           return;<br>
> > +   }<br>
> > +<br>
> >     wl_list_remove(&shsurf->popup.grab_link);<br>
> >     wl_list_init(&shsurf->popup.grab_link);<br>
> >     if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {<br>
> > @@ -3430,7 +3469,7 @@ remove_popup_grab(struct shell_surface *shsurf)<br>
> >     }<br>
> >  }<br>
> ><br>
> > -static void<br>
> > +static int<br>
> >  shell_map_popup(struct shell_surface *shsurf)<br>
> >  {<br>
> >     struct shell_seat *shseat = shsurf->popup.shseat;<br>
> > @@ -3445,14 +3484,18 @@ shell_map_popup(struct shell_surface *shsurf)<br>
> ><br>
> >     if (shseat->seat->pointer &&<br>
> >         shseat->seat->pointer->grab_serial == shsurf->popup.serial) {<br>
> > -           add_popup_grab(shsurf, shseat, POINTER);<br>
> > +           if (add_popup_grab(shsurf, shseat, POINTER) != 0)<br>
> > +                   return -1;<br>
> >     } else if (shseat->seat->touch &&<br>
> >                shseat->seat->touch->grab_serial == shsurf->popup.serial) {<br>
> > -           add_popup_grab(shsurf, shseat, TOUCH);<br>
> > +           if (add_popup_grab(shsurf, shseat, TOUCH) != 0)<br>
> > +                   return -1;<br>
> >     } else {<br>
> >             shell_surface_send_popup_done(shsurf);<br>
> >             shseat->popup_grab.client = NULL;<br>
> >     }<br>
> > +<br>
> > +   return 0;<br>
> >  }<br>
> ><br>
> >  static const struct wl_shell_surface_interface shell_surface_implementation = {<br>
> > @@ -4051,6 +4094,10 @@ create_xdg_popup(struct shell_client *owner, void *shell,<br>
> >  {<br>
> >     struct shell_surface *shsurf;<br>
> ><br>
> > +   /* Verify that we are creating the top most popup when mapping,<br>
> > +    * as its not until then we know whether it was mapped as most<br>
> > +    * top level or not. */<br>
><br>
> Ok!<br>
><br>
> > +<br>
> >     shsurf = create_common_surface(owner, shell, surface, client);<br>
> >     if (!shsurf)<br>
> >             return NULL;<br>
> > @@ -5451,7 +5498,8 @@ map(struct desktop_shell *shell, struct shell_surface *shsurf,<br>
> >             }<br>
> >             break;<br>
> >     case SHELL_SURFACE_POPUP:<br>
> > -           shell_map_popup(shsurf);<br>
> > +           if (shell_map_popup(shsurf) != 0)<br>
> > +                   return;<br>
> >             break;<br>
> >     case SHELL_SURFACE_NONE:<br>
> >             weston_view_set_position(shsurf->view,<br>
> > diff --git a/protocol/xdg-shell.xml b/protocol/xdg-shell.xml<br>
> > index 4414d46..360179d 100644<br>
> > --- a/protocol/xdg-shell.xml<br>
> > +++ b/protocol/xdg-shell.xml<br>
> > @@ -398,6 +398,13 @@<br>
> >        xdg_popup surfaces are always transient for another surface.<br>
> >      </description><br>
> ><br>
> > +    <enum name="error"><br>
> > +      <description summary="xdg_popup error values"><br>
> > +   These errors can be emitted in response to xdg_popup requests.<br>
> > +      </description><br>
> > +      <entry name="not_the_topmost_popup" value="0" summary="The client tried to destroy a non-toplevel popup"/><br>
><br>
> What is a toplevel popup? Did you mean top-most?<br></div></div></blockquote><div><br></div><div>Whoops. The "not_the_topmost" should probably clue you in that, yes, I did :)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> > +    </enum><br>
> > +<br>
> >      <request name="destroy" type="destructor"><br>
> >        <description summary="remove xdg_surface interface"><br>
> >     The xdg_surface interface is removed from the wl_surface object<br>
><br>
> Otherwise looks good to me.<br>
><br>
><br>
> Thanks,<br>
> pq<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature">  Jasper<br></div>
</div></div>