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

Improve xdg_popup support

* use TYPE_POPUP for xdg_popup. The differences from TYPE_WINDOW are:
  - no frame
  - ash will not control its bounds
* make popups transient children: this fixes following scenarios
  - z order is correctly updated when parent's z order changes
  - they're grouped in overview.
* implement grab
  - capture even when the grab is requested on the surface
  - transfer capture to child if the child popup requested
     grab.
  - close the surface when capture(grab) is lost.
  - but transfer the grab to the parent if the parent had grab.

BUG=788782
TEST=covered by unit tests. manually tested with gtk3-demo.

Change-Id: I73f5bc7e555f2c28f78dc25a55f77f0a70fd9b78
Reviewed-on: https://chromium-review.googlesource.com/1102354
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568364}
parent 099d49c3
......@@ -9,6 +9,7 @@
#include "ash/public/cpp/shell_window_ids.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/pointer_gesture_pinch_delegate.h"
#include "components/exo/shell_surface_base.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
......@@ -44,13 +45,8 @@ const float kLargeCursorScale = 2.8f;
const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0);
// Synthesized events typically lack floating point precision so to avoid
// generating mouse event jitter we consider the location of these events
// to be the same as |location| if floored values match.
bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
if (event->flags() & ui::EF_IS_SYNTHESIZED)
return event->location() == gfx::ToFlooredPoint(location);
bool SameLocation(const gfx::PointF& location_in_target,
const gfx::PointF& location) {
// In general, it is good practice to compare floats using an epsilon.
// In particular, the mouse location_f() could differ between the
// MOUSE_PRESSED and MOUSE_RELEASED events. At MOUSE_RELEASED, it will have a
......@@ -58,7 +54,7 @@ bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
// calculate it passing through all the hierarchy of windows, and that could
// generate rounding error. std::numeric_limits<float>::epsilon() is not big
// enough to catch this rounding error.
gfx::Vector2dF offset = event->location_f() - location;
gfx::Vector2dF offset = location_in_target - location;
return offset.LengthSquared() < (2 * kLocatedEventEpsilonSquared);
}
......@@ -203,10 +199,16 @@ void Pointer::OnSurfaceDestroying(Surface* surface) {
void Pointer::OnMouseEvent(ui::MouseEvent* event) {
Surface* target = GetEffectiveTargetForEvent(event);
gfx::PointF location_in_target = event->location_f();
if (target) {
aura::Window::ConvertPointToTarget(
static_cast<aura::Window*>(event->target()), target->window(),
&location_in_target);
}
// Update focus if target is different than the current pointer focus.
if (target != focus_surface_)
SetFocus(target, event->location_f(), event->button_flags());
SetFocus(target, location_in_target, event->button_flags());
if (!focus_surface_)
return;
......@@ -218,8 +220,15 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
// here as mouse movement can generate both "moved" and "entered" events
// but OnPointerMotion should only be called if location changed since
// OnPointerEnter was called.
if (!SameLocation(event, location_)) {
location_ = event->location_f();
// For synthesized events, they typically lack floating point precision
// so to avoid generating mouse event jitter we consider the location of
// these events to be the same as |location| if floored values match.
bool same_location = !event->IsSynthesized()
? SameLocation(location_in_target, location_)
: gfx::ToFlooredPoint(location_in_target) ==
gfx::ToFlooredPoint(location_);
if (!same_location) {
location_ = location_in_target;
delegate_->OnPointerMotion(event->time_stamp(), location_);
delegate_->OnPointerFrame();
}
......@@ -360,9 +369,9 @@ void Pointer::OnDisplayConfigurationChanged() {
////////////////////////////////////////////////////////////////////////////////
// Pointer, private:
Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
Surface* target =
Surface::AsSurface(static_cast<aura::Window*>(event->target()));
Surface* Pointer::GetEffectiveTargetForEvent(ui::LocatedEvent* event) const {
Surface* target = ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(event);
if (!target)
return nullptr;
......
......@@ -27,7 +27,7 @@ class CopyOutputResult;
}
namespace ui {
class Event;
class LocatedEvent;
class MouseEvent;
}
......@@ -84,7 +84,7 @@ class Pointer : public SurfaceTreeHost,
private:
// Returns the effective target for |event|.
Surface* GetEffectiveTargetForEvent(ui::Event* event) const;
Surface* GetEffectiveTargetForEvent(ui::LocatedEvent* event) const;
// Change pointer focus to |surface|.
void SetFocus(Surface* surface,
......
......@@ -140,6 +140,17 @@ void ShellSurface::SetFullscreen(bool fullscreen) {
widget_->SetFullscreen(fullscreen);
}
void ShellSurface::SetPopup() {
DCHECK(!widget_);
is_popup_ = true;
}
void ShellSurface::Grab() {
DCHECK(is_popup_);
DCHECK(!widget_);
has_grab_ = true;
}
void ShellSurface::Resize(int component) {
TRACE_EVENT1("exo", "ShellSurface::Resize", "component", component);
......
......@@ -43,6 +43,12 @@ class ShellSurface : public ShellSurfaceBase,
// Set fullscreen state for shell surface.
void SetFullscreen(bool fullscreen);
// Make the shell surface popup type.
void SetPopup();
// Set event grab on the surface.
void Grab();
// Start an interactive resize of surface. |component| is one of the windows
// HT constants (see ui/base/hit_test.h) and describes in what direction the
// surface should be resized.
......
......@@ -45,6 +45,7 @@
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/path.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/capture_controller.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_types.h"
......@@ -236,7 +237,10 @@ class CustomWindowTargeter : public aura::WindowTargeter {
if (!surface)
return false;
int component = widget_->non_client_view()->NonClientHitTest(local_point);
int component =
widget_->non_client_view()
? widget_->non_client_view()->NonClientHitTest(local_point)
: HTNOWHERE;
if (component != HTNOWHERE && component != HTCLIENT &&
component != HTBORDER) {
return true;
......@@ -412,6 +416,8 @@ ShellSurfaceBase::~ShellSurfaceBase() {
parent_->RemoveObserver(this);
if (root_surface())
root_surface()->RemoveSurfaceObserver(this);
if (has_grab_)
wm::CaptureController::Get()->RemoveObserver(this);
}
void ShellSurfaceBase::AcknowledgeConfigure(uint32_t serial) {
......@@ -650,6 +656,41 @@ Surface* ShellSurfaceBase::GetMainSurface(const aura::Window* window) {
return window->GetProperty(kMainSurfaceKey);
}
// static
Surface* ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(
ui::LocatedEvent* event) {
aura::Window* window = wm::CaptureController::Get()->GetCaptureWindow();
gfx::PointF location_in_target = event->location_f();
if (!window)
return Surface::AsSurface(static_cast<aura::Window*>(event->target()));
Surface* main_surface = ShellSurfaceBase::GetMainSurface(window);
// Skip if the event is captured by non exo windwows.
if (!main_surface)
return nullptr;
while (true) {
aura::Window* focused = window->GetEventHandlerForPoint(
gfx::ToFlooredPoint(location_in_target));
if (focused) {
aura::Window::ConvertPointToTarget(window, focused, &location_in_target);
return Surface::AsSurface(focused);
}
aura::Window* parent_window = wm::GetTransientParent(window);
if (!parent_window) {
location_in_target = event->location_f();
return main_surface;
}
aura::Window::ConvertPointToTarget(window, parent_window,
&location_in_target);
window = parent_window;
}
}
std::unique_ptr<base::trace_event::TracedValue>
ShellSurfaceBase::AsTracedValue() const {
std::unique_ptr<base::trace_event::TracedValue> value(
......@@ -746,6 +787,9 @@ void ShellSurfaceBase::OnSurfaceCommit() {
DCHECK(!widget_->IsVisible());
pending_show_widget_ = false;
widget_->Show();
if (has_grab_)
StartCapture();
if (container_ == ash::kShellWindowId_SystemModalContainer)
UpdateSystemModal();
}
......@@ -970,6 +1014,29 @@ void ShellSurfaceBase::GetWidgetHitTestMask(gfx::Path* mask) const {
mask->transform(matrix);
}
void ShellSurfaceBase::OnCaptureChanged(aura::Window* lost_capture,
aura::Window* gained_capture) {
if (lost_capture == widget_->GetNativeWindow() && is_popup_) {
wm::CaptureController::Get()->RemoveObserver(this);
if (gained_capture &&
lost_capture == wm::GetTransientParent(gained_capture)) {
// Don't close if the capture has been transferred to the child popup.
return;
}
aura::Window* parent = wm::GetTransientParent(lost_capture);
if (parent) {
// The capture needs to be transferred to the parent if it had grab.
views::Widget* parent_widget =
views::Widget::GetWidgetForNativeWindow(parent);
ShellSurfaceBase* parent_shell_surface = static_cast<ShellSurfaceBase*>(
parent_widget->widget_delegate()->GetContentsView());
if (parent_shell_surface->has_grab_)
parent_shell_surface->StartCapture();
}
widget_->Close();
}
}
////////////////////////////////////////////////////////////////////////////////
// views::Views overrides:
......@@ -1178,7 +1245,8 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
DCHECK(!widget_);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.type = is_popup_ ? views::Widget::InitParams::TYPE_POPUP
: views::Widget::InitParams::TYPE_WINDOW;
params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
params.delegate = this;
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
......@@ -1268,9 +1336,8 @@ void ShellSurfaceBase::Configure() {
uint32_t serial = 0;
if (!configure_callback_.is_null()) {
if (widget_) {
const views::NonClientView* non_client_view = widget_->non_client_view();
serial = configure_callback_.Run(
non_client_view->frame_view()->GetBoundsForClientView().size(),
GetClientViewBounds().size(),
ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(),
IsResizing(), widget_->IsActive(), origin_offset);
} else {
......@@ -1349,10 +1416,7 @@ void ShellSurfaceBase::SetWidgetBounds(const gfx::Rect& bounds) {
}
void ShellSurfaceBase::UpdateSurfaceBounds() {
gfx::Point origin = widget_->non_client_view()
->frame_view()
->GetBoundsForClientView()
.origin();
gfx::Point origin = GetClientViewBounds().origin();
origin += GetSurfaceOrigin().OffsetFromOrigin();
origin -= ToFlooredVector2d(ScaleVector2d(
......@@ -1413,6 +1477,14 @@ gfx::Point ShellSurfaceBase::GetMouseLocation() const {
return location;
}
gfx::Rect ShellSurfaceBase::GetClientViewBounds() const {
return widget_->non_client_view()
? widget_->non_client_view()
->frame_view()
->GetBoundsForClientView()
: gfx::Rect(widget_->GetWindowBoundsInScreen().size());
}
gfx::Rect ShellSurfaceBase::GetShadowBounds() const {
return shadow_bounds_->IsEmpty()
? gfx::Rect(widget_->GetNativeWindow()->bounds().size())
......@@ -1551,8 +1623,11 @@ void ShellSurfaceBase::EndDrag(bool revert) {
gfx::Rect ShellSurfaceBase::GetWidgetBounds() const {
gfx::Rect visible_bounds = GetVisibleBounds();
gfx::Rect new_widget_bounds =
widget_->non_client_view()->GetWindowBoundsForClientBounds(
visible_bounds);
widget_->non_client_view()
? widget_->non_client_view()->GetWindowBoundsForClientBounds(
visible_bounds)
: visible_bounds;
if (movement_disabled_) {
new_widget_bounds.set_origin(origin_);
} else if (resize_component_ == HTCAPTION) {
......@@ -1574,8 +1649,8 @@ gfx::Point ShellSurfaceBase::GetSurfaceOrigin() const {
DCHECK(!movement_disabled_ || resize_component_ == HTCAPTION);
gfx::Rect visible_bounds = GetVisibleBounds();
gfx::Rect client_bounds =
widget_->non_client_view()->frame_view()->GetBoundsForClientView();
gfx::Rect client_bounds = GetClientViewBounds();
switch (resize_component_) {
case HTCAPTION:
return gfx::Point() + origin_offset_ - visible_bounds.OffsetFromOrigin();
......@@ -1619,4 +1694,11 @@ void ShellSurfaceBase::SetParentWindow(aura::Window* parent) {
widget_->OnSizeConstraintsChanged();
}
void ShellSurfaceBase::StartCapture() {
widget_->set_auto_release_capture(false);
wm::CaptureController::Get()->AddObserver(this);
// Just capture on the window.
widget_->SetCapture(nullptr /* view */);
}
} // namespace exo
......@@ -17,6 +17,7 @@
#include "base/strings/string16.h"
#include "components/exo/surface_observer.h"
#include "components/exo/surface_tree_host.h"
#include "ui/aura/client/capture_client_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/compositor_lock.h"
......@@ -53,6 +54,7 @@ class Surface;
class ShellSurfaceBase : public SurfaceTreeHost,
public SurfaceObserver,
public aura::WindowObserver,
public aura::client::CaptureClientObserver,
public views::WidgetDelegate,
public views::View,
public wm::ActivationChangeObserver {
......@@ -166,6 +168,12 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// |window| must not be nullptr.
static Surface* GetMainSurface(const aura::Window* window);
// Returns the target surface for the located event |event|. If an
// event handling is grabbed by an window, it'll first examine that
// window, then traverse to its transeitn parent if the parent also
// requested grab.
static Surface* GetTargetSurfaceForLocatedEvent(ui::LocatedEvent* event);
// Returns a trace value representing the state of the surface.
std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
......@@ -181,6 +189,10 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Overridden from SurfaceObserver:
void OnSurfaceDestroying(Surface* surface) override;
// Overridden from CaptureClientObserver:
void OnCaptureChanged(aura::Window* lost_capture,
aura::Window* gained_capture) override;
// Overridden from views::WidgetDelegate:
bool CanResize() const override;
bool CanMaximize() const override;
......@@ -278,6 +290,9 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// In the coordinate system of the parent root window.
gfx::Point GetMouseLocation() const;
// Returns the bounds of the client area.nnn
gfx::Rect GetClientViewBounds() const;
// In the local coordinate system of the window.
virtual gfx::Rect GetShadowBounds() const;
......@@ -289,6 +304,9 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Set the parent window of this surface.
void SetParentWindow(aura::Window* parent);
// Start the event capture on this surface.
void StartCapture();
const gfx::Rect& geometry() const { return geometry_; }
views::Widget* widget_ = nullptr;
......@@ -316,6 +334,8 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// complete. https://crbug.com/801666.
bool client_controlled_move_resize_ = true;
SurfaceFrameType frame_type_ = SurfaceFrameType::NONE;
bool is_popup_ = false;
bool has_grab_ = false;
bool frame_enabled() const {
return frame_type_ != SurfaceFrameType::NONE &&
......
......@@ -33,7 +33,10 @@
#include "ui/display/display.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/capture_controller.h"
#include "ui/wm/core/window_util.h"
namespace exo {
......@@ -57,6 +60,18 @@ uint32_t ConfigureFullscreen(uint32_t serial,
return serial;
}
std::unique_ptr<ShellSurface> CreatePopupShellSurface(
Surface* popup_surface,
ShellSurface* parent,
const gfx::Point& origin) {
auto popup_shell_surface = std::make_unique<ShellSurface>(popup_surface);
popup_shell_surface->DisableMovement();
popup_shell_surface->SetPopup();
popup_shell_surface->SetParent(parent);
popup_shell_surface->SetOrigin(origin);
return popup_shell_surface;
}
TEST_F(ShellSurfaceTest, AcknowledgeConfigure) {
gfx::Size buffer_size(32, 32);
std::unique_ptr<Buffer> buffer(
......@@ -583,5 +598,86 @@ TEST_F(ShellSurfaceTest, CycleSnap) {
shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
}
TEST_F(ShellSurfaceTest, Popup) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
surface->Attach(buffer.get());
surface->Commit();
shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
std::unique_ptr<Buffer> popup_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
std::unique_ptr<Surface> popup_surface(new Surface);
popup_surface->Attach(popup_buffer.get());
std::unique_ptr<ShellSurface> popup_shell_surface(CreatePopupShellSurface(
popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
popup_shell_surface->Grab();
popup_surface->Commit();
ASSERT_EQ(gfx::Rect(50, 50, 256, 256),
popup_shell_surface->GetWidget()->GetWindowBoundsInScreen());
// Verify that created shell surface is popup and has capture.
EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP,
popup_shell_surface->GetWidget()->GetNativeWindow()->type());
EXPECT_EQ(wm::CaptureController::Get()->GetCaptureWindow(),
popup_shell_surface->GetWidget()->GetNativeWindow());
// ShellSurface can capture the event even after it is craeted.
std::unique_ptr<Buffer> sub_popup_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
std::unique_ptr<Surface> sub_popup_surface(new Surface);
sub_popup_surface->Attach(popup_buffer.get());
std::unique_ptr<ShellSurface> sub_popup_shell_surface(CreatePopupShellSurface(
sub_popup_surface.get(), popup_shell_surface.get(), gfx::Point(100, 50)));
sub_popup_shell_surface->Grab();
sub_popup_surface->Commit();
ASSERT_EQ(gfx::Rect(100, 50, 256, 256),
sub_popup_shell_surface->GetWidget()->GetWindowBoundsInScreen());
// The capture should be on sub_popup_shell_surface.
EXPECT_EQ(wm::CaptureController::Get()->GetCaptureWindow(),
sub_popup_shell_surface->GetWidget()->GetNativeWindow());
EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP,
sub_popup_shell_surface->GetWidget()->GetNativeWindow()->type());
{
// Mouse is on the top most popup.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
gfx::Point(100, 50), ui::EventTimeForNow(), 0, 0);
EXPECT_EQ(sub_popup_surface.get(),
ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(&event));
}
{
// Move the mouse to the parent popup.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, 0),
gfx::Point(75, 50), ui::EventTimeForNow(), 0, 0);
EXPECT_EQ(popup_surface.get(),
ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(&event));
}
{
// Move the mouse to the main window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, -25),
gfx::Point(75, 25), ui::EventTimeForNow(), 0, 0);
EXPECT_EQ(surface.get(),
ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(&event));
}
// Removing top most popup moves the grab to parent popup.
sub_popup_shell_surface.reset();
EXPECT_EQ(wm::CaptureController::Get()->GetCaptureWindow(),
popup_shell_surface->GetWidget()->GetNativeWindow());
{
// Targetting should still work.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
gfx::Point(50, 50), ui::EventTimeForNow(), 0, 0);
EXPECT_EQ(popup_surface.get(),
ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(&event));
}
}
} // namespace
} // namespace exo
......@@ -4,12 +4,15 @@
#include "components/exo/touch.h"
#include "components/exo/shell_surface_base.h"
#include "components/exo/surface.h"
#include "components/exo/touch_delegate.h"
#include "components/exo/touch_stylus_delegate.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
#include "ui/wm/core/capture_controller.h"
#include "ui/wm/core/window_util.h"
namespace exo {
namespace {
......@@ -190,9 +193,9 @@ void Touch::OnSurfaceDestroying(Surface* surface) {
////////////////////////////////////////////////////////////////////////////////
// Touch, private:
Surface* Touch::GetEffectiveTargetForEvent(ui::Event* event) const {
Surface* target =
Surface::AsSurface(static_cast<aura::Window*>(event->target()));
Surface* Touch::GetEffectiveTargetForEvent(ui::LocatedEvent* event) const {
Surface* target = ShellSurfaceBase::GetTargetSurfaceForLocatedEvent(event);
if (!target)
return nullptr;
......
......@@ -13,6 +13,7 @@
#include "ui/gfx/geometry/point_f.h"
namespace ui {
class LocatedEvent;
class TouchEvent;
}
......@@ -41,7 +42,7 @@ class Touch : public ui::EventHandler, public SurfaceObserver {
private:
// Returns the effective target for |event|.
Surface* GetEffectiveTargetForEvent(ui::Event* event) const;
Surface* GetEffectiveTargetForEvent(ui::LocatedEvent* event) const;
// The delegate instance that all events are dispatched to.
TouchDelegate* const delegate_;
......
......@@ -1792,18 +1792,43 @@ const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_implementation = {
// Wrapper around shell surface that allows us to handle the case where the
// xdg surface resource is destroyed before the popup resource.
class WaylandPopup {
class WaylandPopup : aura::WindowObserver {
public:
WaylandPopup(wl_resource* resource, wl_resource* surface_resource)
: resource_(resource), weak_ptr_factory_(this) {
ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(surface_resource);
shell_surface->set_close_callback(
: resource_(resource),
shell_surface_(GetUserDataAs<ShellSurface>(surface_resource)),
weak_ptr_factory_(this) {
shell_surface_->host_window()->AddObserver(this);
shell_surface_->set_close_callback(
base::Bind(&WaylandPopup::OnClose, weak_ptr_factory_.GetWeakPtr()));
shell_surface->set_configure_callback(
shell_surface_->set_configure_callback(
base::Bind(&HandleXdgSurfaceV6ConfigureCallback, surface_resource,
base::Bind(&WaylandPopup::OnConfigure,
weak_ptr_factory_.GetWeakPtr())));
}
~WaylandPopup() override {
if (shell_surface_)
shell_surface_->host_window()->RemoveObserver(this);
}
void Grab() {
if (!shell_surface_) {
wl_resource_post_error(resource_, ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
"the surface has already been destroyed");
return;
}
if (shell_surface_->GetWidget()) {
wl_resource_post_error(resource_, ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
"grab must be called before construction");
return;
}
shell_surface_->Grab();
}
// Overridden from aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override {
shell_surface_ = nullptr;
}
private:
void OnClose() {
......@@ -1819,6 +1844,7 @@ class WaylandPopup {
}
wl_resource* const resource_;
ShellSurface* shell_surface_;
base::WeakPtrFactory<WaylandPopup> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
......@@ -1832,7 +1858,7 @@ void xdg_popup_v6_grab(wl_client* client,
wl_resource* resource,
wl_resource* seat,
uint32_t serial) {
NOTIMPLEMENTED();
GetUserDataAs<WaylandPopup>(resource)->Grab();
}
const struct zxdg_popup_v6_interface xdg_popup_v6_implementation = {
......@@ -1885,6 +1911,12 @@ void xdg_surface_v6_get_popup(wl_client* client,
return;
}
if (shell_surface->GetWidget()) {
wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
"get_popup is called after constructed");
return;
}
gfx::Point position = GetUserDataAs<WaylandPositioner>(positioner_resource)
->CalculatePosition();
// |position| is relative to the parent's contents view origin, and |origin|
......@@ -1897,6 +1929,8 @@ void xdg_surface_v6_get_popup(wl_client* client,
shell_surface->DisableMovement();
shell_surface->SetActivatable(false);
shell_surface->SetCanMinimize(false);
shell_surface->SetParent(parent);
shell_surface->SetPopup();
shell_surface->SetEnabled(true);
wl_resource* xdg_popup_resource =
......
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