Chromium Code Reviews| Index: components/exo/shell_surface.cc |
| diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc |
| index 465477e79c488da48e2b777eaafd631ae51591a8..8952f1cb3b665d988d0ed99d055fc12f8849ab67 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) |
|
oshima
2016/10/01 02:00:09
Do you need this? I believe this file is compiled
reveman
2016/10/01 08:12:30
Compiling this only on ChromeOS is by choice and t
|
| +#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 the underlay is accepting events, test against it's bounds instead |
| + // since it will be larger than (and contain) the surface's bounds. |
| + aura::Window* shadow_underlay = |
| + static_cast<ShellSurface*>( |
| + widget_->widget_delegate()->GetContentsView()) |
| + ->shadow_underlay(); |
| + if (shadow_underlay && !shadow_underlay->ignore_events()) { |
| + 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,30 @@ 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 && |
| + !shadow_underlay->ignore_events()) { |
| + 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 +211,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 +383,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 +809,14 @@ gfx::Size ShellSurface::GetPreferredSize() const { |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| +// ash::AccessibilityObserver overrides: |
| + |
| +void ShellSurface::OnAccessibilityModeChanged( |
| + ash::AccessibilityNotificationVisibility) { |
| + UpdateShadow(); |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| // ash::wm::WindowStateObserver overrides: |
| void ShellSurface::OnPreWindowStateTypeChange( |
| @@ -821,6 +912,7 @@ void ShellSurface::OnWindowActivated( |
| lost_active == widget_->GetNativeWindow()) { |
| DCHECK(activatable_); |
| Configure(); |
| + UpdateShadow(); |
| } |
| } |
| @@ -936,7 +1028,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 +1074,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 +1336,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 +1351,23 @@ void ShellSurface::UpdateShadow() { |
| window->StackChildAtBottom(shadow_underlay_); |
| } |
| + bool underlay_capture_events = ash::WmShell::Get() |
| + ->accessibility_delegate() |
| + ->IsSpokenFeedbackEnabled() && |
| + widget_->IsActive(); |
| + shadow_underlay_->set_ignore_events(!underlay_capture_events); |
|
oshima
2016/10/01 02:00:10
I think shadow underlay should always consume even
reveman
2016/10/01 08:12:30
+1
Mr4D (OOO till 08-26)
2016/10/01 08:56:21
The purpose of this is that blind people can touch
erosky
2016/10/03 17:44:02
Doing that would include things like immersive-mod
oshima
2016/10/03 19:57:01
Yes, we want this for both cases.
erosky
2016/10/03 22:35:08
Done.
|
| + |
| 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); |