Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(944)

Unified Diff: components/exo/shell_surface.cc

Issue 2645663004: exo: Initial support for multiple displays in ARC (Closed)
Patch Set: Rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/exo/shell_surface.cc
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 3f5a1cf4ef103d7cc54bf6619807f14a4e973a51..445657cc00f36fdd8ca3a743def25c7ee2a51c6a 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -14,6 +14,7 @@
#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"
@@ -188,6 +189,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)
@@ -390,6 +411,9 @@ ShellSurface::~ShellSurface() {
surface_->RemoveSurfaceObserver(this);
}
WMHelper::GetInstance()->RemoveAccessibilityObserver(this);
+
+ if (!destroyed_callback_.is_null())
+ destroyed_callback_.Run();
}
void ShellSurface::AcknowledgeConfigure(uint32_t serial) {
@@ -414,8 +438,10 @@ void ShellSurface::AcknowledgeConfigure(uint32_t serial) {
break;
}
- if (widget_)
+ if (widget_) {
UpdateWidgetBounds();
+ UpdateShadow();
+ }
}
void ShellSurface::SetParent(ShellSurface* parent) {
@@ -567,7 +593,7 @@ void ShellSurface::SetApplicationId(const std::string& application_id) {
void ShellSurface::Move() {
TRACE_EVENT0("exo", "ShellSurface::Move");
- if (!widget_)
+ if (!widget_ || resizer_)
return;
switch (bounds_mode_) {
@@ -575,6 +601,8 @@ void ShellSurface::Move() {
AttemptToStartDrag(HTCAPTION);
return;
case BoundsMode::CLIENT:
+ AttemptToStartClientDrag();
+ return;
case BoundsMode::FIXED:
return;
}
@@ -585,7 +613,7 @@ void ShellSurface::Move() {
void ShellSurface::Resize(int component) {
TRACE_EVENT1("exo", "ShellSurface::Resize", "component", component);
- if (!widget_)
+ if (!widget_ || resizer_)
return;
switch (bounds_mode_) {
@@ -674,7 +702,25 @@ void ShellSurface::SetTopInset(int height) {
void ShellSurface::SetOrigin(const gfx::Point& origin) {
TRACE_EVENT1("exo", "ShellSurface::SetOrigin", "origin", origin.ToString());
+ const gfx::Point old_origin = origin_;
origin_ = origin;
+
+ if (bounds_mode_ != BoundsMode::CLIENT || origin == old_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.
+ const gfx::Vector2d delta = origin - old_origin;
+ origin_offset_ -= delta;
+ pending_origin_offset_accumulator_ += delta;
+
+ if (widget_) {
+ UpdateWidgetBounds();
+ UpdateShadow();
+ }
+
+ Configure();
}
void ShellSurface::SetActivatable(bool activatable) {
@@ -721,10 +767,12 @@ void ShellSurface::OnSurfaceCommit() {
if (enabled() && !widget_) {
// Defer widget creation until surface contains some contents.
- if (surface_->content_size().IsEmpty())
+ if (surface_->content_size().IsEmpty()) {
Configure();
- else
- CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
+ return;
+ }
+
+ CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
}
// Apply the accumulated pending origin offset to reflect acknowledged
@@ -919,7 +967,10 @@ void ShellSurface::OnPreWindowStateTypeChange(
// cross-fade animations. The configure callback provides a mechanism for
// the client to inform us that a frame has taken the state change into
// account and without this cross-fade animations are unreliable.
- if (configure_callback_.is_null())
+
+ // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the
+ // client, the configure callback does not yet support window state changes.
+ if (configure_callback_.is_null() || bounds_mode_ == BoundsMode::CLIENT)
scoped_animations_disabled_.reset(new ScopedAnimationsDisabled(this));
}
}
@@ -951,7 +1002,8 @@ void ShellSurface::OnPostWindowStateTypeChange(
void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- if (!widget_ || !surface_ || ignore_window_bounds_changes_)
+ if (bounds_mode_ == BoundsMode::CLIENT || !widget_ || !surface_ ||
+ ignore_window_bounds_changes_)
return;
if (window == widget_->GetNativeWindow()) {
@@ -1020,7 +1072,8 @@ void ShellSurface::OnKeyEvent(ui::KeyEvent* event) {
return;
}
- if (event->type() == ui::ET_KEY_PRESSED &&
+ if (bounds_mode_ == BoundsMode::SHELL &&
+ event->type() == ui::ET_KEY_PRESSED &&
event->key_code() == ui::VKEY_ESCAPE) {
EndDrag(true /* revert */);
}
@@ -1049,6 +1102,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(),
@@ -1202,10 +1258,11 @@ void ShellSurface::Configure() {
serial = configure_callback_.Run(
non_client_view->frame_view()->GetBoundsForClientView().size(),
ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(),
- IsResizing(), widget_->IsActive());
+ IsResizing(), widget_->IsActive(), origin_);
} else {
- serial = configure_callback_.Run(
- gfx::Size(), ash::wm::WINDOW_STATE_TYPE_NORMAL, false, false);
+ serial = configure_callback_.Run(gfx::Size(),
+ ash::wm::WINDOW_STATE_TYPE_NORMAL, false,
+ false, origin_);
}
}
@@ -1226,23 +1283,13 @@ void ShellSurface::Configure() {
void ShellSurface::AttemptToStartDrag(int component) {
DCHECK(widget_);
- // Cannot start another drag if one is already taking place.
- if (resizer_)
- return;
-
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) {
@@ -1279,8 +1326,8 @@ void ShellSurface::AttemptToStartDrag(int component) {
}
resizer_ = ash::CreateWindowResizer(
- ash::WmWindow::Get(widget_->GetNativeWindow()), drag_location, component,
- aura::client::WINDOW_MOVE_SOURCE_MOUSE);
+ ash::WmWindow::Get(widget_->GetNativeWindow()), GetMouseLocation(),
+ component, aura::client::WINDOW_MOVE_SOURCE_MOUSE);
if (!resizer_)
return;
@@ -1299,26 +1346,63 @@ void ShellSurface::AttemptToStartDrag(int component) {
Configure();
}
+void ShellSurface::AttemptToStartClientDrag() {
+ DCHECK(widget_);
+
+ if (surface_->window()->HasCapture())
+ 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.
+ resizer_.reset(ash::DragWindowResizer::Create(
+ new CustomWindowResizer(window_state), window_state));
+
+ WMHelper::GetInstance()->AddPreTargetHandler(this);
+ surface_->window()->SetCapture();
+}
+
void ShellSurface::EndDrag(bool revert) {
DCHECK(widget_);
DCHECK(resizer_);
- bool was_resizing = IsResizing();
+ switch (bounds_mode_) {
+ case BoundsMode::SHELL: {
+ bool was_resizing = IsResizing();
+
+ EndDrag(widget_->GetNativeWindow(), revert);
+
+ // Notify client that resizing state has changed.
+ if (was_resizing)
+ Configure();
+
+ UpdateWidgetBounds();
+ return;
+ }
+ case BoundsMode::CLIENT:
+ EndDrag(surface_->window(), revert);
+ return;
+ case BoundsMode::FIXED:
+ break;
+ }
+
+ NOTREACHED();
+}
+void ShellSurface::EndDrag(aura::Window* window, bool revert) {
if (revert)
resizer_->RevertDrag();
else
resizer_->CompleteDrag();
WMHelper::GetInstance()->RemovePreTargetHandler(this);
- widget_->GetNativeWindow()->ReleaseCapture();
+ window->ReleaseCapture();
resizer_.reset();
-
- // Notify client that resizing state has changed.
- if (was_resizing)
- Configure();
-
- UpdateWidgetBounds();
}
bool ShellSurface::IsResizing() const {
@@ -1341,7 +1425,8 @@ gfx::Point ShellSurface::GetSurfaceOrigin() const {
// For client-positioned shell surfaces, the surface origin corresponds to the
// widget position relative to the origin specified by the client. Since the
// surface is positioned relative to the widget, negate this vector to align
- // the surface with the widget.
+ // the surface with the widget. Note that the widget position must have been
+ // adjusted by the |origin_offset_| prior to this call.
if (bounds_mode_ != BoundsMode::SHELL) {
gfx::Point position = widget_->GetNativeWindow()->bounds().origin();
wm::ConvertPointToScreen(widget_->GetNativeWindow()->parent(), &position);
@@ -1404,6 +1489,9 @@ void ShellSurface::UpdateWidgetBounds() {
switch (bounds_mode_) {
case BoundsMode::CLIENT:
+ // Position is relative to the latest origin acknowledged by the client.
+ new_widget_bounds -= origin_offset_;
+ break;
case BoundsMode::FIXED:
// Position is relative to the origin.
new_widget_bounds += origin_.OffsetFromOrigin();
@@ -1429,8 +1517,31 @@ 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.
+ LOG_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;
}
@@ -1466,11 +1577,9 @@ void ShellSurface::UpdateShadow() {
}
}
- // 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();
- shadow_origin -= origin.OffsetFromOrigin();
+ gfx::Point shadow_origin = shadow_content_bounds.origin() - origin_offset_;
+ wm::ConvertPointFromScreen(window->parent(), &shadow_origin);
+ shadow_origin -= window->bounds().OffsetFromOrigin();
gfx::Rect shadow_bounds(shadow_origin, shadow_content_bounds.size());
// Always create and show the underlay, even in maximized/fullscreen.
@@ -1575,4 +1684,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

Powered by Google App Engine
This is Rietveld 408576698