| Index: components/exo/shell_surface.cc
|
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
|
| index 8b61a9d121e7169dea7f1cf3e1f7be42053fc4b9..7016042a4f8faee91424ac3e8eaa6c03a45f1579 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,39 @@ 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 old_primary_display;
|
| + if (screen->GetDisplayWithDisplayId(primary_display_id_,
|
| + &old_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() - old_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 +1061,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 +1093,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 +1249,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 +1271,22 @@ void ShellSurface::Configure() {
|
| << pending_configs_.size();
|
| }
|
|
|
| +aura::Window* ShellSurface::GetDragWindow() const {
|
| + switch (bounds_mode_) {
|
| + case BoundsMode::SHELL:
|
| + return widget_->GetNativeWindow();
|
| +
|
| + case BoundsMode::CLIENT:
|
| + return surface_ ? surface_->window() : nullptr;
|
| +
|
| + case BoundsMode::FIXED:
|
| + return nullptr;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return nullptr;
|
| +}
|
| +
|
| void ShellSurface::AttemptToStartDrag(int component) {
|
| DCHECK(widget_);
|
|
|
| @@ -1232,69 +1294,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 +1379,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 +1391,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 +1504,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 +1693,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
|
|
|