Chromium Code Reviews| Index: components/exo/shell_surface.cc |
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc |
| index 8b61a9d121e7169dea7f1cf3e1f7be42053fc4b9..32aedd79ecaf13379294de27e36a7e7279cbfe06 100644 |
| --- a/components/exo/shell_surface.cc |
| +++ b/components/exo/shell_surface.cc |
| @@ -10,8 +10,10 @@ |
| #include "ash/common/shelf/wm_shelf.h" |
| #include "ash/common/wm/window_resizer.h" |
| #include "ash/common/wm/window_state.h" |
| +#include "ash/common/wm_shell.h" |
| #include "ash/common/wm_window.h" |
| #include "ash/public/cpp/shell_window_ids.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" |
| @@ -29,6 +31,8 @@ |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/accelerators/accelerator.h" |
| #include "ui/base/class_property.h" |
| +#include "ui/display/display.h" |
| +#include "ui/display/screen.h" |
| #include "ui/gfx/path.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/coordinate_conversion.h" |
| @@ -143,6 +147,27 @@ class CustomWindowTargeter : public aura::WindowTargeter { |
| DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter); |
| }; |
| +// Minimal WindowResizer that unlike DefaultWindowResizer does not handle |
| +// dragging and resizing windows. |
| +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(); } |
| + |
| + // Overridden from 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) |
| @@ -299,11 +324,14 @@ ShellSurface::ShellSurface(Surface* surface, |
| surface_(surface), |
| parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr), |
| bounds_mode_(bounds_mode), |
| + primary_display_id_( |
| + display::Screen::GetScreen()->GetPrimaryDisplay().id()), |
| origin_(origin), |
| activatable_(activatable), |
| can_minimize_(can_minimize), |
| container_(container) { |
| WMHelper::GetInstance()->AddActivationObserver(this); |
| + WMHelper::GetInstance()->AddDisplayConfigurationObserver(this); |
| surface_->SetSurfaceDelegate(this); |
| surface_->AddSurfaceObserver(this); |
| surface_->window()->Show(); |
| @@ -336,6 +364,7 @@ ShellSurface::~ShellSurface() { |
| widget_->CloseNow(); |
| } |
| WMHelper::GetInstance()->RemoveActivationObserver(this); |
| + WMHelper::GetInstance()->RemoveDisplayConfigurationObserver(this); |
| if (parent_) |
| parent_->RemoveObserver(this); |
| if (surface_) { |
| @@ -542,9 +571,9 @@ void ShellSurface::Move() { |
| switch (bounds_mode_) { |
| case BoundsMode::SHELL: |
| + case BoundsMode::CLIENT: |
| AttemptToStartDrag(HTCAPTION); |
| return; |
| - case BoundsMode::CLIENT: |
| case BoundsMode::FIXED: |
| return; |
| } |
| @@ -644,29 +673,7 @@ void ShellSurface::SetTopInset(int height) { |
| void ShellSurface::SetOrigin(const gfx::Point& origin) { |
| TRACE_EVENT1("exo", "ShellSurface::SetOrigin", "origin", origin.ToString()); |
| - if (origin == origin_) |
| - return; |
| - |
| - if (bounds_mode_ != BoundsMode::CLIENT) { |
| - origin_ = origin; |
| - return; |
| - } |
| - |
| - // If the origin changed, give the client a chance to adjust window positions |
| - // before switching to the new coordinate system. Retain the old origin by |
| - // reverting the origin delta until the next configure is acknowledged. |
| - gfx::Vector2d delta = origin - origin_; |
| - origin_offset_ -= delta; |
| - pending_origin_offset_accumulator_ += delta; |
| - |
| origin_ = origin; |
| - |
| - if (widget_) { |
| - UpdateWidgetBounds(); |
| - UpdateShadow(); |
| - } |
| - |
| - Configure(); |
| } |
| void ShellSurface::SetActivatable(bool activatable) { |
| @@ -913,8 +920,8 @@ void ShellSurface::OnPreWindowStateTypeChange( |
| // the client to inform us that a frame has taken the state change into |
| // account and without this cross-fade animations are unreliable. |
| - // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the |
| - // client, the configure callback does not yet support window state changes. |
| + // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does |
| + // not yet support window state changes. See crbug.com/699746. |
| if (configure_callback_.is_null() || bounds_mode_ == BoundsMode::CLIENT) |
| scoped_animations_disabled_.reset(new ScopedAnimationsDisabled(this)); |
| } |
| @@ -947,8 +954,8 @@ void ShellSurface::OnPostWindowStateTypeChange( |
| void ShellSurface::OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| - // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the |
| - // client, the configure callback does not yet support resizing. |
| + // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does not |
| + // yet support resizing. See crbug.com/699746. |
| if (bounds_mode_ == BoundsMode::CLIENT) |
| return; |
| @@ -1013,6 +1020,38 @@ void ShellSurface::OnAccessibilityModeChanged() { |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| +// WMHelper::DisplayConfigurationObserver overrides: |
| + |
| +void ShellSurface::OnDisplayConfigurationChanged() { |
| + if (bounds_mode_ != BoundsMode::CLIENT) |
| + return; |
| + |
| + const display::Screen* screen = display::Screen::GetScreen(); |
| + int64_t primary_display_id = screen->GetPrimaryDisplay().id(); |
| + if (primary_display_id == primary_display_id_) |
| + return; |
| + |
| + display::Display primary_display; |
|
reveman
2017/03/15 21:26:14
nit: maybe s/primary_display/old_primary_display/
Dominik Laskowski
2017/03/15 21:43:56
Done.
|
| + if (screen->GetDisplayWithDisplayId(primary_display_id_, &primary_display)) { |
| + // Give the client a chance to adjust window positions before switching to |
| + // the new coordinate system. Retain the old origin by reverting the origin |
| + // delta until the next configure is acknowledged. |
| + gfx::Vector2d delta = gfx::Point() - primary_display.bounds().origin(); |
| + origin_offset_ -= delta; |
| + pending_origin_offset_accumulator_ += delta; |
| + |
| + if (widget_) { |
| + UpdateWidgetBounds(); |
| + UpdateShadow(); |
| + } |
| + |
| + Configure(); |
| + } |
| + |
| + primary_display_id_ = primary_display_id; |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| // ui::EventHandler overrides: |
| void ShellSurface::OnKeyEvent(ui::KeyEvent* event) { |
| @@ -1021,6 +1060,9 @@ void ShellSurface::OnKeyEvent(ui::KeyEvent* event) { |
| return; |
| } |
| + // TODO(domlaskowski): For BoundsMode::CLIENT, synchronize the revert with the |
| + // client, instead of having the client destroy the window on VKEY_ESCAPE. See |
| + // crbug.com/699746. |
| if (event->type() == ui::ET_KEY_PRESSED && |
| event->key_code() == ui::VKEY_ESCAPE) { |
| EndDrag(true /* revert */); |
| @@ -1050,6 +1092,9 @@ void ShellSurface::OnMouseEvent(ui::MouseEvent* event) { |
| switch (event->type()) { |
| case ui::ET_MOUSE_DRAGGED: { |
| + if (bounds_mode_ == BoundsMode::CLIENT) |
| + break; |
| + |
| gfx::Point location(event->location()); |
| aura::Window::ConvertPointToTarget(widget_->GetNativeWindow(), |
| widget_->GetNativeWindow()->parent(), |
| @@ -1203,11 +1248,11 @@ void ShellSurface::Configure() { |
| serial = configure_callback_.Run( |
| non_client_view->frame_view()->GetBoundsForClientView().size(), |
| ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), |
| - IsResizing(), widget_->IsActive(), origin_); |
| + IsResizing(), widget_->IsActive(), origin_offset); |
| } else { |
| serial = configure_callback_.Run(gfx::Size(), |
| ash::wm::WINDOW_STATE_TYPE_NORMAL, false, |
| - false, origin_); |
| + false, origin_offset); |
| } |
| } |
| @@ -1225,6 +1270,16 @@ void ShellSurface::Configure() { |
| << pending_configs_.size(); |
| } |
| +aura::Window* ShellSurface::GetDragWindow() const { |
| + if (bounds_mode_ == BoundsMode::SHELL) |
|
reveman
2017/03/15 21:26:14
nit: switch statement here without a "default" cas
Dominik Laskowski
2017/03/15 21:43:56
Done.
|
| + return widget_->GetNativeWindow(); |
| + |
| + if (bounds_mode_ == BoundsMode::CLIENT && surface_) |
| + return surface_->window(); |
| + |
| + return nullptr; |
| +} |
| + |
| void ShellSurface::AttemptToStartDrag(int component) { |
| DCHECK(widget_); |
| @@ -1232,69 +1287,81 @@ void ShellSurface::AttemptToStartDrag(int component) { |
| if (resizer_) |
| return; |
| - if (widget_->GetNativeWindow()->HasCapture()) |
| + aura::Window* window = GetDragWindow(); |
| + if (!window || window->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); |
| - DCHECK(cursor_client); |
| + if (bounds_mode_ == BoundsMode::SHELL) { |
| + // 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(window->GetRootWindow()); |
| + DCHECK(cursor_client); |
| + |
| + switch (component) { |
| + case HTCAPTION: |
| + cursor_client->SetCursor(ui::kCursorPointer); |
| + break; |
| + case HTTOP: |
| + cursor_client->SetCursor(ui::kCursorNorthResize); |
| + break; |
| + case HTTOPRIGHT: |
| + cursor_client->SetCursor(ui::kCursorNorthEastResize); |
| + break; |
| + case HTRIGHT: |
| + cursor_client->SetCursor(ui::kCursorEastResize); |
| + break; |
| + case HTBOTTOMRIGHT: |
| + cursor_client->SetCursor(ui::kCursorSouthEastResize); |
| + break; |
| + case HTBOTTOM: |
| + cursor_client->SetCursor(ui::kCursorSouthResize); |
| + break; |
| + case HTBOTTOMLEFT: |
| + cursor_client->SetCursor(ui::kCursorSouthWestResize); |
| + break; |
| + case HTLEFT: |
| + cursor_client->SetCursor(ui::kCursorWestResize); |
| + break; |
| + case HTTOPLEFT: |
| + cursor_client->SetCursor(ui::kCursorNorthWestResize); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| - switch (component) { |
| - case HTCAPTION: |
| - cursor_client->SetCursor(ui::kCursorPointer); |
| - break; |
| - case HTTOP: |
| - cursor_client->SetCursor(ui::kCursorNorthResize); |
| - break; |
| - case HTTOPRIGHT: |
| - cursor_client->SetCursor(ui::kCursorNorthEastResize); |
| - break; |
| - case HTRIGHT: |
| - cursor_client->SetCursor(ui::kCursorEastResize); |
| - break; |
| - case HTBOTTOMRIGHT: |
| - cursor_client->SetCursor(ui::kCursorSouthEastResize); |
| - break; |
| - case HTBOTTOM: |
| - cursor_client->SetCursor(ui::kCursorSouthResize); |
| - break; |
| - case HTBOTTOMLEFT: |
| - cursor_client->SetCursor(ui::kCursorSouthWestResize); |
| - break; |
| - case HTLEFT: |
| - cursor_client->SetCursor(ui::kCursorWestResize); |
| - break; |
| - case HTTOPLEFT: |
| - cursor_client->SetCursor(ui::kCursorNorthWestResize); |
| - break; |
| - default: |
| - NOTREACHED(); |
| - break; |
| - } |
| + resizer_ = ash::CreateWindowResizer(ash::WmWindow::Get(window), |
| + GetMouseLocation(), component, |
| + aura::client::WINDOW_MOVE_SOURCE_MOUSE); |
| + if (!resizer_) |
| + return; |
| - resizer_ = ash::CreateWindowResizer( |
| - ash::WmWindow::Get(widget_->GetNativeWindow()), drag_location, component, |
| - aura::client::WINDOW_MOVE_SOURCE_MOUSE); |
| - if (!resizer_) |
| - return; |
| + // Apply pending origin offsets and resize direction before starting a |
| + // new resize operation. These can still be pending if the client has |
| + // acknowledged the configure request but not yet called Commit(). |
| + origin_offset_ += pending_origin_offset_; |
| + pending_origin_offset_ = gfx::Vector2d(); |
| + resize_component_ = pending_resize_component_; |
| + } else { |
| + DCHECK(bounds_mode_ == BoundsMode::CLIENT); |
| - // Apply pending origin offsets and resize direction before starting a new |
| - // resize operation. These can still be pending if the client has acknowledged |
| - // the configure request but not yet called Commit(). |
| - origin_offset_ += pending_origin_offset_; |
| - pending_origin_offset_ = gfx::Vector2d(); |
| - resize_component_ = pending_resize_component_; |
| + ash::wm::WindowState* window_state = |
| + ash::wm::GetWindowState(widget_->GetNativeWindow()); |
| + DCHECK(!window_state->drag_details()); |
| + DCHECK(component == HTCAPTION); |
| + window_state->CreateDragDetails(GetMouseLocation(), component, |
| + aura::client::WINDOW_MOVE_SOURCE_MOUSE); |
| + |
| + // Chained with a CustomWindowResizer, DragWindowResizer does not handle |
| + // dragging. It only renders phantom windows and moves the window to the |
| + // target root window when dragging ends. |
| + resizer_.reset(ash::DragWindowResizer::Create( |
| + new CustomWindowResizer(window_state), window_state)); |
| + } |
| WMHelper::GetInstance()->AddPreTargetHandler(this); |
| - widget_->GetNativeWindow()->SetCapture(); |
| + window->SetCapture(); |
| // Notify client that resizing state has changed. |
| if (IsResizing()) |
| @@ -1305,6 +1372,10 @@ void ShellSurface::EndDrag(bool revert) { |
| DCHECK(widget_); |
| DCHECK(resizer_); |
| + aura::Window* window = GetDragWindow(); |
| + DCHECK(window); |
| + DCHECK(window->HasCapture()); |
| + |
| bool was_resizing = IsResizing(); |
| if (revert) |
| @@ -1313,7 +1384,7 @@ void ShellSurface::EndDrag(bool revert) { |
| resizer_->CompleteDrag(); |
| WMHelper::GetInstance()->RemovePreTargetHandler(this); |
| - widget_->GetNativeWindow()->ReleaseCapture(); |
| + window->ReleaseCapture(); |
| resizer_.reset(); |
| // Notify client that resizing state has changed. |
| @@ -1426,8 +1497,32 @@ 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); |
| + const gfx::Rect widget_bounds = widget_->GetWindowBoundsInScreen(); |
| + if (widget_bounds != new_widget_bounds) { |
| + if (bounds_mode_ != BoundsMode::CLIENT || !resizer_) { |
| + widget_->SetBounds(new_widget_bounds); |
| + UpdateSurfaceBounds(); |
| + } else { |
| + // TODO(domlaskowski): Synchronize window state transitions with the |
| + // client, and abort client-side dragging on transition to fullscreen. See |
| + // crbug.com/699746. |
| + DLOG_IF(ERROR, widget_bounds.size() != new_widget_bounds.size()) |
| + << "Window size changed during client-driven drag"; |
| + |
| + // 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. |
| + resizer_->Drag(GetMouseLocation(), 0); |
| + } |
| + } |
| + |
| ignore_window_bounds_changes_ = false; |
| } |
| @@ -1591,4 +1686,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 |