Index: components/exo/shell_surface.cc |
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc |
index 315de70cfa845207ce8afbf2d0e6c04766d20788..6598b78799ee67fc46d7fc43193080483c9e9968 100644 |
--- a/components/exo/shell_surface.cc |
+++ b/components/exo/shell_surface.cc |
@@ -7,6 +7,7 @@ |
#include <algorithm> |
#include "ash/aura/wm_window_aura.h" |
+#include "ash/common/frame/custom_frame_view_ash.h" |
#include "ash/common/shelf/wm_shelf.h" |
#include "ash/common/wm/window_resizer.h" |
#include "ash/common/wm/window_state.h" |
@@ -37,6 +38,7 @@ |
#include "ui/wm/core/shadow.h" |
#include "ui/wm/core/shadow_controller.h" |
#include "ui/wm/core/shadow_types.h" |
+#include "ui/wm/core/window_animations.h" |
#include "ui/wm/core/window_util.h" |
#if defined(OS_CHROMEOS) |
@@ -100,6 +102,15 @@ class CustomWindowTargeter : public aura::WindowTargeter { |
gfx::Point local_point = event.location(); |
+ if (window->parent()) { |
+ aura::Window::ConvertPointToTarget(window->parent(), window, |
+ &local_point); |
+ } |
+ |
+ int component = widget_->non_client_view()->NonClientHitTest(local_point); |
+ if (component != HTNOWHERE && component != HTCLIENT) |
+ return true; |
+ |
// If there is an underlay, test against it's bounds instead since it will |
// be equal or larger than the surface's bounds. |
aura::Window* shadow_underlay = |
@@ -107,16 +118,10 @@ class CustomWindowTargeter : public aura::WindowTargeter { |
widget_->widget_delegate()->GetContentsView()) |
->shadow_underlay(); |
if (shadow_underlay) { |
- if (window->parent()) |
- aura::Window::ConvertPointToTarget(window->parent(), shadow_underlay, |
- &local_point); |
+ aura::Window::ConvertPointToTarget(window, shadow_underlay, &local_point); |
return gfx::Rect(shadow_underlay->layer()->size()).Contains(local_point); |
} |
- if (window->parent()) |
- aura::Window::ConvertPointToTarget(window->parent(), window, |
- &local_point); |
- |
aura::Window::ConvertPointToTarget(window, surface->window(), &local_point); |
return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1))); |
} |
@@ -133,9 +138,8 @@ class CustomWindowTargeter : public aura::WindowTargeter { |
->shadow_underlay(); |
if (surface && event->IsLocatedEvent() && shadow_underlay) { |
gfx::Point local_point = event->AsLocatedEvent()->location(); |
- aura::Window::ConvertPointToTarget(window, surface->window(), |
- &local_point); |
- if (!surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1)))) |
+ int component = widget_->non_client_view()->NonClientHitTest(local_point); |
+ if (component == HTNOWHERE) |
return shadow_underlay; |
} |
return aura::WindowTargeter::FindTargetForEvent(root, event); |
@@ -333,12 +337,14 @@ ShellSurface::ShellSurface(Surface* surface, |
ShellSurface* parent, |
const gfx::Rect& initial_bounds, |
bool activatable, |
+ bool can_minimize, |
int container) |
: widget_(nullptr), |
surface_(surface), |
parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr), |
initial_bounds_(initial_bounds), |
activatable_(activatable), |
+ can_minimize_(can_minimize), |
container_(container) { |
WMHelper::GetInstance()->AddActivationObserver(this); |
surface_->SetSurfaceDelegate(this); |
@@ -354,6 +360,7 @@ ShellSurface::ShellSurface(Surface* surface) |
nullptr, |
gfx::Rect(), |
true, |
+ true, |
ash::kShellWindowId_DefaultContainer) {} |
ShellSurface::~ShellSurface() { |
@@ -578,9 +585,16 @@ void ShellSurface::SetGeometry(const gfx::Rect& geometry) { |
pending_geometry_ = geometry; |
} |
-void ShellSurface::SetRectangularShadow(const gfx::Rect& content_bounds) { |
- TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadow", "content_bounds", |
- content_bounds.ToString()); |
+void ShellSurface::SetRectangularShadow(bool enabled) { |
+ TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadow", "enabled", enabled); |
+ |
+ shadow_enabled_ = enabled; |
+} |
+ |
+void ShellSurface::SetRectangularShadowContentBounds( |
+ const gfx::Rect& content_bounds) { |
+ TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadowContentBounds", |
+ "content_bounds", content_bounds.ToString()); |
shadow_content_bounds_ = content_bounds; |
} |
@@ -589,7 +603,13 @@ void ShellSurface::SetRectangularShadowBackgroundOpacity(float opacity) { |
TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadowBackgroundOpacity", |
"opacity", opacity); |
- rectangular_shadow_background_opacity_ = opacity; |
+ shadow_background_opacity_ = opacity; |
+} |
+ |
+void ShellSurface::SetFrame(bool enabled) { |
+ TRACE_EVENT1("exo", "ShellSurface::SetFrame", "enabled", enabled); |
+ |
+ frame_enabled_ = enabled; |
} |
void ShellSurface::SetScale(double scale) { |
@@ -615,11 +635,10 @@ void ShellSurface::SetOrigin(const gfx::Point& origin) { |
initial_bounds_ = gfx::Rect(origin, gfx::Size(1, 1)); |
} |
-void ShellSurface::SetActivatable(bool activatable) { |
- TRACE_EVENT1("exo", "ShellSurface::SetActivatable", "activatable", |
- activatable); |
+void ShellSurface::SetContainer(int container) { |
+ TRACE_EVENT1("exo", "ShellSurface::SetContainer", "container", container); |
- activatable_ = activatable; |
+ container_ = container; |
} |
// static |
@@ -676,15 +695,12 @@ void ShellSurface::OnSurfaceCommit() { |
top_inset_height_ = pending_top_inset_height_; |
} |
- gfx::Point surface_origin = GetSurfaceOrigin(); |
- |
// System modal container is used by clients to implement overlay |
// windows using a single ShellSurface instance. If hit-test |
// region is empty, then it is non interactive window and won't be |
// activated. |
if (container_ == ash::kShellWindowId_SystemModalContainer) { |
- gfx::Rect hit_test_bounds = |
- surface_->GetHitTestBounds() + surface_origin.OffsetFromOrigin(); |
+ gfx::Rect hit_test_bounds = surface_->GetHitTestBounds(); |
// Prevent window from being activated when hit test bounds are empty. |
bool activatable = activatable_ && !hit_test_bounds.IsEmpty(); |
@@ -698,9 +714,13 @@ void ShellSurface::OnSurfaceCommit() { |
} |
} |
+ gfx::Rect client_view_bounds = |
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView(); |
+ |
// Update surface bounds. |
surface_->window()->SetBounds( |
- gfx::Rect(surface_origin, surface_->window()->layer()->size())); |
+ gfx::Rect(GetSurfaceOrigin() + client_view_bounds.OffsetFromOrigin(), |
+ surface_->window()->layer()->size())); |
// Update surface scale. |
if (pending_scale_ != scale_) { |
@@ -758,12 +778,15 @@ bool ShellSurface::CanResize() const { |
bool ShellSurface::CanMaximize() const { |
// Shell surfaces in system modal container cannot be maximized. |
- return container_ != ash::kShellWindowId_SystemModalContainer; |
+ if (container_ == ash::kShellWindowId_SystemModalContainer) |
+ return false; |
+ |
+ // Non-transient shell surfaces can be maximized. |
+ return !parent_; |
} |
bool ShellSurface::CanMinimize() const { |
- // Shell surfaces in system modal container cannot be minimized. |
- return container_ != ash::kShellWindowId_SystemModalContainer; |
+ return can_minimize_; |
} |
base::string16 ShellSurface::GetWindowTitle() const { |
@@ -793,6 +816,15 @@ views::View* ShellSurface::GetContentsView() { |
views::NonClientFrameView* ShellSurface::CreateNonClientFrameView( |
views::Widget* widget) { |
+ aura::Window* window = widget_->GetNativeWindow(); |
+ ash::wm::WindowState* window_state = ash::wm::GetWindowState(window); |
+ // Set delegate for handling of fullscreening. |
+ window_state->SetDelegate(std::unique_ptr<ash::wm::WindowStateDelegate>( |
+ new CustomWindowStateDelegate(widget_))); |
+ |
+ if (frame_enabled_) |
+ return new ash::CustomFrameViewAsh(widget); |
+ |
return new CustomFrameView(widget); |
} |
@@ -817,6 +849,10 @@ gfx::Size ShellSurface::GetPreferredSize() const { |
return surface_ ? surface_->window()->layer()->size() : gfx::Size(); |
} |
+gfx::Size ShellSurface::GetMinimumSize() const { |
+ return gfx::Size(1, 1); |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// ash::wm::WindowStateObserver overrides: |
@@ -877,8 +913,13 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window, |
pending_origin_config_offset_ += origin_offset; |
origin_ -= origin_offset; |
+ gfx::Rect client_view_bounds = |
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView(); |
+ |
+ // Update surface bounds. |
surface_->window()->SetBounds( |
- gfx::Rect(GetSurfaceOrigin(), surface_->window()->layer()->size())); |
+ gfx::Rect(GetSurfaceOrigin() + client_view_bounds.OffsetFromOrigin(), |
+ surface_->window()->layer()->size())); |
// The shadow size may be updated to match the widget. Change it back |
// to the shadow content size. |
@@ -1065,13 +1106,11 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) { |
// AutoHide shelf in fullscreen state. |
window_state->set_hide_shelf_when_fullscreen(false); |
- // Allow Ash to manage the position of a top-level shell surfaces if show |
- // state is one that allows auto positioning and |initial_bounds_| has |
- // not been set. |
- window_state->set_window_position_managed( |
- ash::wm::ToWindowShowState(ash::wm::WINDOW_STATE_TYPE_AUTO_POSITIONED) == |
- show_state && |
- initial_bounds_.IsEmpty()); |
+ // Fade visibility animations for non-activatable windows. |
+ if (!activatable_) { |
+ wm::SetWindowVisibilityAnimationType( |
+ window, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); |
+ } |
// Register close window accelerators. |
views::FocusManager* focus_manager = widget_->GetFocusManager(); |
@@ -1081,10 +1120,6 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) { |
ui::AcceleratorManager::kNormalPriority, this); |
} |
- // Set delegate for handling of fullscreening. |
- window_state->SetDelegate(std::unique_ptr<ash::wm::WindowStateDelegate>( |
- new CustomWindowStateDelegate(widget_))); |
- |
// Receive accessibility changes to update shadow underlay. |
WMHelper::GetInstance()->AddAccessibilityObserver(this); |
@@ -1104,21 +1139,29 @@ void ShellSurface::Configure() { |
gfx::Vector2d origin_offset = pending_origin_config_offset_; |
pending_origin_config_offset_ = gfx::Vector2d(); |
+ ash::wm::WindowState* window_state = |
+ ash::wm::GetWindowState(widget_->GetNativeWindow()); |
+ |
// If surface is being resized, save the resize direction. |
- int resize_component = |
- resizer_ ? resizer_->details().window_component : HTCAPTION; |
+ int resize_component = window_state->is_dragged() |
+ ? window_state->drag_details()->window_component |
+ : HTCAPTION; |
+ |
+ uint32_t serial = 0; |
+ if (!configure_callback_.is_null()) { |
+ const views::NonClientView* non_client_view = widget_->non_client_view(); |
+ serial = configure_callback_.Run( |
+ non_client_view->frame_view()->GetBoundsForClientView().size(), |
+ ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), |
+ IsResizing(), widget_->IsActive()); |
+ } |
- if (configure_callback_.is_null()) { |
+ if (!serial) { |
pending_origin_offset_ += origin_offset; |
pending_resize_component_ = resize_component; |
return; |
} |
- uint32_t serial = configure_callback_.Run( |
- widget_->GetWindowBoundsInScreen().size(), |
- ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), |
- IsResizing(), widget_->IsActive()); |
- |
// Apply origin offset and resize component at the first Commit() after this |
// configure request has been acknowledged. |
pending_configs_.push_back({serial, origin_offset, resize_component}); |
@@ -1226,10 +1269,12 @@ void ShellSurface::EndDrag(bool revert) { |
} |
bool ShellSurface::IsResizing() const { |
- if (!resizer_) |
+ ash::wm::WindowState* window_state = |
+ ash::wm::GetWindowState(widget_->GetNativeWindow()); |
+ if (!window_state->is_dragged()) |
return false; |
- return resizer_->details().bounds_change & |
+ return window_state->drag_details()->bounds_change & |
ash::WindowResizer::kBoundsChange_Resizes; |
} |
@@ -1240,17 +1285,17 @@ gfx::Rect ShellSurface::GetVisibleBounds() const { |
} |
gfx::Point ShellSurface::GetSurfaceOrigin() const { |
- gfx::Rect window_bounds = widget_->GetNativeWindow()->bounds(); |
- |
// If initial bounds were specified then surface origin is always relative |
// to those bounds. |
if (!initial_bounds_.IsEmpty()) { |
- gfx::Point origin = window_bounds.origin(); |
+ gfx::Point origin = widget_->GetNativeWindow()->bounds().origin(); |
wm::ConvertPointToScreen(widget_->GetNativeWindow()->parent(), &origin); |
return initial_bounds_.origin() - origin.OffsetFromOrigin(); |
} |
gfx::Rect visible_bounds = GetVisibleBounds(); |
+ gfx::Rect client_bounds = |
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView(); |
switch (resize_component_) { |
case HTCAPTION: |
return origin_ - visible_bounds.OffsetFromOrigin(); |
@@ -1260,16 +1305,16 @@ gfx::Point ShellSurface::GetSurfaceOrigin() const { |
return gfx::Point() - visible_bounds.OffsetFromOrigin(); |
case HTTOP: |
case HTTOPRIGHT: |
- return gfx::Point(0, window_bounds.height() - visible_bounds.height()) - |
+ return gfx::Point(0, client_bounds.height() - visible_bounds.height()) - |
visible_bounds.OffsetFromOrigin(); |
break; |
case HTLEFT: |
case HTBOTTOMLEFT: |
- return gfx::Point(window_bounds.width() - visible_bounds.width(), 0) - |
+ return gfx::Point(client_bounds.width() - visible_bounds.width(), 0) - |
visible_bounds.OffsetFromOrigin(); |
case HTTOPLEFT: |
- return gfx::Point(window_bounds.width() - visible_bounds.width(), |
- window_bounds.height() - visible_bounds.height()) - |
+ return gfx::Point(client_bounds.width() - visible_bounds.width(), |
+ client_bounds.height() - visible_bounds.height()) - |
visible_bounds.OffsetFromOrigin(); |
default: |
NOTREACHED(); |
@@ -1299,7 +1344,9 @@ void ShellSurface::UpdateWidgetBounds() { |
return; |
gfx::Rect visible_bounds = GetVisibleBounds(); |
- gfx::Rect new_widget_bounds = visible_bounds; |
+ gfx::Rect new_widget_bounds = |
+ widget_->non_client_view()->GetWindowBoundsForClientBounds( |
+ visible_bounds); |
// Avoid changing widget origin unless initial bounds were specified and |
// widget origin is always relative to it. |
@@ -1328,28 +1375,36 @@ void ShellSurface::UpdateWidgetBounds() { |
widget_->SetBounds(new_widget_bounds); |
ignore_window_bounds_changes_ = false; |
+ gfx::Rect client_view_bounds = |
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView(); |
+ |
// A change to the widget size requires surface bounds to be re-adjusted. |
surface_->window()->SetBounds( |
- gfx::Rect(GetSurfaceOrigin(), surface_->window()->layer()->size())); |
+ gfx::Rect(GetSurfaceOrigin() + client_view_bounds.OffsetFromOrigin(), |
+ surface_->window()->layer()->size())); |
} |
void ShellSurface::UpdateShadow() { |
if (!widget_) |
return; |
aura::Window* window = widget_->GetNativeWindow(); |
- if (shadow_content_bounds_.IsEmpty()) { |
+ if (!shadow_enabled_) { |
wm::SetShadowType(window, wm::SHADOW_TYPE_NONE); |
if (shadow_underlay_) |
shadow_underlay_->Hide(); |
} else { |
wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR); |
+ gfx::Rect shadow_content_bounds = shadow_content_bounds_; |
+ if (shadow_content_bounds.IsEmpty()) |
+ shadow_content_bounds = window->bounds(); |
+ |
// 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(); |
+ gfx::Point shadow_origin = shadow_content_bounds.origin(); |
shadow_origin -= origin.OffsetFromOrigin(); |
- gfx::Rect shadow_bounds(shadow_origin, shadow_content_bounds_.size()); |
+ gfx::Rect shadow_bounds(shadow_origin, shadow_content_bounds.size()); |
// Always create and show the underlay, even in maximized/fullscreen. |
if (!shadow_underlay_) { |
@@ -1373,7 +1428,7 @@ void ShellSurface::UpdateShadow() { |
WMHelper::GetInstance()->IsSpokenFeedbackEnabled() && |
widget_->IsActive(); |
- float shadow_underlay_opacity = rectangular_shadow_background_opacity_; |
+ float shadow_underlay_opacity = shadow_background_opacity_; |
// Put the black background layer behind the window if |
// 1) the window is in immersive fullscreen or is active with |
// spoken feedback enabled. |
@@ -1391,7 +1446,16 @@ void ShellSurface::UpdateShadow() { |
shadow_underlay_opacity = 1.0f; |
} |
- shadow_underlay_->SetBounds(shadow_bounds); |
+ gfx::Rect shadow_underlay_bounds = shadow_bounds; |
+ |
+ // Constrain the underlay bounds to the client area in case shell surface |
+ // frame is enabled. |
+ if (frame_enabled_) { |
+ shadow_underlay_bounds.Intersect( |
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView()); |
+ } |
+ |
+ shadow_underlay_->SetBounds(shadow_underlay_bounds); |
// TODO(oshima): Setting to the same value should be no-op. |
// crbug.com/642223. |
@@ -1418,6 +1482,10 @@ void ShellSurface::UpdateShadow() { |
} |
shadow_overlay_->SetBounds(shadow_bounds); |
shadow->SetContentBounds(gfx::Rect(shadow_bounds.size())); |
+ // Surfaces that can't be activated are usually menus and tooltips. Use a |
+ // small style shadow for them. |
+ if (!activatable_) |
+ shadow->SetStyle(wm::Shadow::STYLE_SMALL); |
} |
} |