Commit 148903c2 authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

chromeos: wires up sending events to remote clients

There is still work to be done here, but this is a good step. The
interesting parts:
. An aura::WindowTargeter is used to ensure events target the right
  Window. In particular if one client intercepts events from another
  client.
. Custom EventHandlers are used to forward to the remote client. This
  is mildly tricky to ensure top-levels are handled correctly.

BUG=837692
TEST=covered by test

Change-Id: I58f0d23e7d7dd6c6c31f3cfbb44889588c4f8f84
Reviewed-on: https://chromium-review.googlesource.com/1054427
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558868}
parent 363e22e8
This diff is collapsed.
...@@ -5,17 +5,24 @@ ...@@ -5,17 +5,24 @@
#ifndef SERVICES_UI_WS2_CLIENT_WINDOW_H_ #ifndef SERVICES_UI_WS2_CLIENT_WINDOW_H_
#define SERVICES_UI_WS2_CLIENT_WINDOW_H_ #define SERVICES_UI_WS2_CLIENT_WINDOW_H_
#include <vector>
#include "base/component_export.h" #include "base/component_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/frame_sink_id.h"
#include "services/ui/ws2/ids.h" #include "services/ui/ws2/ids.h"
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
namespace aura { namespace aura {
class Window; class Window;
} }
namespace ui { namespace ui {
class EventHandler;
namespace ws2 { namespace ws2 {
class WindowHostFrameSinkClient; class WindowHostFrameSinkClient;
...@@ -30,9 +37,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow { ...@@ -30,9 +37,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow {
// Creates a new ClientWindow. The lifetime of the ClientWindow is tied to // Creates a new ClientWindow. The lifetime of the ClientWindow is tied to
// that of the Window (the Window ends up owning the ClientWindow). // that of the Window (the Window ends up owning the ClientWindow).
// |is_top_level| is true if the window represents a top-level window.
static ClientWindow* Create(aura::Window* window, static ClientWindow* Create(aura::Window* window,
WindowServiceClient* client, WindowServiceClient* client,
const viz::FrameSinkId& frame_sink_id); const viz::FrameSinkId& frame_sink_id,
bool is_top_level);
aura::Window* window() { return window_; }
// Returns the ClientWindow associated with a window, null if not created yet. // Returns the ClientWindow associated with a window, null if not created yet.
static ClientWindow* GetMayBeNull(aura::Window* window) { static ClientWindow* GetMayBeNull(aura::Window* window) {
...@@ -61,6 +72,19 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow { ...@@ -61,6 +72,19 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow {
void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id); void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; } const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
const std::vector<gfx::Rect>& additional_client_areas() const {
return additional_client_areas_;
}
const gfx::Insets& client_area() const { return client_area_; }
void SetClientArea(const gfx::Insets& insets,
const std::vector<gfx::Rect>& additional_client_areas);
// Returns true if the window is a top-level window and there is at least some
// non-client area.
bool HasNonClientArea() const;
bool IsTopLevel() const;
void AttachCompositorFrameSink( void AttachCompositorFrameSink(
viz::mojom::CompositorFrameSinkRequest compositor_frame_sink, viz::mojom::CompositorFrameSinkRequest compositor_frame_sink,
viz::mojom::CompositorFrameSinkClientPtr client); viz::mojom::CompositorFrameSinkClientPtr client);
...@@ -68,7 +92,8 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow { ...@@ -68,7 +92,8 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow {
private: private:
ClientWindow(aura::Window*, ClientWindow(aura::Window*,
WindowServiceClient* client, WindowServiceClient* client,
const viz::FrameSinkId& frame_sink_id); const viz::FrameSinkId& frame_sink_id,
bool is_top_level);
aura::Window* window_; aura::Window* window_;
...@@ -99,6 +124,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow { ...@@ -99,6 +124,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) ClientWindow {
// window. // window.
std::unique_ptr<WindowHostFrameSinkClient> window_host_frame_sink_client_; std::unique_ptr<WindowHostFrameSinkClient> window_host_frame_sink_client_;
// Together |client_area_| and |additional_client_areas_| are used to specify
// the client area. See SetClientArea() in mojom for details.
gfx::Insets client_area_;
std::vector<gfx::Rect> additional_client_areas_;
std::unique_ptr<ui::EventHandler> event_handler_;
DISALLOW_COPY_AND_ASSIGN(ClientWindow); DISALLOW_COPY_AND_ASSIGN(ClientWindow);
}; };
......
...@@ -14,6 +14,17 @@ ...@@ -14,6 +14,17 @@
namespace ui { namespace ui {
namespace ws2 { namespace ws2 {
// static
std::unique_ptr<Event> PointerWatcher::CreateEventForClient(
const Event& event) {
// Client code expects to get PointerEvents.
if (event.IsMouseEvent())
return std::make_unique<ui::PointerEvent>(*event.AsMouseEvent());
if (event.IsTouchEvent())
return std::make_unique<ui::PointerEvent>(*event.AsTouchEvent());
return Event::Clone(event);
}
PointerWatcher::PointerWatcher(WindowServiceClient* client) : client_(client) { PointerWatcher::PointerWatcher(WindowServiceClient* client) : client_(client) {
aura::Env::GetInstance()->AddWindowEventDispatcherObserver(this); aura::Env::GetInstance()->AddWindowEventDispatcherObserver(this);
} }
...@@ -51,15 +62,8 @@ void PointerWatcher::OnWindowEventDispatcherStartedProcessing( ...@@ -51,15 +62,8 @@ void PointerWatcher::OnWindowEventDispatcherStartedProcessing(
// only send pointer events if an event wasn't also sent to the client. // only send pointer events if an event wasn't also sent to the client.
// Part of https://crbug.com/837692 // Part of https://crbug.com/837692
std::unique_ptr<ui::Event> event_to_send; std::unique_ptr<ui::Event> event_to_send;
// Client code expects to get PointerEvents.
if (event.IsMouseEvent())
event_to_send = std::make_unique<ui::PointerEvent>(*event.AsMouseEvent());
else if (event.IsTouchEvent())
event_to_send = std::make_unique<ui::PointerEvent>(*event.AsTouchEvent());
else
NOTREACHED();
client_->SendPointerWatcherEventToClient(dispatcher->host()->GetDisplayId(), client_->SendPointerWatcherEventToClient(dispatcher->host()->GetDisplayId(),
std::move(event_to_send)); CreateEventForClient(event));
} }
} // namespace ws2 } // namespace ws2
......
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
#ifndef SERVICES_UI_WS2_POINTER_WATCHER_H_ #ifndef SERVICES_UI_WS2_POINTER_WATCHER_H_
#define SERVICES_UI_WS2_POINTER_WATCHER_H_ #define SERVICES_UI_WS2_POINTER_WATCHER_H_
#include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "ui/aura/window_event_dispatcher_observer.h" #include "ui/aura/window_event_dispatcher_observer.h"
namespace ui { namespace ui {
class Event;
namespace ws2 { namespace ws2 {
class WindowServiceClient; class WindowServiceClient;
...@@ -33,6 +38,10 @@ class PointerWatcher : public aura::WindowEventDispatcherObserver { ...@@ -33,6 +38,10 @@ class PointerWatcher : public aura::WindowEventDispatcherObserver {
explicit PointerWatcher(WindowServiceClient* client); explicit PointerWatcher(WindowServiceClient* client);
~PointerWatcher() override; ~PointerWatcher() override;
// Applies any necessary transformations on the event before sending to the
// client.
static std::unique_ptr<Event> CreateEventForClient(const Event& event);
void set_types_to_watch(TypesToWatch types) { types_to_watch_ = types; } void set_types_to_watch(TypesToWatch types) { types_to_watch_ = types; }
private: private:
......
...@@ -20,7 +20,8 @@ std::unique_ptr<aura::Window> TestWindowServiceDelegate::NewTopLevel( ...@@ -20,7 +20,8 @@ std::unique_ptr<aura::Window> TestWindowServiceDelegate::NewTopLevel(
aura::PropertyConverter* property_converter, aura::PropertyConverter* property_converter,
const base::flat_map<std::string, std::vector<uint8_t>>& properties) { const base::flat_map<std::string, std::vector<uint8_t>>& properties) {
std::unique_ptr<aura::Window> window = std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr); std::make_unique<aura::Window>(delegate_for_next_top_level_);
delegate_for_next_top_level_ = nullptr;
window->Init(LAYER_NOT_DRAWN); window->Init(LAYER_NOT_DRAWN);
if (top_level_parent_) if (top_level_parent_)
top_level_parent_->AddChild(window.get()); top_level_parent_->AddChild(window.get());
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "services/ui/ws2/window_service_delegate.h" #include "services/ui/ws2/window_service_delegate.h"
namespace aura {
class WindowDelegate;
}
namespace ui { namespace ui {
namespace ws2 { namespace ws2 {
...@@ -22,6 +26,10 @@ class TestWindowServiceDelegate : public WindowServiceDelegate { ...@@ -22,6 +26,10 @@ class TestWindowServiceDelegate : public WindowServiceDelegate {
top_level_parent_ = parent; top_level_parent_ = parent;
} }
void set_delegate_for_next_top_level(aura::WindowDelegate* delegate) {
delegate_for_next_top_level_ = delegate;
}
// WindowServiceDelegate: // WindowServiceDelegate:
std::unique_ptr<aura::Window> NewTopLevel( std::unique_ptr<aura::Window> NewTopLevel(
aura::PropertyConverter* property_converter, aura::PropertyConverter* property_converter,
...@@ -30,6 +38,7 @@ class TestWindowServiceDelegate : public WindowServiceDelegate { ...@@ -30,6 +38,7 @@ class TestWindowServiceDelegate : public WindowServiceDelegate {
private: private:
aura::Window* top_level_parent_; aura::Window* top_level_parent_;
aura::WindowDelegate* delegate_for_next_top_level_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestWindowServiceDelegate); DISALLOW_COPY_AND_ASSIGN(TestWindowServiceDelegate);
}; };
......
...@@ -12,6 +12,12 @@ ...@@ -12,6 +12,12 @@
namespace ui { namespace ui {
namespace ws2 { namespace ws2 {
TestWindowTreeClient::InputEvent::InputEvent() = default;
TestWindowTreeClient::InputEvent::InputEvent(InputEvent&& other) = default;
TestWindowTreeClient::InputEvent::~InputEvent() = default;
TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent() = default; TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent() = default;
TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent( TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent(
...@@ -25,6 +31,15 @@ TestWindowTreeClient::TestWindowTreeClient() { ...@@ -25,6 +31,15 @@ TestWindowTreeClient::TestWindowTreeClient() {
TestWindowTreeClient::~TestWindowTreeClient() = default; TestWindowTreeClient::~TestWindowTreeClient() = default;
TestWindowTreeClient::InputEvent TestWindowTreeClient::PopInputEvent() {
if (input_events_.empty())
return InputEvent();
InputEvent event = std::move(input_events_.front());
input_events_.pop();
return event;
}
TestWindowTreeClient::ObservedPointerEvent TestWindowTreeClient::ObservedPointerEvent
TestWindowTreeClient::PopObservedPointerEvent() { TestWindowTreeClient::PopObservedPointerEvent() {
if (observed_pointer_events_.empty()) if (observed_pointer_events_.empty())
...@@ -159,7 +174,20 @@ void TestWindowTreeClient::OnWindowInputEvent( ...@@ -159,7 +174,20 @@ void TestWindowTreeClient::OnWindowInputEvent(
const gfx::PointF& event_location_in_screen_pixel_layout, const gfx::PointF& event_location_in_screen_pixel_layout,
std::unique_ptr<ui::Event> event, std::unique_ptr<ui::Event> event,
bool matches_pointer_watcher) { bool matches_pointer_watcher) {
tree_->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED); tracker_.OnWindowInputEvent(window_id, *event, display_id,
event_location_in_screen_pixel_layout,
matches_pointer_watcher);
InputEvent input_event;
input_event.event_id = event_id;
input_event.window_id = window_id;
input_event.display_id = display_id;
input_event.event = std::move(event);
input_event.matches_pointer_watcher = matches_pointer_watcher;
input_events_.push(std::move(input_event));
if (tree_)
tree_->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED);
} }
void TestWindowTreeClient::OnPointerEventObserved( void TestWindowTreeClient::OnPointerEventObserved(
......
...@@ -21,6 +21,19 @@ namespace ws2 { ...@@ -21,6 +21,19 @@ namespace ws2 {
class TestWindowTreeClient : public mojom::WindowTreeClient, class TestWindowTreeClient : public mojom::WindowTreeClient,
public TestChangeTracker::Delegate { public TestChangeTracker::Delegate {
public: public:
// Created every time OnWindowInputEvent() is called.
struct InputEvent {
InputEvent();
InputEvent(InputEvent&& other);
~InputEvent();
uint32_t event_id;
Id window_id;
int64_t display_id;
std::unique_ptr<ui::Event> event;
bool matches_pointer_watcher;
};
// An ObservedPointerEvent is created for each call to // An ObservedPointerEvent is created for each call to
// OnPointerEventObserved() // OnPointerEventObserved()
struct ObservedPointerEvent { struct ObservedPointerEvent {
...@@ -36,6 +49,13 @@ class TestWindowTreeClient : public mojom::WindowTreeClient, ...@@ -36,6 +49,13 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
TestWindowTreeClient(); TestWindowTreeClient();
~TestWindowTreeClient() override; ~TestWindowTreeClient() override;
std::queue<InputEvent>& input_events() { return input_events_; }
// Returns the oldest InputEvent that was received by way of
// OnWindowInputEvent(). If no events have been observed, |event| in the
// returned object is null.
InputEvent PopInputEvent();
std::queue<ObservedPointerEvent>& observed_pointer_events() { std::queue<ObservedPointerEvent>& observed_pointer_events() {
return observed_pointer_events_; return observed_pointer_events_;
} }
...@@ -163,6 +183,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient, ...@@ -163,6 +183,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
mojom::WindowTreePtr tree_; mojom::WindowTreePtr tree_;
Id root_window_id_ = 0; Id root_window_id_ = 0;
bool track_root_bounds_changes_ = false; bool track_root_bounds_changes_ = false;
std::queue<InputEvent> input_events_;
std::queue<ObservedPointerEvent> observed_pointer_events_; std::queue<ObservedPointerEvent> observed_pointer_events_;
DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient); DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient);
......
...@@ -38,7 +38,8 @@ ClientWindow* WindowService::GetClientWindowForWindowCreateIfNecessary( ...@@ -38,7 +38,8 @@ ClientWindow* WindowService::GetClientWindowForWindowCreateIfNecessary(
const viz::FrameSinkId frame_sink_id = const viz::FrameSinkId frame_sink_id =
ClientWindowId(kWindowServerClientId, next_window_id_++); ClientWindowId(kWindowServerClientId, next_window_id_++);
CHECK_NE(0u, next_window_id_); CHECK_NE(0u, next_window_id_);
return ClientWindow::Create(window, nullptr, frame_sink_id); const bool is_top_level = false;
return ClientWindow::Create(window, nullptr, frame_sink_id, is_top_level);
} }
std::unique_ptr<WindowServiceClient> WindowService::CreateWindowServiceClient( std::unique_ptr<WindowServiceClient> WindowService::CreateWindowServiceClient(
......
...@@ -77,6 +77,20 @@ WindowServiceClient::~WindowServiceClient() { ...@@ -77,6 +77,20 @@ WindowServiceClient::~WindowServiceClient() {
} }
} }
void WindowServiceClient::SendEventToClient(aura::Window* window,
const Event& event) {
// TODO(sky): remove event_id.
const uint32_t event_id = 1;
// Events should only come to windows connected to displays.
DCHECK(window->GetHost());
const int64_t display_id = window->GetHost()->GetDisplayId();
// TODO(sky): wire up |matches_pointer_watcher|.
const bool matches_pointer_watcher = false;
window_tree_client_->OnWindowInputEvent(
event_id, TransportIdForWindow(window), display_id, 0u, gfx::PointF(),
PointerWatcher::CreateEventForClient(event), matches_pointer_watcher);
}
void WindowServiceClient::SendPointerWatcherEventToClient( void WindowServiceClient::SendPointerWatcherEventToClient(
int64_t display_id, int64_t display_id,
std::unique_ptr<ui::Event> event) { std::unique_ptr<ui::Event> event) {
...@@ -84,6 +98,11 @@ void WindowServiceClient::SendPointerWatcherEventToClient( ...@@ -84,6 +98,11 @@ void WindowServiceClient::SendPointerWatcherEventToClient(
kInvalidTransportId, display_id); kInvalidTransportId, display_id);
} }
bool WindowServiceClient::IsTopLevel(aura::Window* window) {
auto iter = FindClientRootWithRoot(window);
return iter != client_roots_.end() && (*iter)->is_top_level();
}
ClientRoot* WindowServiceClient::CreateClientRoot( ClientRoot* WindowServiceClient::CreateClientRoot(
aura::Window* window, aura::Window* window,
mojom::WindowTreePtr window_tree) { mojom::WindowTreePtr window_tree) {
...@@ -206,13 +225,10 @@ bool WindowServiceClient::IsClientRootWindow(aura::Window* window) { ...@@ -206,13 +225,10 @@ bool WindowServiceClient::IsClientRootWindow(aura::Window* window) {
return window && FindClientRootWithRoot(window) != client_roots_.end(); return window && FindClientRootWithRoot(window) != client_roots_.end();
} }
bool WindowServiceClient::IsTopLevel(aura::Window* window) {
auto iter = FindClientRootWithRoot(window);
return iter != client_roots_.end() && (*iter)->is_top_level();
}
WindowServiceClient::ClientRoots::iterator WindowServiceClient::ClientRoots::iterator
WindowServiceClient::FindClientRootWithRoot(aura::Window* window) { WindowServiceClient::FindClientRootWithRoot(aura::Window* window) {
if (!window)
return client_roots_.end();
for (auto iter = client_roots_.begin(); iter != client_roots_.end(); ++iter) { for (auto iter = client_roots_.begin(); iter != client_roots_.end(); ++iter) {
if (iter->get()->window() == window) if (iter->get()->window() == window)
return iter; return iter;
...@@ -234,10 +250,11 @@ bool WindowServiceClient::IsWindowRootOfAnotherClient( ...@@ -234,10 +250,11 @@ bool WindowServiceClient::IsWindowRootOfAnotherClient(
aura::Window* WindowServiceClient::AddClientCreatedWindow( aura::Window* WindowServiceClient::AddClientCreatedWindow(
const ClientWindowId& id, const ClientWindowId& id,
bool is_top_level,
std::unique_ptr<aura::Window> window_ptr) { std::unique_ptr<aura::Window> window_ptr) {
aura::Window* window = window_ptr.get(); aura::Window* window = window_ptr.get();
client_created_windows_.insert(std::move(window_ptr)); client_created_windows_.insert(std::move(window_ptr));
ClientWindow::Create(window, this, id); ClientWindow::Create(window, this, id, is_top_level);
AddWindowToKnownWindows(window, id); AddWindowToKnownWindows(window, id);
return window; return window;
} }
...@@ -374,8 +391,9 @@ bool WindowServiceClient::NewWindowImpl( ...@@ -374,8 +391,9 @@ bool WindowServiceClient::NewWindowImpl(
DVLOG(1) << "NewWindow failed (id is not valid for client)"; DVLOG(1) << "NewWindow failed (id is not valid for client)";
return false; return false;
} }
const bool is_top_level = false;
aura::Window* window = AddClientCreatedWindow( aura::Window* window = AddClientCreatedWindow(
client_window_id, std::make_unique<aura::Window>(nullptr)); client_window_id, is_top_level, std::make_unique<aura::Window>(nullptr));
SetWindowType(window, aura::GetWindowTypeFromProperties(properties)); SetWindowType(window, aura::GetWindowTypeFromProperties(properties));
for (auto& pair : properties) { for (auto& pair : properties) {
...@@ -585,10 +603,11 @@ bool WindowServiceClient::EmbedImpl( ...@@ -585,10 +603,11 @@ bool WindowServiceClient::EmbedImpl(
mojom::WindowTreeClientPtr window_tree_client, mojom::WindowTreeClientPtr window_tree_client,
uint32_t flags) { uint32_t flags) {
DVLOG(3) << "Embed window_id=" << window_id; DVLOG(3) << "Embed window_id=" << window_id;
if (flags & mojom::kEmbedFlagEmbedderInterceptsEvents) {
// TODO: add support for this. // mojom::kEmbedFlagEmbedderInterceptsEvents is inherited, otherwise an
NOTIMPLEMENTED(); // embedder could effectively circumvent it by embedding itself.
} if (intercepts_events_)
flags = mojom::kEmbedFlagEmbedderInterceptsEvents;
aura::Window* window = GetWindowByClientId(window_id); aura::Window* window = GetWindowByClientId(window_id);
if (!window) { if (!window) {
...@@ -600,13 +619,10 @@ bool WindowServiceClient::EmbedImpl( ...@@ -600,13 +619,10 @@ bool WindowServiceClient::EmbedImpl(
return false; return false;
} }
// mojom::kEmbedFlagEmbedderInterceptsEvents is inherited, otherwise an
// embedder could effectively circumvent it by embedding itself.
const bool intercepts_events = intercepts_events_;
auto new_client_binding = std::make_unique<WindowServiceClientBinding>(); auto new_client_binding = std::make_unique<WindowServiceClientBinding>();
new_client_binding->InitForEmbed( new_client_binding->InitForEmbed(
window_service_, std::move(window_tree_client), intercepts_events, window, window_service_, std::move(window_tree_client),
flags & mojom::kEmbedFlagEmbedderInterceptsEvents, window,
base::BindOnce(&WindowServiceClient::OnChildBindingConnectionLost, base::BindOnce(&WindowServiceClient::OnChildBindingConnectionLost,
base::Unretained(this), new_client_binding.get())); base::Unretained(this), new_client_binding.get()));
...@@ -714,8 +730,9 @@ void WindowServiceClient::NewTopLevelWindow( ...@@ -714,8 +730,9 @@ void WindowServiceClient::NewTopLevelWindow(
return; return;
} }
top_level_ptr->set_owned_by_parent(false); top_level_ptr->set_owned_by_parent(false);
aura::Window* top_level = const bool is_top_level = true;
AddClientCreatedWindow(client_window_id, std::move(top_level_ptr)); aura::Window* top_level = AddClientCreatedWindow(
client_window_id, is_top_level, std::move(top_level_ptr));
ClientWindow::GetMayBeNull(top_level)->SetFrameSinkId(client_window_id); ClientWindow::GetMayBeNull(top_level)->SetFrameSinkId(client_window_id);
const int64_t display_id = const int64_t display_id =
display::Screen::GetScreen()->GetDisplayNearestWindow(top_level).id(); display::Screen::GetScreen()->GetDisplayNearestWindow(top_level).id();
...@@ -773,10 +790,26 @@ void WindowServiceClient::SetWindowTransform(uint32_t change_id, ...@@ -773,10 +790,26 @@ void WindowServiceClient::SetWindowTransform(uint32_t change_id,
} }
void WindowServiceClient::SetClientArea( void WindowServiceClient::SetClientArea(
Id window_id, Id transport_window_id,
const gfx::Insets& insets, const gfx::Insets& insets,
const base::Optional<std::vector<gfx::Rect>>& additional_client_areas) { const base::Optional<std::vector<gfx::Rect>>& additional_client_areas) {
NOTIMPLEMENTED(); const ClientWindowId window_id = MakeClientWindowId(transport_window_id);
aura::Window* window = GetWindowByClientId(window_id);
DVLOG(3) << "SetClientArea client window_id=" << window_id.ToString()
<< " insets=" << insets.ToString();
if (!window) {
DVLOG(1) << "SetClientArea failed (invalid window id)";
return;
}
if (!IsClientRootWindow(window) || !IsTopLevel(window)) {
DVLOG(1) << "SetClientArea failed (access denied)";
return;
}
ClientWindow* client_window = ClientWindow::GetMayBeNull(window);
DCHECK(client_window); // Must exist because of preceeding conditionals.
client_window->SetClientArea(
insets, additional_client_areas.value_or(std::vector<gfx::Rect>()));
} }
void WindowServiceClient::SetHitTestMask( void WindowServiceClient::SetHitTestMask(
...@@ -957,10 +990,9 @@ void WindowServiceClient::SetEventTargetingPolicy( ...@@ -957,10 +990,9 @@ void WindowServiceClient::SetEventTargetingPolicy(
window->SetEventTargetingPolicy(policy); window->SetEventTargetingPolicy(policy);
} }
void WindowServiceClient::OnWindowInputEventAck( void WindowServiceClient::OnWindowInputEventAck(uint32_t event_id,
uint32_t event_id, mojom::EventResult result) {
::ui::mojom::EventResult result) { // TODO(sky): this is no longer needed, remove.
NOTIMPLEMENTED();
} }
void WindowServiceClient::DeactivateWindow(Id window_id) { void WindowServiceClient::DeactivateWindow(Id window_id) {
......
...@@ -68,11 +68,20 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient ...@@ -68,11 +68,20 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient
void InitForEmbed(aura::Window* root, mojom::WindowTreePtr window_tree_ptr); void InitForEmbed(aura::Window* root, mojom::WindowTreePtr window_tree_ptr);
void InitFromFactory(); void InitFromFactory();
bool intercepts_events() const { return intercepts_events_; }
// Notifies the client than an event has been received.
void SendEventToClient(aura::Window* window, const ui::Event& event);
// Notifies the client that an event matching a pointer watcher has been // Notifies the client that an event matching a pointer watcher has been
// received. // received.
void SendPointerWatcherEventToClient(int64_t display_id, void SendPointerWatcherEventToClient(int64_t display_id,
std::unique_ptr<Event> event); std::unique_ptr<Event> event);
// Returns true if |window| was created by the client calling
// NewTopLevelWindow().
bool IsTopLevel(aura::Window* window);
WindowService* window_service() { return window_service_; } WindowService* window_service() { return window_service_; }
private: private:
...@@ -119,9 +128,6 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient ...@@ -119,9 +128,6 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient
bool IsClientCreatedWindow(aura::Window* window); bool IsClientCreatedWindow(aura::Window* window);
bool IsClientRootWindow(aura::Window* window); bool IsClientRootWindow(aura::Window* window);
// Returns true if |window| was created by the client calling
// NewTopLevelWindow().
bool IsTopLevel(aura::Window* window);
ClientRoots::iterator FindClientRootWithRoot(aura::Window* window); ClientRoots::iterator FindClientRootWithRoot(aura::Window* window);
// Returns true if |window| has been exposed to this client. A client // Returns true if |window| has been exposed to this client. A client
...@@ -133,6 +139,7 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient ...@@ -133,6 +139,7 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient
// Called for windows created by the client (including top-levels). // Called for windows created by the client (including top-levels).
aura::Window* AddClientCreatedWindow( aura::Window* AddClientCreatedWindow(
const ClientWindowId& id, const ClientWindowId& id,
bool is_top_level,
std::unique_ptr<aura::Window> window_ptr); std::unique_ptr<aura::Window> window_ptr);
// Adds/removes a Window from the set of windows known to the client. This // Adds/removes a Window from the set of windows known to the client. This
...@@ -230,7 +237,7 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient ...@@ -230,7 +237,7 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient
void SetWindowTransform(uint32_t change_id, void SetWindowTransform(uint32_t change_id,
Id window_id, Id window_id,
const gfx::Transform& transform) override; const gfx::Transform& transform) override;
void SetClientArea(Id window_id, void SetClientArea(Id transport_window_id,
const gfx::Insets& insets, const gfx::Insets& insets,
const base::Optional<std::vector<gfx::Rect>>& const base::Optional<std::vector<gfx::Rect>>&
additional_client_areas) override; additional_client_areas) override;
...@@ -329,11 +336,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient ...@@ -329,11 +336,13 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient
mojom::WindowTreeClient* window_tree_client_; mojom::WindowTreeClient* window_tree_client_;
// If true the client sees all the decendants of windows with embeddings // If true, all events that would normally target another client embedded by
// in them that were created by this client, and additionally any events // this client are sent to this client. For example, consider the Window
// normally targeted at a descendant are targeted at the first ancestor Window // hierarchy A->B->C where client 1 created A and B, client 1 embedded
// created by this client. This is done to allow a client to intercept events // client 2 in window B, and client 2 created C. If an event occurs that would
// normally targeted at descendants and dispatch them using some other means. // normally target C, then the event is instead sent to client 1 with a target
// of B. If true, any clients embedded by this client never get normal events
// (they can still observer pointer events).
const bool intercepts_events_; const bool intercepts_events_;
// Controls whether the client can change the visibility of the roots. // Controls whether the client can change the visibility of the roots.
......
...@@ -52,6 +52,15 @@ void WindowServiceClientTestHelper::SetWindowBounds(aura::Window* window, ...@@ -52,6 +52,15 @@ void WindowServiceClientTestHelper::SetWindowBounds(aura::Window* window,
local_surface_id); local_surface_id);
} }
void WindowServiceClientTestHelper::SetClientArea(
aura::Window* window,
const gfx::Insets& insets,
base::Optional<std::vector<gfx::Rect>> additional_client_areas) {
window_service_client_->SetClientArea(
window_service_client_->TransportIdForWindow(window), insets,
additional_client_areas);
}
void WindowServiceClientTestHelper::SetWindowProperty( void WindowServiceClientTestHelper::SetWindowProperty(
aura::Window* window, aura::Window* window,
const std::string& name, const std::string& name,
......
...@@ -10,15 +10,17 @@ ...@@ -10,15 +10,17 @@
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "services/ui/public/interfaces/window_tree_constants.mojom.h" #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
#include "services/ui/ws2/ids.h" #include "services/ui/ws2/ids.h"
#include "ui/gfx/geometry/rect.h"
namespace aura { namespace aura {
class Window; class Window;
} }
namespace gfx { namespace gfx {
class Rect; class Insets;
} }
namespace ui { namespace ui {
...@@ -53,6 +55,11 @@ class WindowServiceClientTestHelper { ...@@ -53,6 +55,11 @@ class WindowServiceClientTestHelper {
void SetWindowBounds(aura::Window* window, void SetWindowBounds(aura::Window* window,
const gfx::Rect& bounds, const gfx::Rect& bounds,
uint32_t change_id = 1); uint32_t change_id = 1);
void SetClientArea(
aura::Window* window,
const gfx::Insets& insets,
base::Optional<std::vector<gfx::Rect>> additional_client_areas =
base::Optional<std::vector<gfx::Rect>>());
void SetWindowProperty(aura::Window* window, void SetWindowProperty(aura::Window* window,
const std::string& name, const std::string& name,
const std::vector<uint8_t>& value, const std::vector<uint8_t>& value,
......
...@@ -248,6 +248,198 @@ TEST(WindowServiceClientTest, WindowToWindowData) { ...@@ -248,6 +248,198 @@ TEST(WindowServiceClientTest, WindowToWindowData) {
data->properties[ui::mojom::WindowManager::kAlwaysOnTop_Property])); data->properties[ui::mojom::WindowManager::kAlwaysOnTop_Property]));
} }
TEST(WindowServiceClientTest, MovePressDragRelease) {
WindowServiceTestHelper helper;
TestWindowTreeClient* window_tree_client = helper.window_tree_client();
aura::Window* top_level = helper.helper()->NewTopLevelWindow(1);
ASSERT_TRUE(top_level);
top_level->Show();
top_level->SetBounds(gfx::Rect(10, 10, 100, 100));
test::EventGenerator event_generator(helper.root());
{
event_generator.MoveMouseTo(50, 50);
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_ENTERED, event->type());
EXPECT_EQ(gfx::Point(40, 40), event->AsLocatedEvent()->location());
event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_MOVED, event->type());
EXPECT_EQ(gfx::Point(40, 40), event->AsLocatedEvent()->location());
}
{
event_generator.PressLeftButton();
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_DOWN, event->type());
EXPECT_EQ(gfx::Point(40, 40), event->AsLocatedEvent()->location());
}
{
event_generator.MoveMouseTo(0, 0);
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_MOVED, event->type());
EXPECT_EQ(gfx::Point(-10, -10), event->AsLocatedEvent()->location());
}
{
event_generator.ReleaseLeftButton();
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_UP, event->type());
EXPECT_EQ(gfx::Point(-10, -10), event->AsLocatedEvent()->location());
}
}
class EventRecordingWindowDelegate : public aura::test::TestWindowDelegate {
public:
EventRecordingWindowDelegate() = default;
~EventRecordingWindowDelegate() override = default;
std::queue<std::unique_ptr<ui::Event>>& events() { return events_; }
std::unique_ptr<Event> PopEvent() {
if (events_.empty())
return nullptr;
auto event = std::move(events_.front());
events_.pop();
return event;
}
void ClearEvents() {
std::queue<std::unique_ptr<ui::Event>> events;
std::swap(events_, events);
}
// aura::test::TestWindowDelegate:
void OnEvent(ui::Event* event) override {
events_.push(ui::Event::Clone(*event));
}
private:
std::queue<std::unique_ptr<ui::Event>> events_;
DISALLOW_COPY_AND_ASSIGN(EventRecordingWindowDelegate);
};
TEST(WindowServiceClientTest, MoveFromClientToNonClient) {
EventRecordingWindowDelegate window_delegate;
WindowServiceTestHelper helper;
TestWindowTreeClient* window_tree_client = helper.window_tree_client();
helper.delegate()->set_delegate_for_next_top_level(&window_delegate);
aura::Window* top_level = helper.helper()->NewTopLevelWindow(1);
ASSERT_TRUE(top_level);
top_level->Show();
top_level->SetBounds(gfx::Rect(10, 10, 100, 100));
helper.helper()->SetClientArea(top_level, gfx::Insets(10, 0, 0, 0));
window_delegate.ClearEvents();
test::EventGenerator event_generator(helper.root());
{
event_generator.MoveMouseTo(50, 50);
// Move generates both an enter and move.
std::unique_ptr<Event> enter_event =
window_tree_client->PopInputEvent().event;
ASSERT_TRUE(enter_event);
EXPECT_EQ(ET_POINTER_ENTERED, enter_event->type());
EXPECT_EQ(gfx::Point(40, 40), enter_event->AsLocatedEvent()->location());
std::unique_ptr<Event> move_event =
window_tree_client->PopInputEvent().event;
ASSERT_TRUE(move_event);
EXPECT_EQ(ET_POINTER_MOVED, move_event->type());
EXPECT_EQ(gfx::Point(40, 40), move_event->AsLocatedEvent()->location());
// The delegate should see the same events.
ASSERT_EQ(2u, window_delegate.events().size());
enter_event = window_delegate.PopEvent();
EXPECT_EQ(ET_MOUSE_ENTERED, enter_event->type());
EXPECT_EQ(gfx::Point(40, 40), enter_event->AsLocatedEvent()->location());
move_event = window_delegate.PopEvent();
EXPECT_EQ(ET_MOUSE_MOVED, move_event->type());
EXPECT_EQ(gfx::Point(40, 40), move_event->AsLocatedEvent()->location());
}
// Move the mouse over the non-client area.
// The event is still sent to the client, and the delegate.
{
event_generator.MoveMouseTo(15, 16);
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_MOVED, event->type());
EXPECT_EQ(gfx::Point(5, 6), event->AsLocatedEvent()->location());
// Delegate should also get the events.
event = window_delegate.PopEvent();
EXPECT_EQ(ET_MOUSE_MOVED, event->type());
EXPECT_EQ(gfx::Point(5, 6), event->AsLocatedEvent()->location());
}
// Only the delegate should get the press in this case.
{
event_generator.PressLeftButton();
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_FALSE(event);
event = window_delegate.PopEvent();
EXPECT_EQ(ET_MOUSE_PRESSED, event->type());
EXPECT_EQ(gfx::Point(5, 6), event->AsLocatedEvent()->location());
}
// Move mouse into client area, only the delegate should get the move (drag).
{
event_generator.MoveMouseTo(35, 51);
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_FALSE(event);
event = window_delegate.PopEvent();
ASSERT_TRUE(event);
EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
EXPECT_EQ(gfx::Point(25, 41), event->AsLocatedEvent()->location());
}
// Release over client area, again only delegate should get it.
{
event_generator.ReleaseLeftButton();
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_FALSE(event);
event = window_delegate.PopEvent();
ASSERT_TRUE(event);
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
}
{
event_generator.MoveMouseTo(26, 50);
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_MOVED, event->type());
EXPECT_EQ(gfx::Point(16, 40), event->AsLocatedEvent()->location());
// Delegate should also get the events.
event = window_delegate.PopEvent();
EXPECT_EQ(ET_MOUSE_MOVED, event->type());
EXPECT_EQ(gfx::Point(16, 40), event->AsLocatedEvent()->location());
}
// Press in client area. Only the client should get the event.
{
event_generator.PressLeftButton();
std::unique_ptr<Event> event = window_tree_client->PopInputEvent().event;
ASSERT_TRUE(event);
EXPECT_EQ(ET_POINTER_DOWN, event->type());
EXPECT_EQ(gfx::Point(16, 40), event->AsLocatedEvent()->location());
event = window_delegate.PopEvent();
ASSERT_FALSE(event);
}
}
TEST(WindowServiceClientTest, PointerWatcher) { TEST(WindowServiceClientTest, PointerWatcher) {
WindowServiceTestHelper helper; WindowServiceTestHelper helper;
TestWindowTreeClient* window_tree_client = helper.window_tree_client(); TestWindowTreeClient* window_tree_client = helper.window_tree_client();
......
...@@ -316,7 +316,7 @@ ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit( ...@@ -316,7 +316,7 @@ ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit(
ui::EventType type) { ui::EventType type) {
Env::GetInstance()->env_controller()->UpdateStateForMouseEvent(window(), Env::GetInstance()->env_controller()->UpdateStateForMouseEvent(window(),
event); event);
if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() || if (!mouse_moved_handler_ || !mouse_moved_handler_->HasTargetHandler() ||
!window()->Contains(mouse_moved_handler_)) !window()->Contains(mouse_moved_handler_))
return DispatchDetails(); return DispatchDetails();
......
...@@ -88,6 +88,8 @@ class EVENTS_EXPORT EventTarget { ...@@ -88,6 +88,8 @@ class EVENTS_EXPORT EventTarget {
// Sets |target_handler| as |target_handler_| and returns the old handler. // Sets |target_handler| as |target_handler_| and returns the old handler.
EventHandler* SetTargetHandler(EventHandler* target_handler); EventHandler* SetTargetHandler(EventHandler* target_handler);
bool HasTargetHandler() const { return target_handler_ != nullptr; }
protected: protected:
EventHandler* target_handler() { return target_handler_; } EventHandler* target_handler() { return target_handler_; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment