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

Bill Spitzak spitzak at gmail.com
Sat Jul 23 01:39:19 UTC 2016


/* Translate xdg_positioner v4 settings to proposed list-of-rectangles api
 *
 * I cannot find any proposed implementation, so I have to base this
off the comments
 * in the protocol spec, which are somewhat ambiguous. See FIXME notes
for where I
 * guessed and may have mis-interpreted the spec.
 */

#include <limits.h>
#include <stdio.h>

/* bits for anchor and gravity */
#define TOP 1
#define BOTTOM 2
#define LEFT 4
#define RIGHT 8

/* bits for constrain_adjustment */
#define SLIDE_X 1
#define SLIDE_Y 2
#define FLIP_X 4
#define FLIP_Y 8

/* v4 positioner data */
typedef struct {
    struct { int width; int height; } size;
    struct { int x; int y; int width; int height; } anchor_rect;
    int anchor;
    int gravity;
    int constrain_adjustment;
    struct { int x; int y; } offset;
} V4Positioner;

/* The new positioner api */
extern void add_rectangle( int x0, int y0, int x1, int y1 ) {
    printf("add_rectangle( %d, %d, %d, %d );\n", x0, y0, x1, y1);
}

/* Possibly the api should support this rather than the 4-number rectangle.
 * x0,y0 must be upper-left corner, x1,y1 the lower-right corner, x,y
is preferred
 * location which must be inside the rectangle.
 */
void add_rectangle6( int x, int y, int x0, int y0, int x1, int y1 )
{
    if (y > y0) {
        if (x > x0)
            add_rectangle(x, y, x0, y0);
        add_rectangle(x, y, x1, y0);
    }
    if (x > x0)
        add_rectangle(x, y, x0, y1);
    add_rectangle(x, y, x1, y1);
}

/* Do one part of a "flip" */
void single_anchor(const V4Positioner* v4, int anchor, int gravity,
int constrain_adjustment) {

    int x, y; /* preferred position */

    /* Find anchor point */
    if (anchor & LEFT)
        x = v4->anchor_rect.x;
    else if (anchor & RIGHT)
        x = v4->anchor_rect.x + v4->anchor_rect.width;
    else
        x = v4->anchor_rect.x + v4->anchor_rect.width / 2;

    if (anchor & TOP)
        y = v4->anchor_rect.y;
    else if (anchor & BOTTOM)
        y = v4->anchor_rect.y + v4->anchor_rect.height;
    else
        y = v4->anchor_rect.y + v4->anchor_rect.height / 2;

    /* move to top-left of size */
    if (gravity & LEFT)
        ;
    else if (gravity & RIGHT)
        x -= v4->size.width;
    else
        x -= v4->size.width / 2;
    if (gravity & TOP)
        ;
    else if (gravity & BOTTOM)
        y -= v4->size.height;
    else
        y -= v4->size.height / 2;

    /* Handle offset.
     * FIXME: I am assuming the "widget in the child" is a rectangle
defined by offset,size.
     * Documentation seems to imply the meaning of offset depends on
the gravity, but
     * that is pretty useless for FLIP setups so I did not do that.
     */
    x -= v4->offset.x;
    y -= v4->offset.y;

    /* Add slide to get resulting rectangles
     * FIXME: unclear if slide is limited to touch the anchor
rectangle. I believe
     * this is not true so I use INT_MAX here.
     * FIXME: unclear if slide is limited to touch the parent surface.
My opinion
     * now is that the compositor can enforce this.
     */
    int x0, y0, x1, y1;
    if (constrain_adjustment & SLIDE_X) {
        x0 = -INT_MAX;
        x1 = +INT_MAX;
    } else {
        x0 = x1 = x;
    }
    if (constrain_adjustment & SLIDE_Y) {
        y0 = -INT_MAX;
        y1 = +INT_MAX;
    } else {
        y0 = y1 = y;
    }

    add_rectangle6(x, y, x0, y0, x1, y1);
}

/* Do the full conversion.
 * FIXME: This will produce redundant identical rectangles. Preventing
this requires more
 * testing for useless flip states.
 */
void convert(const V4Positioner* v4) {

    if (v4->constrain_adjustment & FLIP_Y) {
        /* try the preferred position first, no sliding */
        single_anchor(v4, v4->anchor, v4->gravity,
v4->constrain_adjustment & (~SLIDE_Y));
        /* try the flipped position */
        single_anchor(v4, v4->anchor ^ (TOP|BOTTOM), v4->gravity ^ (TOP|BOTTOM),
                      v4->constrain_adjustment & (~SLIDE_Y));
        /* FIXME: this only does slide on the original side. Unclear
if slide is on other side too.
         */
    }

    /* FIXME: what happens if both FLIP_X and FLIP_Y are set is
unclear. This version only
     * tries three locations, not four.
     */
    if (v4->constrain_adjustment & FLIP_X) {
        /* try the preferred position first, no sliding */
        single_anchor(v4, v4->anchor, v4->gravity,
v4->constrain_adjustment & (~SLIDE_X));
        /* try the flipped position */
        single_anchor(v4, v4->anchor ^ (LEFT|RIGHT), v4->gravity ^ (LEFT|RIGHT),
                      v4->constrain_adjustment & (~SLIDE_X));
    }

    /* Do the non-flipped position */
    single_anchor(v4, v4->anchor, v4->gravity, v4->constrain_adjustment);
}

int main() {
    V4Positioner v4;

    v4.size.width = 100;
    v4.size.height = 100;

    v4.anchor_rect.x = 60;
    v4.anchor_rect.y = 90;
    v4.anchor_rect.width = 0;
    v4.anchor_rect.height = 0;

    v4.anchor = 0;
    v4.gravity = TOP;
    v4.constrain_adjustment = FLIP_Y | SLIDE_X;

    v4.offset.x = 0;
    v4.offset.y = 0;

    convert(&v4);
    return 0;
}


More information about the wayland-devel mailing list