// Copyright 2018 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 "services/ws/injected_event_handler.h" #include "base/memory/ptr_util.h" #include "services/ws/window_service.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" namespace ws { InjectedEventHandler::InjectedEventHandler( WindowService* window_service, aura::WindowTreeHost* window_tree_host) : window_service_(window_service), window_tree_host_(window_tree_host) { window_service_->AddObserver(this); window_tree_host_->window()->AddObserver(this); window_tree_host_->window()->env()->AddWindowEventDispatcherObserver(this); } InjectedEventHandler::~InjectedEventHandler() { RemoveObservers(); } void InjectedEventHandler::Inject(std::unique_ptr event, ResultCallback result_callback) { DCHECK(window_service_); // Inject() can only be called once. DCHECK(!result_callback_); result_callback_ = std::move(result_callback); DCHECK(result_callback_); aura::Window* window_tree_host_window = window_tree_host_->window(); window_tree_host_window->AddPreTargetHandler( this, ui::EventTarget::Priority::kAccessibility); // No need to do anything with the result of sending the event. ignore_result( window_tree_host_->event_sink()->OnEventFromSource(event.get())); // WARNING: it's possible |this| has been destroyed. Make sure you don't // access any locals after this. The use of |this| here is safe as it's only // used to remove from a list. window_tree_host_window->RemovePreTargetHandler(this); } void InjectedEventHandler::NotifyCallback() { RemoveObservers(); std::move(result_callback_).Run(); } void InjectedEventHandler::RemoveObservers() { if (!window_service_) return; window_tree_host_->window()->env()->RemoveWindowEventDispatcherObserver(this); window_tree_host_->window()->RemoveObserver(this); window_service_->RemoveObserver(this); window_service_ = nullptr; } void InjectedEventHandler::OnWindowEventDispatcherFinishedProcessingEvent( aura::WindowEventDispatcher* dispatcher) { if (!event_id_ && dispatcher->host() == window_tree_host_ && event_dispatched_) { // The WindowEventDispatcher finished processing and the event was not sent // to a remote client, notify the callback. This happens here rather than // OnEvent() as during OnEvent() we don't yet know if the event is going to // a remote client. NotifyCallback(); } } void InjectedEventHandler::OnWindowEventDispatcherDispatchedHeldEvents( aura::WindowEventDispatcher* dispatcher) { if (!event_id_ && dispatcher->host() == window_tree_host_) NotifyCallback(); } void InjectedEventHandler::OnWindowDestroying(aura::Window* window) { // This is called when the WindowTreeHost has been destroyed. Assume we won't // be getting an ack from the client. NotifyCallback(); } void InjectedEventHandler::OnWillSendEventToClient(ClientSpecificId client_id, uint32_t event_id) { if (event_id_) return; // Already waiting. event_id_ = std::make_unique(); event_id_->client_id = client_id; event_id_->event_id = event_id; } void InjectedEventHandler::OnClientAckedEvent(ClientSpecificId client_id, uint32_t event_id) { if (event_id_ && event_id_->client_id == client_id && event_id_->event_id == event_id) { NotifyCallback(); } } void InjectedEventHandler::OnWillDestroyClient(ClientSpecificId client_id) { // If the client this is waiting on is being destroyed, an ack will never be // received. if (event_id_ && event_id_->client_id == client_id) NotifyCallback(); } void InjectedEventHandler::OnEvent(ui::Event* event) { // This is called if the event is actually going to be delivered to a target // (not held by WindowEventDispatcher). Don't call NotifyCallback() yet, as we // don't yet know if the event is going to a remote client. event_dispatched_ = true; } } // namespace ws