blob: beed6b538c97c3878fe8cc03cd17f458be51f533 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/mus/pointer_watcher_event_router.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
using display::Display;
using display::Screen;
namespace views {
namespace {
bool HasPointerWatcher(
base::ObserverList<views::PointerWatcher, true>* observer_list) {
return observer_list->begin() != observer_list->end();
}
} // namespace
PointerWatcherEventRouter::PointerWatcherEventRouter(
aura::WindowTreeClient* window_tree_client)
: window_tree_client_(window_tree_client) {
window_tree_client->AddObserver(this);
}
PointerWatcherEventRouter::~PointerWatcherEventRouter() {
if (window_tree_client_)
window_tree_client_->RemoveObserver(this);
}
void PointerWatcherEventRouter::AddPointerWatcher(PointerWatcher* watcher,
bool wants_moves) {
// Pointer watchers cannot be added multiple times.
DCHECK(!move_watchers_.HasObserver(watcher));
DCHECK(!non_move_watchers_.HasObserver(watcher));
if (wants_moves) {
move_watchers_.AddObserver(watcher);
if (event_types_ != EventTypes::MOVE_EVENTS) {
event_types_ = EventTypes::MOVE_EVENTS;
const bool wants_moves = true;
window_tree_client_->StartPointerWatcher(wants_moves);
}
} else {
non_move_watchers_.AddObserver(watcher);
if (event_types_ == EventTypes::NONE) {
event_types_ = EventTypes::NON_MOVE_EVENTS;
const bool wants_moves = false;
window_tree_client_->StartPointerWatcher(wants_moves);
}
}
}
void PointerWatcherEventRouter::RemovePointerWatcher(PointerWatcher* watcher) {
if (non_move_watchers_.HasObserver(watcher)) {
non_move_watchers_.RemoveObserver(watcher);
} else {
DCHECK(move_watchers_.HasObserver(watcher));
move_watchers_.RemoveObserver(watcher);
}
const EventTypes types = DetermineEventTypes();
if (types == event_types_)
return;
event_types_ = types;
switch (types) {
case EventTypes::NONE:
window_tree_client_->StopPointerWatcher();
break;
case EventTypes::NON_MOVE_EVENTS:
window_tree_client_->StartPointerWatcher(false);
break;
case EventTypes::MOVE_EVENTS:
// It isn't possible to remove an observer and transition to wanting move
// events. This could only happen if there is a bug in the add logic.
NOTREACHED();
break;
}
}
void PointerWatcherEventRouter::OnPointerEventObserved(
const ui::PointerEvent& event,
int64_t display_id,
aura::Window* target) {
Widget* target_widget = nullptr;
ui::PointerEvent updated_event(event);
if (target) {
aura::Window* window = target;
while (window && !target_widget) {
target_widget = Widget::GetWidgetForNativeView(window);
if (!target_widget) {
// Widget::GetWidgetForNativeView() uses NativeWidgetAura. Views with
// aura-mus may also create DesktopNativeWidgetAura.
DesktopNativeWidgetAura* desktop_native_widget_aura =
DesktopNativeWidgetAura::ForWindow(target);
if (desktop_native_widget_aura) {
target_widget = static_cast<internal::NativeWidgetPrivate*>(
desktop_native_widget_aura)
->GetWidget();
}
}
window = window->parent();
}
if (target_widget) {
gfx::Point widget_relative_location(event.location());
aura::Window::ConvertPointToTarget(target, target_widget->GetNativeView(),
&widget_relative_location);
updated_event.set_location(widget_relative_location);
}
}
// Compute screen coordinates via |display_id| because there may not be a
// |target| that can be used to find a ScreenPositionClient.
gfx::Point location_in_screen = event.location();
Display display;
if (Screen::GetScreen()->GetDisplayWithDisplayId(display_id, &display))
location_in_screen.Offset(display.bounds().x(), display.bounds().y());
for (PointerWatcher& observer : move_watchers_) {
observer.OnPointerEventObserved(
updated_event, location_in_screen,
target_widget ? target_widget->GetNativeWindow() : target);
}
if (event.type() != ui::ET_POINTER_MOVED) {
for (PointerWatcher& observer : non_move_watchers_) {
observer.OnPointerEventObserved(
updated_event, location_in_screen,
target_widget ? target_widget->GetNativeWindow() : target);
}
}
}
void PointerWatcherEventRouter::AttachToCaptureClient(
aura::client::CaptureClient* capture_client) {
capture_client->AddObserver(this);
}
void PointerWatcherEventRouter::DetachFromCaptureClient(
aura::client::CaptureClient* capture_client) {
capture_client->RemoveObserver(this);
}
PointerWatcherEventRouter::EventTypes
PointerWatcherEventRouter::DetermineEventTypes() {
if (HasPointerWatcher(&move_watchers_))
return EventTypes::MOVE_EVENTS;
if (HasPointerWatcher(&non_move_watchers_))
return EventTypes::NON_MOVE_EVENTS;
return EventTypes::NONE;
}
void PointerWatcherEventRouter::OnCaptureChanged(aura::Window* lost_capture,
aura::Window* gained_capture) {
const ui::MouseEvent mouse_event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
gfx::Point(), ui::EventTimeForNow(), 0, 0);
const ui::PointerEvent event(mouse_event);
gfx::Point location_in_screen = Screen::GetScreen()->GetCursorScreenPoint();
for (PointerWatcher& observer : move_watchers_)
observer.OnPointerEventObserved(event, location_in_screen, nullptr);
for (PointerWatcher& observer : non_move_watchers_)
observer.OnPointerEventObserved(event, location_in_screen, nullptr);
}
void PointerWatcherEventRouter::OnWillDestroyClient(
aura::WindowTreeClient* client) {
// We expect that all observers have been removed by this time.
DCHECK_EQ(event_types_, EventTypes::NONE);
DCHECK_EQ(client, window_tree_client_);
window_tree_client_->RemoveObserver(this);
window_tree_client_ = nullptr;
}
} // namespace views