Commit fbe272fb authored by Mitsuru Oshima's avatar Mitsuru Oshima Committed by Commit Bot

Propagate flip layout proprety of the popups

BUG=788782
TEST=manully tested with gtk3-demo

Change-Id: I4a381b9350675d4e5407b378fbe07ae9de64fe8a
Reviewed-on: https://chromium-review.googlesource.com/1108558
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569893}
parent c126b7af
......@@ -1382,11 +1382,27 @@ uint32_t InvertBitfield(uint32_t bitfield, uint32_t mask) {
// TODO(oshima): propagate x/y flip state to children.
struct WaylandPositioner {
static constexpr uint32_t kHorizontalAnchors =
ZXDG_POSITIONER_V6_ANCHOR_LEFT | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
static constexpr uint32_t kVerticalAnchors =
ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
static constexpr uint32_t kHorizontalGravities =
ZXDG_POSITIONER_V6_GRAVITY_LEFT | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
static constexpr uint32_t kVerticalGravities =
ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
static int CalculateX(const gfx::Size& size,
const gfx::Rect& anchor_rect,
uint32_t anchor,
uint32_t gravity,
int offset) {
int offset,
bool flipped) {
if (flipped) {
anchor = InvertBitfield(anchor, kHorizontalAnchors);
gravity = InvertBitfield(gravity, kHorizontalGravities);
offset = -offset;
}
int x = offset;
if (anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT)
x += anchor_rect.x();
......@@ -1406,7 +1422,14 @@ struct WaylandPositioner {
const gfx::Rect& anchor_rect,
uint32_t anchor,
uint32_t gravity,
int offset) {
int offset,
bool flipped) {
if (flipped) {
anchor = InvertBitfield(anchor, kVerticalAnchors);
gravity = InvertBitfield(gravity, kVerticalGravities);
offset = -offset;
}
int y = offset;
if (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP)
y += anchor_rect.y();
......@@ -1423,21 +1446,13 @@ struct WaylandPositioner {
}
// Calculate and return position from current state.
gfx::Point CalculatePosition(const gfx::Rect& work_area) const {
constexpr uint32_t kHorizontalAnchors =
ZXDG_POSITIONER_V6_ANCHOR_LEFT | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
constexpr uint32_t kVerticalAnchors =
ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
constexpr uint32_t kHorizontalGravities =
ZXDG_POSITIONER_V6_GRAVITY_LEFT | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
constexpr uint32_t kVerticalGravities =
ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
gfx::Point CalculatePosition(const gfx::Rect& work_area) {
// TODO(oshima): The size must be smaller than work area.
gfx::Rect bounds(
gfx::Point(CalculateX(size, anchor_rect, anchor, gravity, offset.x()),
CalculateY(size, anchor_rect, anchor, gravity, offset.y())),
gfx::Rect bounds(gfx::Point(CalculateX(size, anchor_rect, anchor, gravity,
offset.x(), x_flipped),
CalculateY(size, anchor_rect, anchor, gravity,
offset.y(), y_flipped)),
size);
// Adjust x position if the bounds are not fully contained by the work area.
......@@ -1455,9 +1470,9 @@ struct WaylandPositioner {
else if (bounds.right() > work_area.right())
bounds.set_x(work_area.right() - size.width());
} else if (adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X) {
bounds.set_x(CalculateX(
size, anchor_rect, InvertBitfield(anchor, kHorizontalAnchors),
InvertBitfield(gravity, kHorizontalGravities), -offset.x()));
x_flipped = !x_flipped;
bounds.set_x(CalculateX(size, anchor_rect, anchor, gravity, offset.x(),
x_flipped));
}
}
......@@ -1476,9 +1491,9 @@ struct WaylandPositioner {
else if (bounds.bottom() > work_area.bottom())
bounds.set_y(work_area.bottom() - size.height());
} else if (adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y) {
bounds.set_y(CalculateY(
size, anchor_rect, InvertBitfield(anchor, kVerticalAnchors),
InvertBitfield(gravity, kVerticalGravities), -offset.y()));
y_flipped = !y_flipped;
bounds.set_y(CalculateY(size, anchor_rect, anchor, gravity, offset.y(),
y_flipped));
}
}
return bounds.origin();
......@@ -1490,6 +1505,8 @@ struct WaylandPositioner {
uint32_t gravity = ZXDG_POSITIONER_V6_GRAVITY_NONE;
uint32_t adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
gfx::Vector2d offset;
bool y_flipped = false;
bool x_flipped = false;
};
void xdg_positioner_v6_destroy(wl_client* client, wl_resource* resource) {
......@@ -1974,7 +1991,7 @@ void xdg_surface_v6_get_popup(wl_client* client,
return;
}
ShellSurface* parent = GetUserDataAs<ShellSurface>(parent_resource);
XdgShellSurface* parent = GetUserDataAs<XdgShellSurface>(parent_resource);
if (!parent->GetWidget()) {
wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"popup parent not constructed");
......@@ -1986,14 +2003,25 @@ void xdg_surface_v6_get_popup(wl_client* client,
"get_popup is called after constructed");
return;
}
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(
parent->GetWidget()->GetNativeWindow());
gfx::Rect work_area = display.work_area();
wm::ConvertRectFromScreen(parent->GetWidget()->GetNativeWindow(), &work_area);
gfx::Point position = GetUserDataAs<WaylandPositioner>(positioner_resource)
->CalculatePosition(work_area);
WaylandPositioner* positioner =
GetUserDataAs<WaylandPositioner>(positioner_resource);
// Try layout using parent's flip state.
positioner->x_flipped = parent->x_flipped();
positioner->y_flipped = parent->y_flipped();
gfx::Point position = positioner->CalculatePosition(work_area);
// Remember the new flip state for its child popups.
shell_surface->set_x_flipped(positioner->x_flipped);
shell_surface->set_y_flipped(positioner->y_flipped);
// |position| is relative to the parent's contents view origin, and |origin|
// is in screen coordinates.
gfx::Point origin = position;
......
......@@ -50,7 +50,18 @@ class XdgShellSurface : public ShellSurface {
int container);
~XdgShellSurface() override;
bool x_flipped() const { return x_flipped_; }
void set_x_flipped(bool flipped) { x_flipped_ = flipped; }
bool y_flipped() const { return y_flipped_; }
void set_y_flipped(bool flipped) { y_flipped_ = flipped; }
private:
// Used by positioner to layout cascading menus in opposite
// direction when the layout does not fit to the work area.
bool y_flipped_ = false;
bool x_flipped_ = false;
DISALLOW_COPY_AND_ASSIGN(XdgShellSurface);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment