Chromium Code Reviews| Index: components/exo/shell_surface.cc |
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc |
| index 315de70cfa845207ce8afbf2d0e6c04766d20788..0aca3af36f20e4f89ddca6aa103a7ec1ae9f9148 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. |
| @@ -1051,6 +1092,7 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) { |
| if (!initial_bounds_.IsEmpty()) |
| window_state->set_allow_set_bounds_in_maximized(true); |
| + // Notify client of initial state. |
|
Daniele Castagna
2016/12/08 20:19:13
This can go away.
reveman
2016/12/11 07:14:04
Done.
|
| // Notify client of initial state if different than normal. |
| if (window_state->GetStateType() != ash::wm::WINDOW_STATE_TYPE_NORMAL && |
| !state_changed_callback_.is_null()) { |
| @@ -1065,13 +1107,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) == |
|
Daniele Castagna
2016/12/08 20:19:13
:( the animations were cool.
reveman
2016/12/11 07:14:04
sorry. maybe we'll enable them again in the future
|
| - 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 +1121,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 +1140,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 +1270,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 +1286,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 +1306,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 +1345,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 +1376,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 +1429,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 +1447,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 +1483,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); |
| } |
| } |