blob: df6269eb7c5eff5d080b0495add74b489914d8f4 [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.
#ifndef SERVICES_UI_WS_EVENT_PROCESSOR_H_
#define SERVICES_UI_WS_EVENT_PROCESSOR_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <utility>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "services/ui/common/types.h"
#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "services/ui/ws/drag_cursor_updater.h"
#include "services/ui/ws/event_matcher.h"
#include "services/ui/ws/event_targeter.h"
#include "services/ui/ws/event_targeter_delegate.h"
#include "services/ui/ws/modal_window_controller.h"
#include "services/ui/ws/server_window_drawn_tracker_observer.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_f.h"
namespace viz {
class HitTestQuery;
}
namespace ui {
class Event;
class KeyEvent;
class LocatedEvent;
namespace ws {
class Accelerator;
class DragController;
class DragSource;
class DragTargetConnection;
class EventDispatcher;
class EventProcessorDelegate;
class ServerWindow;
class ServerWindowDrawnTracker;
struct EventLocation;
namespace test {
class EventProcessorTestApi;
}
// EventProcessor is responsible for processing events and maintaining event
// related state: capture, cursor, last mouse location... EventProcessor informs
// EventProcessorDelegate of interesting state changes and uses an
// EventDispatcher for the actual dispatch. EventProcessor uses EventTargeter
// to determine the actual target. EventProcessor handles a single event at a
// time, and it may asynchronously process the event (EventTargeter may work
// asynchronously). A single event may result in multiple calls to
// EventDispatcher::DispatchEvent().
class EventProcessor : public ServerWindowDrawnTrackerObserver,
public DragCursorUpdater,
public EventTargeterDelegate {
public:
enum class AcceleratorMatchPhase {
// Both pre and post should be considered.
ANY,
// PRE_TARGETs are not considered, only the actual target and any
// accelerators registered with POST_TARGET.
POST_ONLY,
};
EventProcessor(EventProcessorDelegate* delegate,
EventDispatcher* event_dispatcher);
~EventProcessor() override;
ModalWindowController* modal_window_controller() {
return &modal_window_controller_;
}
// Cancels capture and stops tracking any pointer events. This does not send
// any events to the delegate.
void Reset();
const gfx::PointF& mouse_pointer_last_location() const {
return mouse_pointer_last_location_;
}
int64_t mouse_pointer_display_id() const { return mouse_pointer_display_id_; }
// Returns the cursor for the current target, or POINTER if the mouse is not
// over a valid target.
ui::CursorData GetCurrentMouseCursor() const;
// |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_;
}
void SetDragDropSourceWindow(
DragSource* drag_source,
ServerWindow* window,
DragTargetConnection* source_connection,
int32_t drag_pointer,
const base::flat_map<std::string, std::vector<uint8_t>>& mime_data,
uint32_t drag_operations);
void CancelDragDrop();
void EndDragDrop();
void OnWillDestroyDragTargetConnection(DragTargetConnection* connection);
// 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 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. If there is no valid
// window event target this falls back to the root of the display. In general
// this is not null, but may be null during shutdown.
ServerWindow* mouse_cursor_source_window() const {
return mouse_cursor_source_window_;
}
// Returns the window the mouse cursor is taken from. This does not take
// into account drags. In other words if there is a drag on going the mouse
// comes comes from a different window.
const ServerWindow* GetWindowForMouseCursor() const;
// 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);
void SetKeyEventsThatDontHideCursor(
std::vector<::ui::mojom::EventMatcherPtr> dont_hide_cursor_list);
// True if we are actively finding a target for an event, false otherwise.
bool IsProcessingEvent() const;
// 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.
// This may be asynchronous if we need to find the target window for |event|
// asynchronously.
// NOTE: if |event| is a LocatedEvent, then |event_location.location| is the
// same as the location (and root_location) of |event|.
void ProcessEvent(const ui::Event& event,
const EventLocation& event_location,
AcceleratorMatchPhase match_phase);
// EventTargeterDelegate:
ServerWindow* GetRootWindowForDisplay(int64_t display_id) override;
viz::HitTestQuery* GetHitTestQueryForDisplay(int64_t display_id) override;
ServerWindow* GetWindowFromFrameSinkId(
const viz::FrameSinkId& frame_sink_id) override;
private:
friend class test::EventProcessorTestApi;
// Keeps track of state associated with an active pointer.
struct PointerTarget {
// The target window, which may be null. null is used in two situations:
// when there is no valid window target, or there was a target but the
// window is destroyed before a corresponding release/cancel.
ServerWindow* window = nullptr;
bool is_mouse_event = false;
// Did the pointer event start in the non-client area.
bool in_nonclient_area = false;
bool is_pointer_down = false;
int64_t display_id = display::kInvalidDisplayId;
};
struct DeepestWindowAndTarget {
PointerTarget pointer_target;
DeepestWindow deepest_window;
};
struct ObservedWindow {
ObservedWindow();
~ObservedWindow();
// Number of times ObserveWindow() has been called.
uint8_t num_observers = 0;
std::unique_ptr<ServerWindowDrawnTracker> drawn_tracker;
};
// EventTargeter returns the deepest window based on hit-test data. If the
// target is blocked by a modal window this returns a different target,
// otherwise the supplied target is returned.
DeepestWindow AdjustTargetForModal(const DeepestWindow& target) const;
void SetMouseCursorSourceWindow(ServerWindow* window);
// Called after we found the target for the current mouse cursor to see if
// |mouse_pointer_last_location_| and |mouse_pointer_display_id_| need to be
// updated based on the new target we found. No need to call delegate's
// OnMouseCursorLocationChanged since mouse location is the same in
// screen-coord.
// TODO(riajiang): No need to update mouse location after ozone drm can tell
// us the right display the cursor is on for drag-n-drop events.
// crbug.com/726470
void SetMousePointerLocation(const gfx::PointF& new_mouse_location,
int64_t new_mouse_display_id);
void ProcessKeyEvent(const ui::KeyEvent& event,
int64_t display_id,
AcceleratorMatchPhase match_phase);
// When the user presses a key, we want to hide the cursor if it doesn't
// match a list of window manager supplied keys.
void HideCursorOnMatchedKeyEvent(const ui::KeyEvent& event);
bool IsTrackingPointer(int32_t pointer_id) const {
return pointer_targets_.count(pointer_id) > 0;
}
// Returns true if EventTargeter needs to be queried for the specified event.
bool ShouldUseEventTargeter(const Event& event) const;
// Callback from EventTargeter once the target has been found. Calls
// ProcessEventOnFoundTargetImpl().
void ProcessEventOnFoundTarget(std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow& target);
// EventProcessor provides the following logic for 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.
//
// NOTE: |found_target| is null if ShouldUseEventTargeter() returned false.
// If ShouldUseEventTargeter() returned false it means this function should
// not need |found_target| and has enough information to process the event
// without a DeepestWindow.
void ProcessEventOnFoundTargetImpl(std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow* found_target);
// Called when processing a event to updated cursor related properties.
void UpdateCursorRelatedProperties(const ui::Event& event,
const EventLocation& event_location);
void UpdateNonClientAreaForCurrentWindowOnFoundWindow(
const EventLocation& event_location,
const DeepestWindow& target);
// This callback is triggered by UpdateCursorProviderByLastKnownLocation().
// It calls UpdateCursorProvider() as appropriate.
void UpdateCursorProviderByLastKnownLocationOnFoundWindow(
const EventLocation& event_location,
const DeepestWindow& target);
// Immediatley updates the cursor provider (|mouse_cursor_source_window_|)
// as appropriate.
void UpdateCursorProvider(const DeepestWindow& target);
// Called during a click to nodify if the click was blocked by a modal.
void HandleClickOnBlockedWindow(const DeepestWindow& target);
// 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,
const PointerTarget& pointer_target,
const EventLocation& event_location);
// 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,
const EventLocation& event_location);
// Dispatch |event| to the delegate.
void DispatchToClient(ServerWindow* window,
ClientSpecificId client_id,
const ui::LocatedEvent& event,
const EventLocation& event_location);
// 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);
// Clears the implicit captures in |pointer_targets_|, with the exception of
// |window|. |window| may be null. |client_id| is the target client of
// |window|.
void CancelImplicitCaptureExcept(ServerWindow* window,
ClientSpecificId client_id);
// Called when |window| is no longer a valid target for events, for example,
// the window was removed from the hierarchy.
void WindowNoLongerValidTarget(ServerWindow* window);
// ServerWindowDrawnTrackerObserver:
void OnDrawnStateChanged(ServerWindow* ancestor,
ServerWindow* window,
bool is_drawn) override;
void OnRootDidChange(ServerWindow* ancestor, ServerWindow* window) override;
// DragCursorUpdater:
void OnDragCursorUpdated() override;
EventProcessorDelegate* delegate_;
EventDispatcher* event_dispatcher_;
ServerWindow* capture_window_;
ClientSpecificId capture_window_client_id_;
std::unique_ptr<DragController> drag_controller_;
ModalWindowController modal_window_controller_;
std::unique_ptr<EventTargeter> event_targeter_;
bool mouse_button_down_;
ServerWindow* mouse_cursor_source_window_;
bool mouse_cursor_in_non_client_area_;
// The location of the mouse pointer in display coordinates. This can be
// outside the bounds of |mouse_cursor_source_window_|, which can capture the
// cursor.
gfx::PointF mouse_pointer_last_location_;
// Id of the display |mouse_pointer_last_location_| is on.
int64_t mouse_pointer_display_id_ = display::kInvalidDisplayId;
std::map<uint32_t, std::unique_ptr<Accelerator>> accelerators_;
// A list of EventMatchers provided by the window manager. When this list is
// empty, we perform no processing. When it contains EventMatchers, we run
// each post-targeted key event through this list and if there's a match, we
// don't hide the cursor (otherwise we hide the cursor).
std::vector<EventMatcher> dont_hide_cursor_matchers_;
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*, std::unique_ptr<ObservedWindow>>
observed_windows_;
// Set to true when querying EventTargeter for the target.
bool waiting_on_event_targeter_ = false;
#if !defined(NDEBUG)
std::unique_ptr<ui::Event> previous_event_;
AcceleratorMatchPhase previous_accelerator_match_phase_ =
AcceleratorMatchPhase::ANY;
#endif
DISALLOW_COPY_AND_ASSIGN(EventProcessor);
};
} // namespace ws
} // namespace ui
#endif // SERVICES_UI_WS_EVENT_PROCESSOR_H_