Chromium Code Reviews| Index: components/exo/shell_surface.cc |
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc |
| index 2027afdc95cefa71592fedd06a1681c7bc6043ee..e3a5ea0448223ad537651b8ff0f2b6b991f1810c 100644 |
| --- a/components/exo/shell_surface.cc |
| +++ b/components/exo/shell_surface.cc |
| @@ -15,6 +15,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" |
| @@ -23,6 +24,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" |
| @@ -188,6 +190,23 @@ 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(); } |
| + |
|
oshima
2016/10/12 01:56:54
// ash::WindowResizer:
Dominik Laskowski
2016/10/13 03:21:17
Done.
|
| + void Drag(const gfx::Point& location, int event_flags) override {} |
| + void CompleteDrag() override {} |
| + void RevertDrag() override {} |
| + |
| + private: |
| + ash::WmShell* const shell_; |
|
oshima
2016/10/12 01:56:54
DISALLOW_COPY_AND_ASSIGN
Dominik Laskowski
2016/10/13 03:21:17
Done.
|
| +}; |
| + |
| class ShellSurfaceWidget : public views::Widget { |
| public: |
| explicit ShellSurfaceWidget(ShellSurface* shell_surface) |
| @@ -335,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(); |
| @@ -355,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, |
| @@ -364,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); |
| @@ -374,6 +396,7 @@ ShellSurface::~ShellSurface() { |
| widget_->CloseNow(); |
| } |
| WMHelper::GetInstance()->RemoveActivationObserver(this); |
| + WMHelper::GetInstance()->RemoveShellObserver(this); |
| if (parent_) |
| parent_->RemoveObserver(this); |
| if (surface_) { |
| @@ -474,6 +497,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); |
| @@ -688,9 +746,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_) { |
| @@ -720,8 +776,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); |
| @@ -761,8 +816,7 @@ base::string16 ShellSurface::GetWindowTitle() const { |
| } |
| void ShellSurface::WindowClosing() { |
| - if (resizer_) |
| - EndDrag(true /* revert */); |
| + EndDragOrMove(true /* revert */); |
| SetEnabled(false); |
| widget_ = nullptr; |
| shadow_overlay_ = nullptr; |
| @@ -824,6 +878,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 |
| @@ -875,8 +931,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. |
| @@ -907,6 +962,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_); |
| @@ -916,6 +974,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; |
| +} |
|
oshima
2016/10/12 01:56:54
Can you test what happens when display configurati
Dominik Laskowski
2016/10/13 03:21:17
In general, this edge case is broken even for Chro
oshima
2016/10/17 17:22:58
That's a separate issue. When display configuraito
Dominik Laskowski
2016/10/18 21:22:56
Sorry, I misread that as changing the display conf
|
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| // ui::EventHandler overrides: |
| void ShellSurface::OnKeyEvent(ui::KeyEvent* event) { |
| @@ -1012,6 +1082,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. |
| @@ -1125,16 +1196,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) { |
| @@ -1171,7 +1236,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; |
| @@ -1213,6 +1278,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; |
| @@ -1232,8 +1304,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_) { |
| @@ -1275,15 +1351,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 |
| @@ -1291,6 +1367,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. |
| @@ -1305,11 +1387,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())); |
| } |
| @@ -1325,10 +1425,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()); |
| @@ -1403,4 +1504,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 |