[PATCH wayland-protocols v4 7/7] xdg-shell: Introduce xdg_positioner

Jonas Ådahl jadahl at gmail.com
Fri Jul 22 06:55:22 UTC 2016


On Wed, Jul 20, 2016 at 10:06:00AM -0700, Yong Bakos wrote:
> Jonas,
> My R'b for 1-6 of v4 stand.
> 
> I think I finally grok xdg_positioner, and this seems straightforward.
> I would like to understand Bill's 'list of rectangles' approach,
> mentioned off-list, but from what I can tell it doesn't jive with
> current best practices. I mention this because I'm always open to
> 'better' ways of handling positioning, if there's an opportunity to do
> something better.

I tried shortly to make sense of it, but gave up when I couldn't figure
out how to describe the most basic (just move me any in any direction
until I'm inside the screen) case. It definitely doesn't seem like a
"simple" solution anyhow (except if you define "simple" to "number of
requests"), and I doubt there is any proof-of-concept implementation of
it either.

> 
> I /think/ this can be landed as-is, especially since we've got a branch
> for this, but I have some comments inline below before I R'b.
> 
> 
> > On Jun 23, 2016, at 11:47 PM, Jonas Ådahl <jadahl at gmail.com> wrote:
> > 
> > xdg_positioner is a method for declarative positioning of child surfaces
> > (currently only xdg_popup surfaces). A client creates a description of a
> > positioning logic using the xdg_positioner interface. The xdg_positioner
> > object is then used when creating a xdg_popup for describing how the
> > child surface should be positioned in relation to the parent surface.
> > 
> > Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> > Signed-off-by: Mike Blumenkrantz <zmike at samsung.com>
> > Acked-by: Yong Bakos <ybakos at humanoriented.com>
> > ---
> > 
> > Changes since v3:
> > 
> > - Allow combining slide_x/y and flip_x/y enums, while explaining the order of
> >   adjustments.
> > - Reworded the non-immediate effect of the configure event (the same as
> >   xdg-surface generic split update)
> > 
> > 
> > unstable/xdg-shell/xdg-shell-unstable-v6.xml | 266 ++++++++++++++++++++++++++-
> > 1 file changed, 263 insertions(+), 3 deletions(-)
> > 
> > diff --git a/unstable/xdg-shell/xdg-shell-unstable-v6.xml b/unstable/xdg-shell/xdg-shell-unstable-v6.xml
> > index 4c5dab4..7fab656 100644
> > --- a/unstable/xdg-shell/xdg-shell-unstable-v6.xml
> > +++ b/unstable/xdg-shell/xdg-shell-unstable-v6.xml
> > @@ -45,6 +45,8 @@
> > 	     summary="the client specified an invalid popup parent surface"/>
> >       <entry name="invalid_surface_state" value="4"
> > 	     summary="the client provided an invalid surface state"/>
> > +      <entry name="invalid_positioner" value="5"
> > +	     summary="the client provided an invalid positioner"/>
> >     </enum>
> > 
> >     <request name="destroy" type="destructor">
> > @@ -57,6 +59,15 @@
> >       </description>
> >     </request>
> > 
> > +    <request name="create_positioner">
> > +      <description summary="create a positioner object">
> > +	Create a positioner object. A positioner object is used to position
> > +	surfaces relative to some parent surface. See the interface description
> > +	and xdg_surface.get_popup for details.
> > +      </description>
> > +      <arg name="id" type="new_id" interface="zxdg_positioner_v6"/>
> > +    </request>
> > +
> >     <request name="get_xdg_surface">
> >       <description summary="create a shell surface from a surface">
> > 	This creates an xdg_surface for the given surface. While xdg_surface
> > @@ -101,6 +112,240 @@
> >     </event>
> >   </interface>
> > 
> > +  <interface name="zxdg_positioner_v6" version="1">
> > +    <description summary="child surface positioner">
> > +      The xdg_positioner provides an interface for constructing positioning
> > +      rules used for positioning a child surface relative to a parent surface
> > +      in a certain way. It allows methods for defining a rule that will make
> > +      the child surface stay within the border of the visible area of the
> > +      screen, with different ways in which the child surface should change
> > +      its position, including sliding along an axis, or flipping around a
> > +      rectangle.
> > +
> > +      See the various requests for details about possible rules.
> > +
> > +      Semantically, an xdg_positioner is a collection of positioning rules. When
> > +      used for positioning a surface, for example when passed as an argument to
> > +      xdg_surface.get_popup, the compositor copies the rules that were set up at
> > +      the time of the request. Making any changes or destroying the object after
> > +      it was used has no effect on previous usages.
> > +
> > +      For an xdg_positioner object to be considered complete, it must have a
> > +      non-zero size set by set_size, and a non-zero anchor rectangle set by
> > +      set_anchor_rect. Passing an incomplete xdg_positioner object when
> > +      positioning a surface raises an error.
> > +    </description>
> > +
> > +    <enum name="error">
> > +      <entry name="invalid_input" value="0" summary="invalid input provided"/>
> > +    </enum>
> > +
> > +    <request name="destroy" type="destructor">
> > +      <description summary="destroy the xdg_positioner object">
> > +	Notify the compositor that the xdg_positioner will no longer be used.
> > +      </description>
> > +    </request>
> > +
> > +    <request name="set_size">
> > +      <description summary="set the size of the to-be positioned rectangle">
> > +	Set the size of the surface that is to be positioned with the positioner
> > +	object. The size is in surface-local coordinates and corresponds to the
> > +	window geometry. See xdg_surface.set_window_geometry.
> > +
> > +	If a zero or negative size is set the invalid_input error is raised.
> > +      </description>
> > +      <arg name="width" type="int" summary="width of positioned rectangle"/>
> > +      <arg name="height" type="int" summary="height of positioned rectangle"/>
> > +    </request>
> > +
> > +    <request name="set_anchor_rect">
> > +      <description summary="set the anchor rectangle within the parent surface">
> > +	Specify the anchor rectangle within the parent surface that the child
> > +	surface will be placed relative to. The rectangle is relative to the
> > +	window geometry as defined by xdg_surface.set_window_geometry of the
> > +	parent surface. The rectangle must be at least 1x1 large.
> > +
> > +	When the xdg_positioner object is used to position a child surface, the
> > +	anchor rectangle may not extend outside the window geometry of the
> > +	positioned child's parent surface.
> > +
> > +	If a zero or negative size is set the invalid_input error is raised.
> > +      </description>
> > +      <arg name="x" type="int" summary="x position of anchor rectangle"/>
> > +      <arg name="y" type="int" summary="y position of anchor rectangle"/>
> > +      <arg name="width" type="int" summary="width of anchor rectangle"/>
> > +      <arg name="height" type="int" summary="height of anchor rectangle"/>
> > +    </request>
> > +
> > +    <enum name="anchor" bitfield="true">
> > +      <entry name="none" value="0"
> > +	     summary="the center of the anchor rectangle"/>
> > +      <entry name="top" value="1"
> > +	     summary="the top edge of the anchor rectangle"/>
> > +      <entry name="bottom" value="2"
> > +	     summary="the bottom edge of the anchor rectangle"/>
> > +      <entry name="left" value="4"
> > +	     summary="the left edge of the anchor rectangle"/>
> > +      <entry name="right" value="8"
> > +	     summary="the right edge of the anchor rectangle"/>
> > +    </enum>
> > +
> > +    <request name="set_anchor">
> > +      <description summary="set anchor rectangle anchor edges">
> > +	Set the anchor edges of the anchor rectangle. The anchor edges define
> > +	where on the anchor rectangle the child surface should be positioned
> > +	relative to. An anchor is a bit mask of up to two values of the anchor
> > +	enum.
> > +
> > +	If two values on the same axis (for example left and right) are set the
> > +	invalid_input error is raised.
> > +
> > +	If no anchor is set on any axis, the anchor position will be positioned
> > +	at the center of the anchor rectangle on the unset axis. The default
> > +	value is "none".
> > +      </description>
> > +      <arg name="anchor" type="uint" enum="anchor"
> > +	   summary="bit mask of anchor edges"/>
> > +    </request>
> > +
> > +    <enum name="gravity" bitfield="true">
> > +      <entry name="none" value="0"
> > +	     summary="center over the anchor edge"/>
> > +      <entry name="top" value="1"
> > +	     summary="position above the anchor edge"/>
> > +      <entry name="bottom" value="2"
> > +	     summary="position below the anchor edge"/>
> > +      <entry name="left" value="4"
> > +	     summary="position to the left of the anchor edge"/>
> > +      <entry name="right" value="8"
> > +	     summary="position to the right of the anchor edge"/>
> > +    </enum>
> > +
> > +    <request name="set_gravity">
> > +      <description summary="set child surface gravity">
> > +	The gravity defines in what direction a surface would be positioned,
> > +	relative to the anchor edges on the parent surface. A gravity is a
> > +	bit mask of up to two values of the gravity enum.
> > +
> > +	If two values on the same axis (for example left and right) are set the
> > +	invalid_input error is raised.
> > +
> > +	If no gravity is set on an axis, the gravity for that axis will be
> > +	equivalent to setting "none" for that axis, resulting in the child being
> > +	centered over the anchor edges on that axis.
> > +      </description>
> > +      <arg name="gravity" type="uint" enum="gravity"
> > +	   summary="bit mask of gravity directions"/>
> > +    </request>
> 
> Should there be some error cases mentioned here in the protocol when
> the anchor rectangle specifies edges incompatible with gravity? For example,
> if the anchor is only 'top edge' and gravity is 'left', would gravity just
> get ignored or should it raise an error? I'm thinking the former. Regardless,
> should the protocol specify something about this?

Gravity can be set no matter the anchor rect's anchor edges, since it
isn't really edges but points. The 'none' anchor is in the center, and
if only an anchor on the x axis is specified, then the y anchor remains
in the center on the y axis.

I realize the text is a bit confusing since I talk about both edges and
points, but the meaning is you specify an edge, which moves the point.
If you specify two edges, then the point is in a corner; if you specify
only one edge, the point is on the center of that edge. If you specify
no edges, the point remains centered.

The same concept applies to the gravity.

> 
> (Something like this could be added after these patches are landed.)
> 
> One more thing, below...
> 
> > +
> > +    <enum name="constrain_adjustment" bitfield="true">
> > +      <entry name="none" value="0">
> > +	<description summary="don't move the child surface when constrained">
> > +	  Don't alter the surface position even if it is constrained on some
> > +	  axis, for example partially outside the edge of a monitor.
> > +	</description>
> > +      </entry>
> > +      <entry name="slide_x" value="1">
> > +	<description summary="move along the x axis until unconstrained">
> > +	  Slide the surface along the x axis until it is no longer constrained.
> > +
> > +	  First try to slide towards the direction of the gravity on the x axis
> > +	  until either the edge in the opposite direction of the gravity is
> > +	  unconstrained or the edge in the direction of the gravity is
> > +	  constrained.
> > +
> > +	  Then try to slide towards the opposite direction of the gravity on the
> > +	  x axis until either the edge in the direction of the gravity is
> > +	  unconstrained or the edge in the opposite direction of the gravity is
> > +	  constrained.
> > +
> > +	  If 'slide_x' is combined with 'flip_x', 'flip_x' takes precedence.
> > +	</description>
> > +      </entry>
> > +      <entry name="slide_y" value="2">
> > +	<description summary="move along the y axis until unconstrained">
> > +	  Slide the surface along the y axis until it is no longer constrained.
> > +
> > +	  First try to slide towards the direction of the gravity on the y axis
> > +	  until either the edge in the opposite direction of the gravity is
> > +	  unconstrained or the edge in the direction of the gravity is
> > +	  constrained.
> > +
> > +	  Then try to slide towards the opposite direction of the gravity on the
> > +	  y axis until either the edge in the direction of the gravity is
> > +	  unconstrained or the edge in the opposite direction of the gravity is
> > +	  constrained.
> > +
> > +	  If 'slide_y' is combined with 'flip_y', 'flip_y' takes precedence.
> > +	</description>
> > +      </entry>
> > +      <entry name="flip_x" value="4">
> > +	<description summary="invert the anchor and gravity on the x axis">
> > +	  Invert the anchor and gravity on the x axis if the surface is
> > +	  constrained on the x axis. For example, if the left edge of the
> > +	  surface is constrained, the gravity is 'left' and the anchor is
> > +	  'left', change the gravity to 'right' and the anchor to 'right'.
> > +
> > +	  If the adjusted position also ends up being constrained, the resulting
> > +	  position will be the one before the adjustment. If the resulting
> > +	  position is still constrained, and 'flip_x' is combined with
> > +	  'slide_x', the position is adjusted according to 'slide_x'.
> > +	</description>
> > +      </entry>
> > +      <entry name="flip_y" value="8">
> > +	<description summary="invert the anchor and gravity on the y axis">
> > +	  Invert the anchor and gravity on the y axis if the surface is
> > +	  constrained on the y axis. For example, if the bottom edge of the
> > +	  surface is constrained, the gravity is 'bottom' and the anchor is
> > +	  'bottom', change the gravity to 'top' and the anchor to 'top'.
> > +
> > +	  If the adjusted position also ends up being constrained, the resulting
> > +	  position will be the one before the adjustment. If the resulting
> > +	  position is still constrained, and 'flip_y' is combined with
> > +	  'slide_y', the position is adjusted according to 'slide_y'.
> > +	</description>
> > +      </entry>
> > +    </enum>
> > +
> > +    <request name="set_constrain_adjustment">
> > +      <description summary="set the adjustment to be done when constrained">
> > +	Specify how the window should be positioned if the originally intended
> > +	position caused the surface to be constrained, meaning at least
> > +	partially outside positioning boundaries set by the compositor. The
> > +	adjustment is set by constructing a bitmask describing the adjustment to
> > +	be made when the surface is constrained on that axis.
> > +
> > +	If no bit for one axis is set, the compositor will assume that the child
> > +	surface should not change its position on that axis when constrained.
> > +
> > +	If more than one bit for one axis is set, the order of how adjustments
> > +	are applied is specified in the corresponding adjustment descriptions.
> > +
> > +	The default adjustment is none.
> > +      </description>
> > +      <arg name="constrain_adjustment" type="uint"
> > +	   summary="bit mask of constrain adjustments"/>
> > +    </request>
> > +
> > +    <request name="set_offset">
> > +      <description summary="set surface position offset">
> > +	Specify the surface position offset relative to the position of the
> > +	anchor on the anchor rectangle and the anchor on the surface. For
> > +	example if the anchor of the anchor rectangle is at (x, y), the surface
> > +	has the gravity bottom|right, and the offset is (ox, oy), the calculated
> > +	surface position will be (x + ox, y + oy). The offset position of the
> > +	surface is the one used for constraint testing. See
> > +	set_constrain_adjustment.
> > +
> > +	An example use case is placing a popup menu on top of a user interface
> > +	element, while aligning the user interface element of the parent surface
> > +	with some user interface element placed somewhere in the popup surface.
> > +      </description>
> > +      <arg name="x" type="int" summary="surface position x offset"/>
> > +      <arg name="y" type="int" summary="surface position y offset"/>
> > +    </request>
> > +  </interface>
> > +
> >   <interface name="zxdg_surface_v6" version="1">
> >     <description summary="desktop user interface surface base interface">
> >       An interface that may be implemented by a wl_surface, for
> > @@ -169,8 +414,7 @@
> >       </description>
> >       <arg name="id" type="new_id" interface="zxdg_popup_v6"/>
> >       <arg name="parent" type="object" interface="zxdg_surface_v6"/>
> > -      <arg name="x" type="int"/>
> > -      <arg name="y" type="int"/>
> > +      <arg name="positioner" type="object" interface="zxdg_positioner_v6"/>
> >     </request>
> > 
> >     <request name="set_window_geometry">
> > @@ -729,7 +973,7 @@
> > 	button press, key press, or touch down event. The serial number of the
> > 	event should be passed as 'serial'.
> > 
> > -	The parent of a grabbing popup must either be a xdg_toplevel surface or
> > +	The parent of a grabbing popup must either be an xdg_toplevel surface or
> > 	another xdg_popup with an explicit grab. If the parent is another
> > 	xdg_popup it means that the popups are nested, with this popup now being
> > 	the topmost popup.
> > @@ -764,6 +1008,22 @@
> >       <arg name="serial" type="uint" summary="the serial of the user event"/>
> >     </request>
> > 
> > +    <event name="configure">
> > +      <description summary="configure the popup surface">
> > +	This event asks the popup surface to configure itself given the
> > +	configuration. The configured state should not be applied immediately.
> > +	See xdg_surface.configure for details.
> > +
> > +	The x and y arguments represent the position the popup was placed at
> > +	given the xdg_positioner rule, relative to the upper left corner of the
> > +	window geometry of the parent surface.
> > +      </description>
> > +      <arg name="x" type="int"
> > +	   summary="x position relative to parent surface window geometry"/>
> > +      <arg name="y" type="int"
> > +	   summary="y position relative to parent surface window geometry"/>
> 
> Would 'x position within the parent surface coordinate system' be more clear?
> Again, something that could be adjusted after the merge.

That'd change the meaning. With window geometry, what is meant is
relative to the top left point of the window geometry rectangle.


Jonas

> 
> yong
> 
> 
> > +    </event>
> > +
> >     <event name="popup_done">
> >       <description summary="popup interaction is done">
> > 	The popup_done event is sent out when a popup is dismissed by the
> > -- 
> > 2.5.5
> > 
> > _______________________________________________
> > wayland-devel mailing list
> > wayland-devel at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/wayland-devel
> 


More information about the wayland-devel mailing list