blob: 0bbac9e0417285c36b32f4ec09421fbc6ee6c1f6 [file] [log] [blame]
// Copyright 2015 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 <stdint.h>
#include <map>
#include <memory>
#include <utility>
#include "base/macros.h"
#include "services/ui/common/types.h"
#include "services/ui/public/interfaces/event_matcher.mojom.h"
#include "services/ui/ws/modal_window_controller.h"
#include "services/ui/ws/server_window_observer.h"
#include "ui/gfx/geometry/rect_f.h"
namespace ui {
class Event;
class KeyEvent;
class LocatedEvent;
namespace ws {
class Accelerator;
class EventDispatcherDelegate;
class ServerWindow;
namespace test {
class EventDispatcherTestApi;
// Handles dispatching events to the right location as well as updating focus.
class EventDispatcher : public ServerWindowObserver {
enum class AcceleratorMatchPhase {
// Both pre and post should be considered.
// PRE_TARGETs are not considered, only the actual target and any
// accelerators registered with POST_TARGET.
explicit EventDispatcher(EventDispatcherDelegate* delegate);
~EventDispatcher() override;
// Cancels capture and stops tracking any pointer events. This does not send
// any events to the delegate.
void Reset();
void SetMousePointerScreenLocation(const gfx::Point& screen_location);
const gfx::Point& mouse_pointer_last_location() const {
return mouse_pointer_last_location_;
// If we still have the window of the last mouse move, returns true and sets
// the current cursor to use to |cursor_out|.
bool GetCurrentMouseCursor(int32_t* cursor_out);
// |capture_window_| will receive all input. See window_tree.mojom for
// details.
ServerWindow* capture_window() { return capture_window_; }
const ServerWindow* capture_window() const { return capture_window_; }
// Setting capture can fail if the window is blocked by a modal window
// (indicated by returning |false|).
bool SetCaptureWindow(ServerWindow* capture_window,
ClientSpecificId client_id);
// Id of the client that capture events are sent to.
ClientSpecificId capture_window_client_id() const {
return capture_window_client_id_;
// Adds a system modal window. The window remains modal to system until it is
// destroyed. There can exist multiple system modal windows, in which case the
// one that is visible and added most recently or shown most recently would be
// the active one.
void AddSystemModalWindow(ServerWindow* window);
// Checks if |modal_window| is a visible modal window that blocks current
// capture window and if that's the case, releases the capture.
void ReleaseCaptureBlockedByModalWindow(const ServerWindow* modal_window);
// Checks if the current capture window is blocked by any visible modal window
// and if that's the case, releases the capture.
void ReleaseCaptureBlockedByAnyModalWindow();
// Retrieves the ServerWindow of the last mouse move.
ServerWindow* mouse_cursor_source_window() const {
return mouse_cursor_source_window_;
// If the mouse cursor is still over |mouse_cursor_source_window_|, updates
// whether we are in the non-client area. Used when
// |mouse_cursor_source_window_| has changed its properties.
void UpdateNonClientAreaForCurrentWindow();
// Possibly updates the cursor. If we aren't in an implicit capture, we take
// the last known location of the mouse pointer, and look for the
// ServerWindow* under it.
void UpdateCursorProviderByLastKnownLocation();
// Adds an accelerator with the given id and event-matcher. If an accelerator
// already exists with the same id or the same matcher, then the accelerator
// is not added. Returns whether adding the accelerator was successful or not.
bool AddAccelerator(uint32_t id, mojom::EventMatcherPtr event_matcher);
void RemoveAccelerator(uint32_t id);
// Processes the supplied event, informing the delegate as approriate. This
// may result in generating any number of events. If |match_phase| is
// ANY and there is a matching accelerator with PRE_TARGET found, than only
// OnAccelerator() is called. The expectation is after the PRE_TARGET has been
// handled this is again called with an AcceleratorMatchPhase of POST_ONLY.
void ProcessEvent(const ui::Event& event, AcceleratorMatchPhase match_phase);
friend class test::EventDispatcherTestApi;
// Keeps track of state associated with an active pointer.
struct PointerTarget {
: window(nullptr),
is_pointer_down(false) {}
// NOTE: this is set to null if the window is destroyed before a
// corresponding release/cancel.
ServerWindow* window;
bool is_mouse_event;
// Did the pointer event start in the non-client area.
bool in_nonclient_area;
bool is_pointer_down;
void ProcessKeyEvent(const ui::KeyEvent& event,
AcceleratorMatchPhase match_phase);
bool IsTrackingPointer(int32_t pointer_id) const {
return pointer_targets_.count(pointer_id) > 0;
// EventDispatcher provides the following logic for pointer events:
// . wheel events go to the current target of the associated pointer. If
// there is no target, they go to the deepest window.
// . move (not drag) events go to the deepest window.
// . when a pointer goes down all events until the corresponding up or
// cancel go to the deepest target. For mouse events the up only occurs
// when no buttons on the mouse are down.
// This also generates exit events as appropriate. For example, if the mouse
// moves between one window to another an exit is generated on the first.
void ProcessPointerEvent(const ui::PointerEvent& event);
// Adds |pointer_target| to |pointer_targets_|.
void StartTrackingPointer(int32_t pointer_id,
const PointerTarget& pointer_target);
// Removes a PointerTarget from |pointer_targets_|.
void StopTrackingPointer(int32_t pointer_id);
// Starts tracking the pointer for |event|, or if already tracking the
// pointer sends the appropriate event to the delegate and updates the
// currently tracked PointerTarget appropriately.
void UpdateTargetForPointer(int32_t pointer_id,
const ui::LocatedEvent& event);
// Returns a PointerTarget from the supplied event.
PointerTarget PointerTargetForEvent(const ui::LocatedEvent& event);
// Returns true if any pointers are in the pressed/down state.
bool AreAnyPointersDown() const;
// If |target->window| is valid, then passes the event to the delegate.
void DispatchToPointerTarget(const PointerTarget& target,
const ui::LocatedEvent& event);
// Dispatch |event| to the delegate.
void DispatchToClient(ServerWindow* window,
ClientSpecificId client_id,
const ui::LocatedEvent& event);
// Stops sending pointer events to |window|. This does not remove the entry
// for |window| from |pointer_targets_|, rather it nulls out the window. This
// way we continue to eat events until the up/cancel is received.
void CancelPointerEventsToTarget(ServerWindow* window);
// Used to observe a window. Can be called multiple times on a window. To
// unobserve a window, UnobserveWindow() should be called the same number of
// times.
void ObserveWindow(ServerWindow* winodw);
void UnobserveWindow(ServerWindow* winodw);
// Returns an Accelerator bound to the specified code/flags, and of the
// matching |phase|. Otherwise returns null.
Accelerator* FindAccelerator(const ui::KeyEvent& event,
const ui::mojom::AcceleratorPhase phase);
ServerWindow* FindDeepestVisibleWindowForEvents(gfx::Point* location);
// ServerWindowObserver:
void OnWillChangeWindowHierarchy(ServerWindow* window,
ServerWindow* new_parent,
ServerWindow* old_parent) override;
void OnWindowVisibilityChanged(ServerWindow* window) override;
void OnWindowDestroyed(ServerWindow* window) override;
EventDispatcherDelegate* delegate_;
ServerWindow* capture_window_;
ClientSpecificId capture_window_client_id_;
ModalWindowController modal_window_controller_;
bool mouse_button_down_;
ServerWindow* mouse_cursor_source_window_;
bool mouse_cursor_in_non_client_area_;
// The on screen location of the mouse pointer. This can be outside the
// bounds of |mouse_cursor_source_window_|, which can capture the cursor.
gfx::Point mouse_pointer_last_location_;
std::map<uint32_t, std::unique_ptr<Accelerator>> accelerators_;
using PointerIdToTargetMap = std::map<int32_t, PointerTarget>;
// |pointer_targets_| contains the active pointers. For a mouse based pointer
// a PointerTarget is always active (and present in |pointer_targets_|). For
// touch based pointers the pointer is active while down and removed on
// cancel or up.
PointerIdToTargetMap pointer_targets_;
// Keeps track of number of observe requests for each observed window.
std::map<const ServerWindow*, uint8_t> observed_windows_;
#if !defined(NDEBUG)
std::unique_ptr<ui::Event> previous_event_;
AcceleratorMatchPhase previous_accelerator_match_phase_ =
} // namespace ws
} // namespace ui