| Index: components/exo/shell_surface.cc
|
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
|
| index cf8cced1d4c8210fd0d2ee2a0262be8089afd467..d82efbfc17b277835dfcf0eb7dcc75121459dc1c 100644
|
| --- a/components/exo/shell_surface.cc
|
| +++ b/components/exo/shell_surface.cc
|
| @@ -13,6 +13,7 @@
|
| #include "ash/common/wm/window_state.h"
|
| #include "ash/common/wm/window_state_delegate.h"
|
| #include "ash/common/wm_shell.h"
|
| +#include "ash/wm/drag_window_resizer.h"
|
| #include "ash/wm/window_state_aura.h"
|
| #include "ash/wm/window_util.h"
|
| #include "base/logging.h"
|
| @@ -21,6 +22,7 @@
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "base/trace_event/trace_event_argument.h"
|
| +#include "components/exo/display.h"
|
| #include "components/exo/surface.h"
|
| #include "ui/aura/client/aura_constants.h"
|
| #include "ui/aura/client/cursor_client.h"
|
| @@ -186,6 +188,26 @@ class CustomWindowStateDelegate : public ash::wm::WindowStateDelegate,
|
| DISALLOW_COPY_AND_ASSIGN(CustomWindowStateDelegate);
|
| };
|
|
|
| +class CustomWindowResizer : public ash::WindowResizer {
|
| + public:
|
| + explicit CustomWindowResizer(ash::wm::WindowState* window_state)
|
| + : WindowResizer(window_state), shell_(GetTarget()->GetShell()) {
|
| + shell_->LockCursor();
|
| + }
|
| +
|
| + ~CustomWindowResizer() override { shell_->UnlockCursor(); }
|
| +
|
| + // ash::WindowResizer:
|
| + void Drag(const gfx::Point& location, int event_flags) override {}
|
| + void CompleteDrag() override {}
|
| + void RevertDrag() override {}
|
| +
|
| + private:
|
| + ash::WmShell* const shell_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CustomWindowResizer);
|
| +};
|
| +
|
| class ShellSurfaceWidget : public views::Widget {
|
| public:
|
| explicit ShellSurfaceWidget(ShellSurface* shell_surface)
|
| @@ -332,18 +354,21 @@ ShellSurface::ScopedAnimationsDisabled::~ScopedAnimationsDisabled() {
|
| DEFINE_LOCAL_WINDOW_PROPERTY_KEY(std::string*, kApplicationIdKey, nullptr)
|
| DEFINE_LOCAL_WINDOW_PROPERTY_KEY(Surface*, kMainSurfaceKey, nullptr)
|
|
|
| -ShellSurface::ShellSurface(Surface* surface,
|
| +ShellSurface::ShellSurface(const Display& display,
|
| + Surface* surface,
|
| ShellSurface* parent,
|
| const gfx::Rect& initial_bounds,
|
| bool activatable,
|
| int container)
|
| - : widget_(nullptr),
|
| + : display_(display),
|
| + widget_(nullptr),
|
| surface_(surface),
|
| parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr),
|
| initial_bounds_(initial_bounds),
|
| activatable_(activatable),
|
| container_(container) {
|
| WMHelper::GetInstance()->AddActivationObserver(this);
|
| + WMHelper::GetInstance()->AddShellObserver(this);
|
| surface_->SetSurfaceDelegate(this);
|
| surface_->AddSurfaceObserver(this);
|
| surface_->window()->Show();
|
| @@ -352,8 +377,9 @@ ShellSurface::ShellSurface(Surface* surface,
|
| parent_->AddObserver(this);
|
| }
|
|
|
| -ShellSurface::ShellSurface(Surface* surface)
|
| - : ShellSurface(surface,
|
| +ShellSurface::ShellSurface(const Display& display, Surface* surface)
|
| + : ShellSurface(display,
|
| + surface,
|
| nullptr,
|
| gfx::Rect(),
|
| true,
|
| @@ -361,8 +387,7 @@ ShellSurface::ShellSurface(Surface* surface)
|
|
|
| ShellSurface::~ShellSurface() {
|
| DCHECK(!scoped_configure_);
|
| - if (resizer_)
|
| - EndDrag(false /* revert */);
|
| + EndDragOrMove(false /* revert */);
|
| if (widget_) {
|
| ash::wm::GetWindowState(widget_->GetNativeWindow())->RemoveObserver(this);
|
| widget_->GetNativeWindow()->RemoveObserver(this);
|
| @@ -371,6 +396,7 @@ ShellSurface::~ShellSurface() {
|
| widget_->CloseNow();
|
| }
|
| WMHelper::GetInstance()->RemoveActivationObserver(this);
|
| + WMHelper::GetInstance()->RemoveShellObserver(this);
|
| if (parent_)
|
| parent_->RemoveObserver(this);
|
| if (surface_) {
|
| @@ -470,6 +496,41 @@ void ShellSurface::Restore() {
|
| widget_->Restore();
|
| }
|
|
|
| +void ShellSurface::SetMoving() {
|
| + TRACE_EVENT0("exo", "ShellSurface::SetMoving");
|
| +
|
| + if (move_resizer_)
|
| + return;
|
| +
|
| + ash::wm::WindowState* const window_state =
|
| + ash::wm::GetWindowState(widget_->GetNativeWindow());
|
| +
|
| + DCHECK(!window_state->drag_details());
|
| + window_state->CreateDragDetails(GetMouseLocation(), HTCAPTION,
|
| + aura::client::WINDOW_MOVE_SOURCE_MOUSE);
|
| +
|
| + // The resizer renders phantom windows, but does not control window movement.
|
| + move_resizer_.reset(ash::DragWindowResizer::Create(
|
| + new CustomWindowResizer(window_state), window_state));
|
| +
|
| + surface_->window()->SetCapture();
|
| +}
|
| +
|
| +void ShellSurface::UnsetMoving(bool revert) {
|
| + TRACE_EVENT1("exo", "ShellSurface::UnsetMoving", "revert", revert);
|
| +
|
| + if (!move_resizer_)
|
| + return;
|
| +
|
| + if (revert)
|
| + move_resizer_->RevertDrag();
|
| + else
|
| + move_resizer_->CompleteDrag();
|
| +
|
| + move_resizer_.reset();
|
| + surface_->window()->ReleaseCapture();
|
| +}
|
| +
|
| void ShellSurface::SetFullscreen(bool fullscreen) {
|
| TRACE_EVENT1("exo", "ShellSurface::SetFullscreen", "fullscreen", fullscreen);
|
|
|
| @@ -684,9 +745,7 @@ void ShellSurface::OnSurfaceCommit() {
|
| }
|
| }
|
|
|
| - // Update surface bounds.
|
| - surface_->window()->SetBounds(
|
| - gfx::Rect(surface_origin, surface_->window()->layer()->size()));
|
| + UpdateSurfaceBounds();
|
|
|
| // Update surface scale.
|
| if (pending_scale_ != scale_) {
|
| @@ -716,8 +775,7 @@ bool ShellSurface::IsSurfaceSynchronized() const {
|
| // SurfaceObserver overrides:
|
|
|
| void ShellSurface::OnSurfaceDestroying(Surface* surface) {
|
| - if (resizer_)
|
| - EndDrag(false /* revert */);
|
| + EndDragOrMove(false /* revert */);
|
| if (widget_)
|
| SetMainSurface(widget_->GetNativeWindow(), nullptr);
|
| surface->RemoveSurfaceObserver(this);
|
| @@ -757,8 +815,7 @@ base::string16 ShellSurface::GetWindowTitle() const {
|
| }
|
|
|
| void ShellSurface::WindowClosing() {
|
| - if (resizer_)
|
| - EndDrag(true /* revert */);
|
| + EndDragOrMove(true /* revert */);
|
| SetEnabled(false);
|
| widget_ = nullptr;
|
| shadow_overlay_ = nullptr;
|
| @@ -812,6 +869,8 @@ void ShellSurface::OnPreWindowStateTypeChange(
|
| ash::wm::WindowStateType new_type = window_state->GetStateType();
|
| if (ash::wm::IsMaximizedOrFullscreenOrPinnedWindowStateType(old_type) ||
|
| ash::wm::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
|
| + EndDragOrMove(false /* revert */);
|
| +
|
| // When transitioning in/out of maximized or fullscreen mode we need to
|
| // make sure we have a configure callback before we allow the default
|
| // cross-fade animations. The configure callback provides a mechanism for
|
| @@ -863,8 +922,7 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
|
| pending_origin_config_offset_ += origin_offset;
|
| origin_ -= origin_offset;
|
|
|
| - surface_->window()->SetBounds(
|
| - gfx::Rect(GetSurfaceOrigin(), surface_->window()->layer()->size()));
|
| + UpdateSurfaceBounds();
|
|
|
| // The shadow size may be updated to match the widget. Change it back
|
| // to the shadow content size.
|
| @@ -895,6 +953,9 @@ void ShellSurface::OnWindowActivated(
|
| if (!widget_)
|
| return;
|
|
|
| + if (lost_active == widget_->GetNativeWindow())
|
| + UnsetMoving(false /* revert */);
|
| +
|
| if (gained_active == widget_->GetNativeWindow() ||
|
| lost_active == widget_->GetNativeWindow()) {
|
| DCHECK(activatable_);
|
| @@ -904,6 +965,18 @@ void ShellSurface::OnWindowActivated(
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| +// WMHelper::ShellObserver overrides:
|
| +
|
| +void ShellSurface::OnOverviewModeStarted() {
|
| + EndDragOrMove(false /* revert */);
|
| + ignore_widget_bounds_changes_ = true;
|
| +}
|
| +
|
| +void ShellSurface::OnOverviewModeEnded() {
|
| + ignore_widget_bounds_changes_ = false;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| // WMHelper::AccessibilityObserver overrides:
|
|
|
| void ShellSurface::OnAccessibilityModeChanged() {
|
| @@ -1007,6 +1080,7 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
|
| params.parent =
|
| parent_ ? parent_ : WMHelper::GetInstance()->GetContainer(container_);
|
| params.bounds = initial_bounds_;
|
| + display_.ConvertFromVirtualToScreen(¶ms.bounds);
|
| bool activatable = activatable_;
|
| // ShellSurfaces in system modal container are only activatable if input
|
| // region is non-empty. See OnCommitSurface() for more details.
|
| @@ -1120,16 +1194,10 @@ void ShellSurface::AttemptToStartDrag(int component) {
|
| if (widget_->GetNativeWindow()->HasCapture())
|
| return;
|
|
|
| - aura::Window* root_window = widget_->GetNativeWindow()->GetRootWindow();
|
| - gfx::Point drag_location =
|
| - root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
|
| - aura::Window::ConvertPointToTarget(
|
| - root_window, widget_->GetNativeWindow()->parent(), &drag_location);
|
| -
|
| // Set the cursor before calling CreateWindowResizer(), as that will
|
| // eventually call LockCursor() and prevent the cursor from changing.
|
| - aura::client::CursorClient* cursor_client =
|
| - aura::client::GetCursorClient(root_window);
|
| + aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
|
| + widget_->GetNativeWindow()->GetRootWindow());
|
| DCHECK(cursor_client);
|
|
|
| switch (component) {
|
| @@ -1166,7 +1234,7 @@ void ShellSurface::AttemptToStartDrag(int component) {
|
| }
|
|
|
| resizer_ = ash::CreateWindowResizer(
|
| - ash::WmWindowAura::Get(widget_->GetNativeWindow()), drag_location,
|
| + ash::WmWindowAura::Get(widget_->GetNativeWindow()), GetMouseLocation(),
|
| component, aura::client::WINDOW_MOVE_SOURCE_MOUSE);
|
| if (!resizer_)
|
| return;
|
| @@ -1208,6 +1276,13 @@ void ShellSurface::EndDrag(bool revert) {
|
| UpdateWidgetBounds();
|
| }
|
|
|
| +void ShellSurface::EndDragOrMove(bool revert) {
|
| + if (resizer_)
|
| + EndDrag(revert);
|
| + else
|
| + UnsetMoving(revert);
|
| +}
|
| +
|
| bool ShellSurface::IsResizing() const {
|
| if (!resizer_)
|
| return false;
|
| @@ -1227,8 +1302,12 @@ gfx::Point ShellSurface::GetSurfaceOrigin() const {
|
|
|
| // If initial bounds were specified then surface origin is always relative
|
| // to those bounds.
|
| - if (!initial_bounds_.IsEmpty())
|
| - return initial_bounds_.origin() - window_bounds.OffsetFromOrigin();
|
| + if (!initial_bounds_.IsEmpty()) {
|
| + gfx::Point origin = window_bounds.origin();
|
| + wm::ConvertPointToScreen(widget_->GetNativeWindow()->parent(), &origin);
|
| + display_.ConvertFromScreenToVirtual(&origin);
|
| + return initial_bounds_.origin() - origin.OffsetFromOrigin();
|
| + }
|
|
|
| gfx::Rect visible_bounds = GetVisibleBounds();
|
| switch (resize_component_) {
|
| @@ -1270,15 +1349,15 @@ void ShellSurface::UpdateWidgetBounds() {
|
| return;
|
| }
|
|
|
| - // 2) When a window is being dragged.
|
| - if (IsResizing())
|
| + // 2) When a window is being dragged, or is being moved by the shell.
|
| + if (IsResizing() || ignore_widget_bounds_changes_)
|
| return;
|
|
|
| // Return early if there is pending configure requests.
|
| if (!pending_configs_.empty() || scoped_configure_)
|
| return;
|
|
|
| - gfx::Rect visible_bounds = GetVisibleBounds();
|
| + gfx::Rect visible_bounds = GetVisibleBounds(); // In virtual coordinates.
|
| gfx::Rect new_widget_bounds = visible_bounds;
|
|
|
| // Avoid changing widget origin unless initial bounds were specified and
|
| @@ -1286,6 +1365,12 @@ void ShellSurface::UpdateWidgetBounds() {
|
| if (initial_bounds_.IsEmpty())
|
| new_widget_bounds.set_origin(widget_->GetWindowBoundsInScreen().origin());
|
|
|
| + else {
|
| + new_widget_bounds.set_origin(initial_bounds_.origin() +
|
| + visible_bounds.OffsetFromOrigin());
|
| + display_.ConvertFromVirtualToScreen(&new_widget_bounds);
|
| + }
|
| +
|
| // Update widget origin using the surface origin if the current location of
|
| // surface is being anchored to one side of the widget as a result of a
|
| // resize operation.
|
| @@ -1300,11 +1385,29 @@ void ShellSurface::UpdateWidgetBounds() {
|
| // should not result in a configure request.
|
| DCHECK(!ignore_window_bounds_changes_);
|
| ignore_window_bounds_changes_ = true;
|
| - if (widget_->GetWindowBoundsInScreen() != new_widget_bounds)
|
| - widget_->SetBounds(new_widget_bounds);
|
| + if (widget_->GetWindowBoundsInScreen() != new_widget_bounds) {
|
| + if (!move_resizer_) {
|
| + widget_->SetBounds(new_widget_bounds);
|
| + UpdateSurfaceBounds();
|
| + } else {
|
| + // Convert from screen to display coordinates.
|
| + gfx::Point origin = new_widget_bounds.origin();
|
| + wm::ConvertPointFromScreen(widget_->GetNativeWindow()->parent(), &origin);
|
| + new_widget_bounds.set_origin(origin);
|
| +
|
| + // Move the window relative to the current display.
|
| + widget_->GetNativeWindow()->SetBounds(new_widget_bounds);
|
| + UpdateSurfaceBounds();
|
| +
|
| + // Render phantom windows when beyond the current display.
|
| + move_resizer_->Drag(GetMouseLocation(), 0);
|
| + }
|
| + }
|
| +
|
| ignore_window_bounds_changes_ = false;
|
| +}
|
|
|
| - // A change to the widget size requires surface bounds to be re-adjusted.
|
| +void ShellSurface::UpdateSurfaceBounds() {
|
| surface_->window()->SetBounds(
|
| gfx::Rect(GetSurfaceOrigin(), surface_->window()->layer()->size()));
|
| }
|
| @@ -1320,10 +1423,11 @@ void ShellSurface::UpdateShadow() {
|
| } else {
|
| wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR);
|
|
|
| - // TODO(oshima): Adjust the coordinates from client screen to
|
| - // chromeos screen when multi displays are supported.
|
| gfx::Point origin = window->bounds().origin();
|
| gfx::Point shadow_origin = shadow_content_bounds_.origin();
|
| +
|
| + display_.ConvertFromVirtualToScreen(&shadow_origin);
|
| + wm::ConvertPointFromScreen(window->parent(), &shadow_origin);
|
| shadow_origin -= origin.OffsetFromOrigin();
|
| gfx::Rect shadow_bounds(shadow_origin, shadow_content_bounds_.size());
|
|
|
| @@ -1397,4 +1501,13 @@ void ShellSurface::UpdateShadow() {
|
| }
|
| }
|
|
|
| +gfx::Point ShellSurface::GetMouseLocation() const {
|
| + aura::Window* const root_window = widget_->GetNativeWindow()->GetRootWindow();
|
| + gfx::Point location =
|
| + root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
|
| + aura::Window::ConvertPointToTarget(
|
| + root_window, widget_->GetNativeWindow()->parent(), &location);
|
| + return location;
|
| +}
|
| +
|
| } // namespace exo
|
|
|