Chromium Code Reviews| Index: components/mus/ws/event_dispatcher.cc |
| diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc |
| index 69d7fa155ecaf903264d89c6736a20eb9dd75b5a..6e49d6630c7ea49b37a15902271d73e0db760382 100644 |
| --- a/components/mus/ws/event_dispatcher.cc |
| +++ b/components/mus/ws/event_dispatcher.cc |
| @@ -4,8 +4,6 @@ |
| #include "components/mus/ws/event_dispatcher.h" |
| -#include <set> |
| - |
| #include "base/time/time.h" |
| #include "cc/surfaces/surface_hittest.h" |
| #include "components/mus/surfaces/surfaces_state.h" |
| @@ -76,17 +74,18 @@ EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate) |
| mouse_cursor_source_window_(nullptr) {} |
| EventDispatcher::~EventDispatcher() { |
| - std::set<ServerWindow*> pointer_targets; |
| if (capture_window_) { |
| - pointer_targets.insert(capture_window_); |
| - capture_window_->RemoveObserver(this); |
| + UnobserveWindow(capture_window_); |
| capture_window_ = nullptr; |
| } |
| + for (auto it = system_modal_windows_.begin(); |
| + it != system_modal_windows_.end();) { |
| + auto remove_it = it++; |
| + RemoveSystemModalWindow(remove_it); |
| + } |
| for (const auto& pair : pointer_targets_) { |
| - if (pair.second.window && |
| - pointer_targets.insert(pair.second.window).second) { |
| - pair.second.window->RemoveObserver(this); |
| - } |
| + if (pair.second.window) |
| + UnobserveWindow(pair.second.window); |
| } |
| pointer_targets_.clear(); |
| } |
| @@ -116,23 +115,23 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window, |
| return true; |
| // A window that is blocked by a modal window cannot gain capture. |
| - if (window && window->IsBlockedByModalWindow()) |
| + if (window && |
| + (GetActiveSystemModalWindow() || window->IsBlockedByModalWindow())) { |
| return false; |
| + } |
| if (capture_window_) { |
| // Stop observing old capture window. |pointer_targets_| are cleared on |
| // initial setting of a capture window. |
| delegate_->OnServerWindowCaptureLost(capture_window_); |
| - capture_window_->RemoveObserver(this); |
| + UnobserveWindow(capture_window_); |
| } else { |
| // Cancel implicit capture to all other windows. |
| - std::set<ServerWindow*> unobserved_windows; |
| for (const auto& pair : pointer_targets_) { |
| ServerWindow* target = pair.second.window; |
| if (!target) |
| continue; |
| - if (unobserved_windows.insert(target).second) |
| - target->RemoveObserver(this); |
| + UnobserveWindow(target); |
| if (target == window) |
| continue; |
| @@ -154,7 +153,7 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window, |
| // Begin tracking the capture window if it is not yet being observed. |
| if (window) { |
| - window->AddObserver(this); |
| + ObserveWindow(window); |
| if (!capture_window_) |
| delegate_->SetNativeCapture(); |
| } else { |
| @@ -168,6 +167,45 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window, |
| return true; |
| } |
| +void EventDispatcher::AddSystemModalWindow(ServerWindow* window) { |
| + DCHECK(window); |
| + DCHECK(std::find(system_modal_windows_.begin(), system_modal_windows_.end(), |
| + window) == system_modal_windows_.end()); |
| + |
| + window->SetModal(); |
| + system_modal_windows_.push_front(window); |
| + ObserveWindow(window); |
|
sky
2016/04/25 23:36:08
It's confusing and error prone to have this class
mohsen
2016/04/26 20:24:05
I agree. Even before adding modal windows, it was
|
| + |
| + ReleaseCaptureBlockedByModalWindow(window); |
| +} |
| + |
| +void EventDispatcher::ReleaseCaptureBlockedByModalWindow( |
| + const ServerWindow* modal_window) { |
| + if (!capture_window_ || !modal_window->is_modal() || |
| + !modal_window->IsDrawn()) { |
| + return; |
| + } |
| + |
| + if (modal_window->transient_parent() && |
| + !modal_window->transient_parent()->Contains(capture_window_)) { |
| + return; |
| + } |
| + |
| + SetCaptureWindow(nullptr, false); |
| +} |
| + |
| +void EventDispatcher::ReleaseCaptureBlockedByAnyModalWindow() { |
| + if (!capture_window_) |
| + return; |
| + |
| + if (!GetActiveSystemModalWindow() && |
| + !capture_window_->IsBlockedByModalWindow()) { |
| + return; |
| + } |
| + |
| + SetCaptureWindow(nullptr, false); |
| +} |
| + |
| void EventDispatcher::UpdateCursorProviderByLastKnownLocation() { |
| if (!mouse_button_down_) { |
| gfx::Point location = mouse_pointer_last_location_; |
| @@ -311,8 +349,7 @@ void EventDispatcher::StartTrackingPointer( |
| int32_t pointer_id, |
| const PointerTarget& pointer_target) { |
| DCHECK(!IsTrackingPointer(pointer_id)); |
| - if (!IsObservingWindow(pointer_target.window)) |
| - pointer_target.window->AddObserver(this); |
| + ObserveWindow(pointer_target.window); |
| pointer_targets_[pointer_id] = pointer_target; |
| } |
| @@ -320,8 +357,8 @@ void EventDispatcher::StopTrackingPointer(int32_t pointer_id) { |
| DCHECK(IsTrackingPointer(pointer_id)); |
| ServerWindow* window = pointer_targets_[pointer_id].window; |
| pointer_targets_.erase(pointer_id); |
| - if (window && !IsObservingWindow(window)) |
| - window->RemoveObserver(this); |
| + if (window) |
| + UnobserveWindow(window); |
| } |
| void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id, |
| @@ -363,7 +400,9 @@ EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent( |
| gfx::Point location(event.location()); |
| ServerWindow* target_window = |
| FindDeepestVisibleWindowForEvents(root_, surface_id_, &location); |
| - pointer_target.window = target_window->GetModalTarget(); |
| + ServerWindow* system_modal_window = GetActiveSystemModalWindow(); |
| + pointer_target.window = system_modal_window ? system_modal_window |
| + : target_window->GetModalTarget(); |
| pointer_target.is_mouse_event = event.IsMousePointerEvent(); |
| pointer_target.in_nonclient_area = |
| target_window != pointer_target.window || |
| @@ -399,9 +438,8 @@ void EventDispatcher::DispatchToPointerTarget(const PointerTarget& target, |
| } |
| void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) { |
| - window->RemoveObserver(this); |
| - |
| if (capture_window_ == window) { |
| + UnobserveWindow(window); |
| capture_window_ = nullptr; |
| mouse_button_down_ = false; |
| // A window only cares to be informed that it lost capture if it explicitly |
| @@ -414,17 +452,29 @@ void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) { |
| } |
| for (auto& pair : pointer_targets_) { |
| - if (pair.second.window == window) |
| + if (pair.second.window == window) { |
| + UnobserveWindow(window); |
| pair.second.window = nullptr; |
| + } |
| } |
| } |
| -bool EventDispatcher::IsObservingWindow(ServerWindow* window) { |
| - for (const auto& pair : pointer_targets_) { |
| - if (pair.second.window == window) |
| - return true; |
| +void EventDispatcher::ObserveWindow(ServerWindow* window) { |
| + auto res = observed_windows_.insert(std::make_pair(window, 0u)); |
| + res.first->second++; |
| + if (res.second) |
| + window->AddObserver(this); |
| +} |
| + |
| +void EventDispatcher::UnobserveWindow(ServerWindow* window) { |
| + auto it = observed_windows_.find(window); |
| + DCHECK(it != observed_windows_.end()); |
| + DCHECK_LT(0u, it->second); |
| + it->second--; |
| + if (!it->second) { |
| + window->RemoveObserver(this); |
| + observed_windows_.erase(it); |
| } |
| - return false; |
| } |
| Accelerator* EventDispatcher::FindAccelerator( |
| @@ -438,6 +488,20 @@ Accelerator* EventDispatcher::FindAccelerator( |
| return nullptr; |
| } |
| +ServerWindow* EventDispatcher::GetActiveSystemModalWindow() const { |
| + for (auto modal : system_modal_windows_) { |
| + if (modal->IsDrawn()) |
| + return modal; |
| + } |
| + return nullptr; |
| +} |
| + |
| +void EventDispatcher::RemoveSystemModalWindow(ServerWindowList::iterator it) { |
| + DCHECK(it != system_modal_windows_.end()); |
| + UnobserveWindow(*it); |
| + system_modal_windows_.erase(it); |
| +} |
| + |
| void EventDispatcher::OnWillChangeWindowHierarchy(ServerWindow* window, |
| ServerWindow* new_parent, |
| ServerWindow* old_parent) { |
| @@ -445,12 +509,29 @@ void EventDispatcher::OnWillChangeWindowHierarchy(ServerWindow* window, |
| } |
| void EventDispatcher::OnWindowVisibilityChanged(ServerWindow* window) { |
| + if (window->is_modal() && window->IsDrawn()) { |
| + auto it = std::find(system_modal_windows_.begin(), |
| + system_modal_windows_.end(), window); |
| + DCHECK(window->transient_parent() || it != system_modal_windows_.end()); |
| + |
| + if (it != system_modal_windows_.end()) { |
| + system_modal_windows_.splice(system_modal_windows_.begin(), |
| + system_modal_windows_, it); |
| + } |
| + return; |
| + } |
| + |
| CancelPointerEventsToTarget(window); |
| } |
| void EventDispatcher::OnWindowDestroyed(ServerWindow* window) { |
| CancelPointerEventsToTarget(window); |
| + auto it = std::find(system_modal_windows_.begin(), |
| + system_modal_windows_.end(), window); |
| + if (it != system_modal_windows_.end()) |
| + RemoveSystemModalWindow(it); |
| + |
| if (mouse_cursor_source_window_ == window) |
| mouse_cursor_source_window_ = nullptr; |
| } |