| Index: components/exo/shell_surface.cc
|
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
|
| index 465477e79c488da48e2b777eaafd631ae51591a8..2027afdc95cefa71592fedd06a1681c7bc6043ee 100644
|
| --- a/components/exo/shell_surface.cc
|
| +++ b/components/exo/shell_surface.cc
|
| @@ -4,9 +4,13 @@
|
|
|
| #include "components/exo/shell_surface.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "ash/aura/wm_window_aura.h"
|
| +#include "ash/common/accessibility_delegate.h"
|
| #include "ash/common/shelf/wm_shelf.h"
|
| #include "ash/common/shell_window_ids.h"
|
| +#include "ash/common/system/tray/system_tray_notifier.h"
|
| #include "ash/common/wm/window_resizer.h"
|
| #include "ash/common/wm/window_state.h"
|
| #include "ash/common/wm/window_state_delegate.h"
|
| @@ -37,6 +41,10 @@
|
| #include "ui/wm/core/shadow_types.h"
|
| #include "ui/wm/core/window_util.h"
|
|
|
| +#if defined(OS_CHROMEOS)
|
| +#include "chromeos/audio/chromeos_sounds.h"
|
| +#endif
|
| +
|
| DECLARE_WINDOW_PROPERTY_TYPE(std::string*)
|
|
|
| namespace exo {
|
| @@ -87,7 +95,7 @@ class CustomFrameView : public views::NonClientFrameView {
|
|
|
| class CustomWindowTargeter : public aura::WindowTargeter {
|
| public:
|
| - CustomWindowTargeter() {}
|
| + CustomWindowTargeter(views::Widget* widget) : widget_(widget) {}
|
| ~CustomWindowTargeter() override {}
|
|
|
| // Overridden from aura::WindowTargeter:
|
| @@ -98,6 +106,20 @@ class CustomWindowTargeter : public aura::WindowTargeter {
|
| return false;
|
|
|
| gfx::Point local_point = event.location();
|
| +
|
| + // 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 =
|
| + static_cast<ShellSurface*>(
|
| + widget_->widget_delegate()->GetContentsView())
|
| + ->shadow_underlay();
|
| + if (shadow_underlay) {
|
| + if (window->parent())
|
| + aura::Window::ConvertPointToTarget(window->parent(), 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);
|
| @@ -106,7 +128,29 @@ class CustomWindowTargeter : public aura::WindowTargeter {
|
| return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1)));
|
| }
|
|
|
| + ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
|
| + ui::Event* event) override {
|
| + aura::Window* window = static_cast<aura::Window*>(root);
|
| + Surface* surface = ShellSurface::GetMainSurface(window);
|
| +
|
| + // Send events which are outside of the surface's bounds to the underlay.
|
| + aura::Window* shadow_underlay =
|
| + static_cast<ShellSurface*>(
|
| + widget_->widget_delegate()->GetContentsView())
|
| + ->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))))
|
| + return shadow_underlay;
|
| + }
|
| + return aura::WindowTargeter::FindTargetForEvent(root, event);
|
| + }
|
| +
|
| private:
|
| + views::Widget* const widget_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
|
| };
|
|
|
| @@ -166,6 +210,42 @@ class ShellSurfaceWidget : public views::Widget {
|
| DISALLOW_COPY_AND_ASSIGN(ShellSurfaceWidget);
|
| };
|
|
|
| +class ShadowUnderlayEventHandler : public ui::EventHandler {
|
| + public:
|
| + ShadowUnderlayEventHandler() {}
|
| + ~ShadowUnderlayEventHandler() override {}
|
| +
|
| + // Overridden from ui::EventHandler:
|
| + void OnEvent(ui::Event* event) override {
|
| + // If the event is targeted at the underlay, it means the user has made an
|
| + // interaction that is outside the surface's bounds and we want to capture
|
| + // it (usually when in spoken feedback mode). Handle the event (to prevent
|
| + // behind-windows from receiving it) and play an earcon to notify the user.
|
| + if (event->IsLocatedEvent()) {
|
| +#if defined(OS_CHROMEOS)
|
| + const ui::EventType kEarconEventTypes[] = {ui::ET_MOUSE_PRESSED,
|
| + ui::ET_MOUSEWHEEL,
|
| + ui::ET_TOUCH_PRESSED,
|
| + ui::ET_POINTER_DOWN,
|
| + ui::ET_POINTER_WHEEL_CHANGED,
|
| + ui::ET_GESTURE_BEGIN,
|
| + ui::ET_SCROLL,
|
| + ui::ET_SCROLL_FLING_START};
|
| + bool is_earcon_event_type =
|
| + std::find(std::begin(kEarconEventTypes), std::end(kEarconEventTypes),
|
| + event->type()) != std::end(kEarconEventTypes);
|
| + if (is_earcon_event_type)
|
| + ash::WmShell::Get()->accessibility_delegate()->PlayEarcon(
|
| + chromeos::SOUND_VOLUME_ADJUST);
|
| +#endif
|
| + event->SetHandled();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(ShadowUnderlayEventHandler);
|
| +};
|
| +
|
| } // namespace
|
|
|
| // Helper class used to coalesce a number of changes into one "configure"
|
| @@ -302,6 +382,8 @@ ShellSurface::~ShellSurface() {
|
| surface_->SetSurfaceDelegate(nullptr);
|
| surface_->RemoveSurfaceObserver(this);
|
| }
|
| + ash::WmShell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(
|
| + this);
|
| }
|
|
|
| void ShellSurface::AcknowledgeConfigure(uint32_t serial) {
|
| @@ -726,6 +808,14 @@ gfx::Size ShellSurface::GetPreferredSize() const {
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| +// ash::AccessibilityObserver overrides:
|
| +
|
| +void ShellSurface::OnAccessibilityModeChanged(
|
| + ash::AccessibilityNotificationVisibility) {
|
| + UpdateShadow();
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| // ash::wm::WindowStateObserver overrides:
|
|
|
| void ShellSurface::OnPreWindowStateTypeChange(
|
| @@ -821,6 +911,7 @@ void ShellSurface::OnWindowActivated(
|
| lost_active == widget_->GetNativeWindow()) {
|
| DCHECK(activatable_);
|
| Configure();
|
| + UpdateShadow();
|
| }
|
| }
|
|
|
| @@ -936,7 +1027,7 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
|
| aura::Window* window = widget_->GetNativeWindow();
|
| window->SetName("ExoShellSurface");
|
| window->AddChild(surface_->window());
|
| - window->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter));
|
| + window->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter(widget_)));
|
| SetApplicationId(window, &application_id_);
|
| SetMainSurface(window, surface_);
|
|
|
| @@ -982,6 +1073,9 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
|
| window_state->SetDelegate(std::unique_ptr<ash::wm::WindowStateDelegate>(
|
| new CustomWindowStateDelegate(widget_)));
|
|
|
| + // Receive accessibility changes to update shadow underlay.
|
| + ash::WmShell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
|
| +
|
| // Show widget next time Commit() is called.
|
| pending_show_widget_ = true;
|
| }
|
| @@ -1241,8 +1335,10 @@ void ShellSurface::UpdateShadow() {
|
| // Always create and show the underlay, even in maximized/fullscreen.
|
| if (!shadow_underlay_) {
|
| shadow_underlay_ = new aura::Window(nullptr);
|
| + shadow_underlay_event_handler_ =
|
| + base::MakeUnique<ShadowUnderlayEventHandler>();
|
| + shadow_underlay_->SetTargetHandler(shadow_underlay_event_handler_.get());
|
| DCHECK(shadow_underlay_->owned_by_parent());
|
| - shadow_underlay_->set_ignore_events(true);
|
| // Ensure the background area inside the shadow is solid black.
|
| // Clients that provide translucent contents should not be using
|
| // rectangular shadows as this method requires opaque contents to
|
| @@ -1254,16 +1350,22 @@ void ShellSurface::UpdateShadow() {
|
| window->StackChildAtBottom(shadow_underlay_);
|
| }
|
|
|
| + bool underlay_capture_events = ash::WmShell::Get()
|
| + ->accessibility_delegate()
|
| + ->IsSpokenFeedbackEnabled() &&
|
| + widget_->IsActive();
|
| +
|
| float shadow_underlay_opacity = rectangular_shadow_background_opacity_;
|
| // Put the black background layer behind the window if
|
| - // 1) the window is in immersive fullscreen.
|
| + // 1) the window is in immersive fullscreen or is active with
|
| + // spoken feedback enabled.
|
| // 2) the window can control the bounds of the window in fullscreen (
|
| // thus the background can be visible).
|
| // 3) the window has no transform (the transformed background may
|
| // not cover the entire background, e.g. overview mode).
|
| - if (widget_->IsFullscreen() &&
|
| + if ((widget_->IsFullscreen() || underlay_capture_events) &&
|
| ash::wm::GetWindowState(window)->allow_set_bounds_in_maximized() &&
|
| - window->layer()->transform().IsIdentity()) {
|
| + window->layer()->GetTargetTransform().IsIdentity()) {
|
| gfx::Point origin;
|
| origin -= window->bounds().origin().OffsetFromOrigin();
|
| shadow_bounds.set_origin(origin);
|
|
|