| 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);
|
| }
|
| }
|
|
|
|
|