Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1238)

Unified Diff: components/mus/ws/window_manager_state.cc

Issue 1775133003: Moves EventDispatcher from Display to WindowManagerState (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: todo Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/mus/ws/window_manager_state.h ('k') | components/mus/ws/window_tree.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/mus/ws/window_manager_state.cc
diff --git a/components/mus/ws/window_manager_state.cc b/components/mus/ws/window_manager_state.cc
index f7ccc63d2d3aca7686b16a2717a41c54373f6639..2a6d983767f48ad8f153bdcce3d3bb6aeb78cbba 100644
--- a/components/mus/ws/window_manager_state.cc
+++ b/components/mus/ws/window_manager_state.cc
@@ -6,27 +6,142 @@
#include "components/mus/ws/connection_manager.h"
#include "components/mus/ws/display_manager.h"
+#include "components/mus/ws/platform_display.h"
#include "components/mus/ws/server_window.h"
#include "components/mus/ws/user_display_manager.h"
+#include "components/mus/ws/user_id_tracker.h"
+#include "components/mus/ws/window_tree.h"
+#include "mojo/converters/input_events/input_events_type_converters.h"
#include "mojo/shell/public/interfaces/connector.mojom.h"
+#include "ui/events/event.h"
namespace mus {
namespace ws {
+namespace {
-WindowManagerState::WindowManagerState(Display* display)
- : WindowManagerState(display, false, mojo::shell::mojom::kRootUserID) {}
+base::TimeDelta GetDefaultAckTimerDelay() {
+#if defined(NDEBUG)
+ return base::TimeDelta::FromMilliseconds(100);
+#else
+ return base::TimeDelta::FromMilliseconds(1000);
+#endif
+}
+
+bool EventsCanBeCoalesced(const ui::Event& one, const ui::Event& two) {
+ if (one.type() != two.type() || one.flags() != two.flags())
+ return false;
+
+ // TODO(sad): wheel events can also be merged.
+ if (one.type() != ui::ET_POINTER_MOVED)
+ return false;
+
+ return one.AsPointerEvent()->pointer_id() ==
+ two.AsPointerEvent()->pointer_id();
+}
+
+scoped_ptr<ui::Event> CoalesceEvents(scoped_ptr<ui::Event> first,
+ scoped_ptr<ui::Event> second) {
+ DCHECK(first->type() == ui::ET_POINTER_MOVED)
+ << " Non-move events cannot be merged yet.";
+ // For mouse moves, the new event just replaces the old event.
+ return second;
+}
+
+} // namespace
+
+class WindowManagerState::ProcessedEventTarget {
+ public:
+ ProcessedEventTarget(ServerWindow* window, bool in_nonclient_area)
+ : in_nonclient_area_(in_nonclient_area) {
+ tracker_.Add(window);
+ }
+
+ ~ProcessedEventTarget() {}
+
+ // Return true if the event is still valid. The event becomes invalid if
+ // the window is destroyed while waiting to dispatch.
+ bool IsValid() const { return !tracker_.windows().empty(); }
-WindowManagerState::WindowManagerState(Display* display, const UserId& user_id)
- : WindowManagerState(display, true, user_id) {}
+ ServerWindow* window() {
+ DCHECK(IsValid());
+ return tracker_.windows().front();
+ }
+
+ bool in_nonclient_area() const { return in_nonclient_area_; }
+
+ private:
+ ServerWindowTracker tracker_;
+ const bool in_nonclient_area_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessedEventTarget);
+};
+
+WindowManagerState::QueuedEvent::QueuedEvent() {}
+WindowManagerState::QueuedEvent::~QueuedEvent() {}
+
+WindowManagerState::WindowManagerState(Display* display,
+ PlatformDisplay* platform_display,
+ cc::SurfaceId surface_id)
+ : WindowManagerState(display,
+ platform_display,
+ surface_id,
+ false,
+ mojo::shell::mojom::kRootUserID) {}
+
+WindowManagerState::WindowManagerState(Display* display,
+ PlatformDisplay* platform_display,
+ cc::SurfaceId surface_id,
+ const UserId& user_id)
+ : WindowManagerState(display, platform_display, surface_id, true, user_id) {
+}
WindowManagerState::~WindowManagerState() {}
+void WindowManagerState::SetFrameDecorationValues(
+ mojom::FrameDecorationValuesPtr values) {
+ got_frame_decoration_values_ = true;
+ frame_decoration_values_ = values.Clone();
+ display_->display_manager()
+ ->GetUserDisplayManager(user_id_)
+ ->OnFrameDecorationValuesChanged(this);
+}
+
+void WindowManagerState::SetCapture(ServerWindow* window,
+ bool in_nonclient_area) {
+ // TODO(sky): capture should be a singleton. Need to route to
+ // ConnectionManager so that all other EventDispatchers are updated.
+ DCHECK(IsActive());
+ if (capture_window() == window)
+ return;
+ DCHECK(!window || root_->Contains(window));
+ event_dispatcher_.SetCaptureWindow(window, in_nonclient_area);
+}
+
+mojom::DisplayPtr WindowManagerState::ToMojomDisplay() const {
+ mojom::DisplayPtr display_ptr = display_->ToMojomDisplay();
+ // TODO(sky): set work area.
+ display_ptr->work_area = display_ptr->bounds.Clone();
+ display_ptr->frame_decoration_values = frame_decoration_values_.Clone();
+ return display_ptr;
+}
+
+void WindowManagerState::OnWillDestroyTree(WindowTree* tree) {
+ if (tree_awaiting_input_ack_ != tree)
+ return;
+ // The WindowTree is dying. So it's not going to ack the event.
+ OnEventAck(tree_awaiting_input_ack_);
+}
+
WindowManagerState::WindowManagerState(Display* display,
+ PlatformDisplay* platform_display,
+ cc::SurfaceId surface_id,
bool is_user_id_valid,
const UserId& user_id)
: display_(display),
+ platform_display_(platform_display),
is_user_id_valid_(is_user_id_valid),
- user_id_(user_id) {
+ user_id_(user_id),
+ event_dispatcher_(this) {
frame_decoration_values_ = mojom::FrameDecorationValues::New();
frame_decoration_values_->normal_client_area_insets = mojo::Insets::New();
frame_decoration_values_->maximized_client_area_insets = mojo::Insets::New();
@@ -42,23 +157,162 @@ WindowManagerState::WindowManagerState(Display* display,
root_->SetBounds(gfx::Rect(display->root_window()->bounds().size()));
root_->SetVisible(true);
display->root_window()->Add(root_.get());
+
+ event_dispatcher_.set_root(root_.get());
+ event_dispatcher_.set_surface_id(surface_id);
}
-void WindowManagerState::SetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) {
- got_frame_decoration_values_ = true;
- frame_decoration_values_ = values.Clone();
- display_->display_manager()
- ->GetUserDisplayManager(user_id_)
- ->OnFrameDecorationValuesChanged(this);
+bool WindowManagerState::IsActive() const {
+ return display()->GetActiveWindowManagerState() == this;
}
-mojom::DisplayPtr WindowManagerState::ToMojomDisplay() const {
- mojom::DisplayPtr display_ptr = display_->ToMojomDisplay();
- // TODO(sky): set work area.
- display_ptr->work_area = display_ptr->bounds.Clone();
- display_ptr->frame_decoration_values = frame_decoration_values_.Clone();
- return display_ptr;
+void WindowManagerState::ProcessEvent(const ui::Event& event) {
+ mojom::EventPtr mojo_event(mojom::Event::From(event));
+ // If this is still waiting for an ack from a previously sent event, then
+ // queue up the event to be dispatched once the ack is received.
+ if (event_ack_timer_.IsRunning()) {
+ if (!event_queue_.empty() && !event_queue_.back()->processed_target &&
+ EventsCanBeCoalesced(*event_queue_.back()->event, event)) {
+ event_queue_.back()->event = CoalesceEvents(
+ std::move(event_queue_.back()->event), ui::Event::Clone(event));
+ return;
+ }
+ QueueEvent(event, nullptr);
+ return;
+ }
+ event_dispatcher_.ProcessEvent(event);
+}
+
+void WindowManagerState::OnEventAck(mojom::WindowTree* tree) {
+ if (tree_awaiting_input_ack_ != tree) {
+ // TODO(sad): The ack must have arrived after the timeout. We should do
+ // something here, and in OnEventAckTimeout().
+ return;
+ }
+ tree_awaiting_input_ack_ = nullptr;
+ event_ack_timer_.Stop();
+ ProcessNextEventFromQueue();
+}
+
+ConnectionManager* WindowManagerState::connection_manager() {
+ return display_->connection_manager();
+}
+
+void WindowManagerState::OnEventAckTimeout() {
+ // TODO(sad): Figure out what we should do.
+ NOTIMPLEMENTED() << "Event ACK timed out.";
+ OnEventAck(tree_awaiting_input_ack_);
+}
+
+void WindowManagerState::QueueEvent(
+ const ui::Event& event,
+ scoped_ptr<ProcessedEventTarget> processed_event_target) {
+ scoped_ptr<QueuedEvent> queued_event(new QueuedEvent);
+ queued_event->event = ui::Event::Clone(event);
+ queued_event->processed_target = std::move(processed_event_target);
+ event_queue_.push(std::move(queued_event));
+}
+
+void WindowManagerState::ProcessNextEventFromQueue() {
+ // Loop through |event_queue_| stopping after dispatching the first valid
+ // event.
+ while (!event_queue_.empty()) {
+ scoped_ptr<QueuedEvent> queued_event = std::move(event_queue_.front());
+ event_queue_.pop();
+ if (!queued_event->processed_target) {
+ event_dispatcher_.ProcessEvent(*queued_event->event);
+ return;
+ }
+ if (queued_event->processed_target->IsValid()) {
+ DispatchInputEventToWindowImpl(
+ queued_event->processed_target->window(),
+ queued_event->processed_target->in_nonclient_area(),
+ *queued_event->event);
+ return;
+ }
+ }
+}
+
+void WindowManagerState::DispatchInputEventToWindowImpl(
+ ServerWindow* target,
+ bool in_nonclient_area,
+ const ui::Event& event) {
+ if (target == root_->parent())
+ target = root_.get();
+
+ if (event.IsMousePointerEvent()) {
+ DCHECK(event_dispatcher_.mouse_cursor_source_window());
+ display_->UpdateNativeCursor(
+ event_dispatcher_.mouse_cursor_source_window()->cursor());
+ }
+
+ // If the event is in the non-client area the event goes to the owner of
+ // the window. Otherwise if the window is an embed root, forward to the
+ // embedded window.
+ WindowTree* tree =
+ in_nonclient_area
+ ? connection_manager()->GetTreeWithId(target->id().connection_id)
+ : connection_manager()->GetTreeWithRoot(target);
+ if (!tree) {
+ DCHECK(!in_nonclient_area);
+ tree = connection_manager()->GetTreeWithId(target->id().connection_id);
+ }
+
+ // TOOD(sad): Adjust this delay, possibly make this dynamic.
+ const base::TimeDelta max_delay = base::debug::BeingDebugged()
+ ? base::TimeDelta::FromDays(1)
+ : GetDefaultAckTimerDelay();
+ event_ack_timer_.Start(FROM_HERE, max_delay, this,
+ &WindowManagerState::OnEventAckTimeout);
+
+ tree_awaiting_input_ack_ = tree;
+ tree->DispatchInputEvent(target, mojom::Event::From(event));
+}
+
+void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
+ const ui::Event& event) {
+ DCHECK(IsActive());
+ tree_->OnAccelerator(accelerator_id, mojom::Event::From(event));
+}
+
+void WindowManagerState::SetFocusedWindowFromEventDispatcher(
+ ServerWindow* new_focused_window) {
+ DCHECK(IsActive());
+ display_->SetFocusedWindow(new_focused_window);
+}
+
+ServerWindow* WindowManagerState::GetFocusedWindowForEventDispatcher() {
+ return display()->GetFocusedWindow();
+}
+
+void WindowManagerState::SetNativeCapture() {
+ DCHECK(IsActive());
+ platform_display_->SetCapture();
+}
+
+void WindowManagerState::ReleaseNativeCapture() {
+ platform_display_->ReleaseCapture();
+}
+
+void WindowManagerState::OnServerWindowCaptureLost(ServerWindow* window) {
+ DCHECK(window);
+ display_->connection_manager()->ProcessLostCapture(window);
+}
+
+void WindowManagerState::DispatchInputEventToWindow(ServerWindow* target,
+ bool in_nonclient_area,
+ const ui::Event& event) {
+ DCHECK(IsActive());
+ // TODO(sky): this needs to see if another wms has capture and if so forward
+ // to it.
+ if (event_ack_timer_.IsRunning()) {
+ scoped_ptr<ProcessedEventTarget> processed_event_target(
+ new ProcessedEventTarget(target, in_nonclient_area));
+ QueueEvent(event, std::move(processed_event_target));
+ return;
+ }
+
+ DispatchInputEventToWindowImpl(target, in_nonclient_area, event);
}
} // namespace ws
« no previous file with comments | « components/mus/ws/window_manager_state.h ('k') | components/mus/ws/window_tree.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698