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

Side by Side Diff: components/mus/ws/window_manager_state.cc

Issue 2119963002: Move mus to //services/ui (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 5 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/mus/ws/window_manager_state.h"
6
7 #include "base/memory/weak_ptr.h"
8 #include "components/mus/common/event_matcher_util.h"
9 #include "components/mus/ws/accelerator.h"
10 #include "components/mus/ws/display_manager.h"
11 #include "components/mus/ws/platform_display.h"
12 #include "components/mus/ws/server_window.h"
13 #include "components/mus/ws/user_display_manager.h"
14 #include "components/mus/ws/user_id_tracker.h"
15 #include "components/mus/ws/window_manager_display_root.h"
16 #include "components/mus/ws/window_server.h"
17 #include "components/mus/ws/window_tree.h"
18 #include "services/shell/public/interfaces/connector.mojom.h"
19 #include "ui/events/event.h"
20
21 namespace mus {
22 namespace ws {
23 namespace {
24
25 // Debug accelerator IDs start far above the highest valid Windows command ID
26 // (0xDFFF) and Chrome's highest IDC command ID.
27 const uint32_t kPrintWindowsDebugAcceleratorId = 1u << 31;
28
29 base::TimeDelta GetDefaultAckTimerDelay() {
30 #if defined(NDEBUG)
31 return base::TimeDelta::FromMilliseconds(100);
32 #else
33 return base::TimeDelta::FromMilliseconds(1000);
34 #endif
35 }
36
37 bool EventsCanBeCoalesced(const ui::Event& one, const ui::Event& two) {
38 if (one.type() != two.type() || one.flags() != two.flags())
39 return false;
40
41 // TODO(sad): wheel events can also be merged.
42 if (one.type() != ui::ET_POINTER_MOVED)
43 return false;
44
45 return one.AsPointerEvent()->pointer_id() ==
46 two.AsPointerEvent()->pointer_id();
47 }
48
49 std::unique_ptr<ui::Event> CoalesceEvents(std::unique_ptr<ui::Event> first,
50 std::unique_ptr<ui::Event> second) {
51 DCHECK(first->type() == ui::ET_POINTER_MOVED)
52 << " Non-move events cannot be merged yet.";
53 // For mouse moves, the new event just replaces the old event.
54 return second;
55 }
56
57 const ServerWindow* GetEmbedRoot(const ServerWindow* window) {
58 DCHECK(window);
59 const ServerWindow* embed_root = window->parent();
60 while (embed_root && embed_root->id().client_id == window->id().client_id)
61 embed_root = embed_root->parent();
62 return embed_root;
63 }
64
65 } // namespace
66
67 class WindowManagerState::ProcessedEventTarget {
68 public:
69 ProcessedEventTarget(ServerWindow* window,
70 ClientSpecificId client_id,
71 Accelerator* accelerator)
72 : client_id_(client_id) {
73 tracker_.Add(window);
74 if (accelerator)
75 accelerator_ = accelerator->GetWeakPtr();
76 }
77
78 ~ProcessedEventTarget() {}
79
80 // Return true if the event is still valid. The event becomes invalid if
81 // the window is destroyed while waiting to dispatch.
82 bool IsValid() const { return !tracker_.windows().empty(); }
83
84 ServerWindow* window() {
85 DCHECK(IsValid());
86 return tracker_.windows().front();
87 }
88
89 ClientSpecificId client_id() const { return client_id_; }
90
91 base::WeakPtr<Accelerator> accelerator() { return accelerator_; }
92
93 private:
94 ServerWindowTracker tracker_;
95 const ClientSpecificId client_id_;
96 base::WeakPtr<Accelerator> accelerator_;
97
98 DISALLOW_COPY_AND_ASSIGN(ProcessedEventTarget);
99 };
100
101 WindowManagerState::QueuedEvent::QueuedEvent() {}
102 WindowManagerState::QueuedEvent::~QueuedEvent() {}
103
104 WindowManagerState::WindowManagerState(WindowTree* window_tree)
105 : window_tree_(window_tree), event_dispatcher_(this), weak_factory_(this) {
106 frame_decoration_values_ = mojom::FrameDecorationValues::New();
107 frame_decoration_values_->max_title_bar_button_width = 0u;
108
109 AddDebugAccelerators();
110 }
111
112 WindowManagerState::~WindowManagerState() {}
113
114 void WindowManagerState::SetFrameDecorationValues(
115 mojom::FrameDecorationValuesPtr values) {
116 got_frame_decoration_values_ = true;
117 frame_decoration_values_ = values.Clone();
118 display_manager()
119 ->GetUserDisplayManager(user_id())
120 ->OnFrameDecorationValuesChanged();
121 }
122
123 bool WindowManagerState::SetCapture(ServerWindow* window,
124 ClientSpecificId client_id) {
125 DCHECK(IsActive());
126 if (capture_window() == window &&
127 client_id == event_dispatcher_.capture_window_client_id()) {
128 return true;
129 }
130 #if !defined(NDEBUG)
131 if (window) {
132 WindowManagerDisplayRoot* display_root =
133 display_manager()->GetWindowManagerDisplayRoot(window);
134 DCHECK(display_root && display_root->window_manager_state() == this);
135 }
136 #endif
137 return event_dispatcher_.SetCaptureWindow(window, client_id);
138 }
139
140 void WindowManagerState::ReleaseCaptureBlockedByModalWindow(
141 const ServerWindow* modal_window) {
142 event_dispatcher_.ReleaseCaptureBlockedByModalWindow(modal_window);
143 }
144
145 void WindowManagerState::ReleaseCaptureBlockedByAnyModalWindow() {
146 event_dispatcher_.ReleaseCaptureBlockedByAnyModalWindow();
147 }
148
149 void WindowManagerState::AddSystemModalWindow(ServerWindow* window) {
150 DCHECK(!window->transient_parent());
151 event_dispatcher_.AddSystemModalWindow(window);
152 }
153
154 const UserId& WindowManagerState::user_id() const {
155 return window_tree_->user_id();
156 }
157
158 void WindowManagerState::OnWillDestroyTree(WindowTree* tree) {
159 if (tree_awaiting_input_ack_ != tree)
160 return;
161
162 // The WindowTree is dying. So it's not going to ack the event.
163 // If the dying tree matches the root |tree_| marked as handled so we don't
164 // notify it of accelerators.
165 OnEventAck(tree_awaiting_input_ack_, tree == window_tree_
166 ? mojom::EventResult::HANDLED
167 : mojom::EventResult::UNHANDLED);
168 }
169
170 bool WindowManagerState::IsActive() const {
171 return window_server()->user_id_tracker()->active_id() == user_id();
172 }
173
174 void WindowManagerState::Activate(const gfx::Point& mouse_location_on_screen) {
175 SetAllRootWindowsVisible(true);
176 event_dispatcher_.Reset();
177 event_dispatcher_.SetMousePointerScreenLocation(mouse_location_on_screen);
178 }
179
180 void WindowManagerState::Deactivate() {
181 SetAllRootWindowsVisible(false);
182 event_dispatcher_.Reset();
183 // The tree is no longer active, so no point in dispatching any further
184 // events.
185 std::queue<std::unique_ptr<QueuedEvent>> event_queue;
186 event_queue.swap(event_queue_);
187 }
188
189 void WindowManagerState::ProcessEvent(const ui::Event& event) {
190 // If this is still waiting for an ack from a previously sent event, then
191 // queue up the event to be dispatched once the ack is received.
192 if (event_ack_timer_.IsRunning()) {
193 if (!event_queue_.empty() && !event_queue_.back()->processed_target &&
194 EventsCanBeCoalesced(*event_queue_.back()->event, event)) {
195 event_queue_.back()->event = CoalesceEvents(
196 std::move(event_queue_.back()->event), ui::Event::Clone(event));
197 return;
198 }
199 QueueEvent(event, nullptr);
200 return;
201 }
202 event_dispatcher_.ProcessEvent(event);
203 }
204
205 void WindowManagerState::OnEventAck(mojom::WindowTree* tree,
206 mojom::EventResult result) {
207 if (tree_awaiting_input_ack_ != tree) {
208 // TODO(sad): The ack must have arrived after the timeout. We should do
209 // something here, and in OnEventAckTimeout().
210 return;
211 }
212 tree_awaiting_input_ack_ = nullptr;
213 event_ack_timer_.Stop();
214
215 if (result == mojom::EventResult::UNHANDLED && post_target_accelerator_)
216 OnAccelerator(post_target_accelerator_->id(), *event_awaiting_input_ack_);
217
218 ProcessNextEventFromQueue();
219 }
220
221 const WindowServer* WindowManagerState::window_server() const {
222 return window_tree_->window_server();
223 }
224
225 WindowServer* WindowManagerState::window_server() {
226 return window_tree_->window_server();
227 }
228
229 DisplayManager* WindowManagerState::display_manager() {
230 return window_tree_->display_manager();
231 }
232
233 const DisplayManager* WindowManagerState::display_manager() const {
234 return window_tree_->display_manager();
235 }
236
237 void WindowManagerState::SetAllRootWindowsVisible(bool value) {
238 for (Display* display : display_manager()->displays()) {
239 WindowManagerDisplayRoot* display_root =
240 display->GetWindowManagerDisplayRootForUser(user_id());
241 if (display_root)
242 display_root->root()->SetVisible(value);
243 }
244 }
245
246 ServerWindow* WindowManagerState::GetWindowManagerRoot(ServerWindow* window) {
247 for (Display* display : display_manager()->displays()) {
248 WindowManagerDisplayRoot* display_root =
249 display->GetWindowManagerDisplayRootForUser(user_id());
250 if (display_root && display_root->root()->parent() == window)
251 return display_root->root();
252 }
253 NOTREACHED();
254 return nullptr;
255 }
256
257 void WindowManagerState::OnEventAckTimeout(ClientSpecificId client_id) {
258 WindowTree* hung_tree = window_server()->GetTreeWithId(client_id);
259 if (hung_tree && !hung_tree->janky())
260 window_tree_->ClientJankinessChanged(hung_tree);
261 OnEventAck(tree_awaiting_input_ack_, mojom::EventResult::UNHANDLED);
262 }
263
264 void WindowManagerState::QueueEvent(
265 const ui::Event& event,
266 std::unique_ptr<ProcessedEventTarget> processed_event_target) {
267 std::unique_ptr<QueuedEvent> queued_event(new QueuedEvent);
268 queued_event->event = ui::Event::Clone(event);
269 queued_event->processed_target = std::move(processed_event_target);
270 event_queue_.push(std::move(queued_event));
271 }
272
273 void WindowManagerState::ProcessNextEventFromQueue() {
274 // Loop through |event_queue_| stopping after dispatching the first valid
275 // event.
276 while (!event_queue_.empty()) {
277 std::unique_ptr<QueuedEvent> queued_event = std::move(event_queue_.front());
278 event_queue_.pop();
279 if (!queued_event->processed_target) {
280 event_dispatcher_.ProcessEvent(*queued_event->event);
281 return;
282 }
283 if (queued_event->processed_target->IsValid()) {
284 DispatchInputEventToWindowImpl(
285 queued_event->processed_target->window(),
286 queued_event->processed_target->client_id(), *queued_event->event,
287 queued_event->processed_target->accelerator());
288 return;
289 }
290 }
291 }
292
293 void WindowManagerState::DispatchInputEventToWindowImpl(
294 ServerWindow* target,
295 ClientSpecificId client_id,
296 const ui::Event& event,
297 base::WeakPtr<Accelerator> accelerator) {
298 if (target && target->parent() == nullptr)
299 target = GetWindowManagerRoot(target);
300
301 if (event.IsMousePointerEvent()) {
302 DCHECK(event_dispatcher_.mouse_cursor_source_window());
303
304 int32_t cursor_id = 0;
305 if (event_dispatcher_.GetCurrentMouseCursor(&cursor_id)) {
306 WindowManagerDisplayRoot* display_root =
307 display_manager()->GetWindowManagerDisplayRoot(target);
308 display_root->display()->UpdateNativeCursor(cursor_id);
309 }
310 }
311
312 WindowTree* tree = window_server()->GetTreeWithId(client_id);
313
314 // TOOD(sad): Adjust this delay, possibly make this dynamic.
315 const base::TimeDelta max_delay = base::debug::BeingDebugged()
316 ? base::TimeDelta::FromDays(1)
317 : GetDefaultAckTimerDelay();
318 event_ack_timer_.Start(
319 FROM_HERE, max_delay,
320 base::Bind(&WindowManagerState::OnEventAckTimeout,
321 weak_factory_.GetWeakPtr(), tree->id()));
322
323 tree_awaiting_input_ack_ = tree;
324 if (accelerator) {
325 event_awaiting_input_ack_ = ui::Event::Clone(event);
326 post_target_accelerator_ = accelerator;
327 }
328
329 // Ignore |tree| because it will receive the event via normal dispatch.
330 window_server()->SendToEventObservers(event, user_id(), tree);
331
332 tree->DispatchInputEvent(target, event);
333 }
334
335 void WindowManagerState::AddDebugAccelerators() {
336 // Always register the accelerators, even if they only work in debug, so that
337 // keyboard behavior is the same in release and debug builds.
338 mojom::EventMatcherPtr matcher = CreateKeyMatcher(
339 ui::mojom::KeyboardCode::S, ui::mojom::kEventFlagControlDown |
340 ui::mojom::kEventFlagAltDown |
341 ui::mojom::kEventFlagShiftDown);
342 event_dispatcher_.AddAccelerator(kPrintWindowsDebugAcceleratorId,
343 std::move(matcher));
344 }
345
346 bool WindowManagerState::HandleDebugAccelerator(uint32_t accelerator_id) {
347 #if !defined(NDEBUG)
348 if (accelerator_id == kPrintWindowsDebugAcceleratorId) {
349 // Error so it will be collected in system logs.
350 for (Display* display : display_manager()->displays()) {
351 WindowManagerDisplayRoot* display_root =
352 display->GetWindowManagerDisplayRootForUser(user_id());
353 if (display_root) {
354 LOG(ERROR) << "ServerWindow hierarchy:\n"
355 << display_root->root()->GetDebugWindowHierarchy();
356 }
357 }
358 return true;
359 }
360 #endif
361 return false;
362 }
363
364 ////////////////////////////////////////////////////////////////////////////////
365 // EventDispatcherDelegate:
366
367 void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
368 const ui::Event& event) {
369 DCHECK(IsActive());
370 if (HandleDebugAccelerator(accelerator_id))
371 return;
372 window_tree_->OnAccelerator(accelerator_id, event);
373 }
374
375 void WindowManagerState::SetFocusedWindowFromEventDispatcher(
376 ServerWindow* new_focused_window) {
377 DCHECK(IsActive());
378 window_server()->SetFocusedWindow(new_focused_window);
379 }
380
381 ServerWindow* WindowManagerState::GetFocusedWindowForEventDispatcher() {
382 return window_server()->GetFocusedWindow();
383 }
384
385 void WindowManagerState::SetNativeCapture(ServerWindow* window) {
386 DCHECK(IsActive());
387 WindowManagerDisplayRoot* display_root =
388 display_manager()->GetWindowManagerDisplayRoot(window);
389 DCHECK(display_root);
390 platform_display_with_capture_ = display_root->display()->platform_display();
391 platform_display_with_capture_->SetCapture();
392 }
393
394 void WindowManagerState::ReleaseNativeCapture() {
395 // Tests trigger calling this without a corresponding SetNativeCapture().
396 // TODO(sky): maybe abstract this away so that DCHECK can be added?
397 if (!platform_display_with_capture_)
398 return;
399
400 platform_display_with_capture_->ReleaseCapture();
401 platform_display_with_capture_ = nullptr;
402 }
403
404 void WindowManagerState::OnServerWindowCaptureLost(ServerWindow* window) {
405 DCHECK(window);
406 window_server()->ProcessLostCapture(window);
407 }
408
409 void WindowManagerState::OnMouseCursorLocationChanged(const gfx::Point& point) {
410 window_server()
411 ->display_manager()
412 ->GetUserDisplayManager(user_id())
413 ->OnMouseCursorLocationChanged(point);
414 }
415
416 void WindowManagerState::DispatchInputEventToWindow(ServerWindow* target,
417 ClientSpecificId client_id,
418 const ui::Event& event,
419 Accelerator* accelerator) {
420 DCHECK(IsActive());
421 // TODO(sky): this needs to see if another wms has capture and if so forward
422 // to it.
423 if (event_ack_timer_.IsRunning()) {
424 std::unique_ptr<ProcessedEventTarget> processed_event_target(
425 new ProcessedEventTarget(target, client_id, accelerator));
426 QueueEvent(event, std::move(processed_event_target));
427 return;
428 }
429
430 base::WeakPtr<Accelerator> weak_accelerator;
431 if (accelerator)
432 weak_accelerator = accelerator->GetWeakPtr();
433 DispatchInputEventToWindowImpl(target, client_id, event, weak_accelerator);
434 }
435
436 ClientSpecificId WindowManagerState::GetEventTargetClientId(
437 const ServerWindow* window,
438 bool in_nonclient_area) {
439 // If the event is in the non-client area the event goes to the owner of
440 // the window.
441 WindowTree* tree = nullptr;
442 if (in_nonclient_area) {
443 tree = window_server()->GetTreeWithId(window->id().client_id);
444 } else {
445 // If the window is an embed root, forward to the embedded window.
446 tree = window_server()->GetTreeWithRoot(window);
447 if (!tree)
448 tree = window_server()->GetTreeWithId(window->id().client_id);
449 }
450
451 const ServerWindow* embed_root =
452 tree->HasRoot(window) ? window : GetEmbedRoot(window);
453 while (tree && tree->embedder_intercepts_events()) {
454 DCHECK(tree->HasRoot(embed_root));
455 tree = window_server()->GetTreeWithId(embed_root->id().client_id);
456 embed_root = GetEmbedRoot(embed_root);
457 }
458
459 if (!tree) {
460 DCHECK(in_nonclient_area);
461 tree = window_tree_;
462 }
463 return tree->id();
464 }
465
466 ServerWindow* WindowManagerState::GetRootWindowContaining(
467 const gfx::Point& location) {
468 if (display_manager()->displays().empty())
469 return nullptr;
470
471 // TODO(sky): this isn't right. To correctly implement need bounds of
472 // Display, which we aren't tracking yet. For now, use the first display.
473 Display* display = *(display_manager()->displays().begin());
474 WindowManagerDisplayRoot* display_root =
475 display->GetWindowManagerDisplayRootForUser(user_id());
476 return display_root ? display_root->root() : nullptr;
477 }
478
479 void WindowManagerState::OnEventTargetNotFound(const ui::Event& event) {
480 window_server()->SendToEventObservers(event, user_id(),
481 nullptr /* ignore_tree */);
482 }
483
484 } // namespace ws
485 } // namespace mus
OLDNEW
« no previous file with comments | « components/mus/ws/window_manager_state.h ('k') | components/mus/ws/window_manager_state_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698