OLD | NEW |
| (Empty) |
1 // Copyright 2014 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_tree.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <utility> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/stl_util.h" | |
15 #include "components/mus/ws/default_access_policy.h" | |
16 #include "components/mus/ws/display.h" | |
17 #include "components/mus/ws/display_manager.h" | |
18 #include "components/mus/ws/event_matcher.h" | |
19 #include "components/mus/ws/focus_controller.h" | |
20 #include "components/mus/ws/operation.h" | |
21 #include "components/mus/ws/platform_display.h" | |
22 #include "components/mus/ws/server_window.h" | |
23 #include "components/mus/ws/server_window_observer.h" | |
24 #include "components/mus/ws/user_display_manager.h" | |
25 #include "components/mus/ws/window_manager_display_root.h" | |
26 #include "components/mus/ws/window_manager_state.h" | |
27 #include "components/mus/ws/window_server.h" | |
28 #include "components/mus/ws/window_tree_binding.h" | |
29 #include "ui/display/display.h" | |
30 #include "ui/platform_window/mojo/ime_type_converters.h" | |
31 #include "ui/platform_window/text_input_state.h" | |
32 | |
33 using mojo::Array; | |
34 using mojo::InterfaceRequest; | |
35 using mojo::String; | |
36 | |
37 namespace mus { | |
38 namespace ws { | |
39 | |
40 class TargetedEvent : public ServerWindowObserver { | |
41 public: | |
42 TargetedEvent(ServerWindow* target, const ui::Event& event) | |
43 : target_(target), event_(ui::Event::Clone(event)) { | |
44 target_->AddObserver(this); | |
45 } | |
46 ~TargetedEvent() override { | |
47 if (target_) | |
48 target_->RemoveObserver(this); | |
49 } | |
50 | |
51 ServerWindow* target() { return target_; } | |
52 std::unique_ptr<ui::Event> TakeEvent() { return std::move(event_); } | |
53 | |
54 private: | |
55 // ServerWindowObserver: | |
56 void OnWindowDestroyed(ServerWindow* window) override { | |
57 DCHECK_EQ(target_, window); | |
58 target_->RemoveObserver(this); | |
59 target_ = nullptr; | |
60 } | |
61 | |
62 ServerWindow* target_; | |
63 std::unique_ptr<ui::Event> event_; | |
64 | |
65 DISALLOW_COPY_AND_ASSIGN(TargetedEvent); | |
66 }; | |
67 | |
68 WindowTree::WindowTree(WindowServer* window_server, | |
69 const UserId& user_id, | |
70 ServerWindow* root, | |
71 std::unique_ptr<AccessPolicy> access_policy) | |
72 : window_server_(window_server), | |
73 user_id_(user_id), | |
74 id_(window_server_->GetAndAdvanceNextClientId()), | |
75 next_window_id_(1), | |
76 access_policy_(std::move(access_policy)), | |
77 event_ack_id_(0), | |
78 window_manager_internal_(nullptr) { | |
79 if (root) | |
80 roots_.insert(root); | |
81 access_policy_->Init(id_, this); | |
82 } | |
83 | |
84 WindowTree::~WindowTree() { | |
85 DestroyWindows(); | |
86 } | |
87 | |
88 void WindowTree::Init(std::unique_ptr<WindowTreeBinding> binding, | |
89 mojom::WindowTreePtr tree) { | |
90 DCHECK(!binding_); | |
91 binding_ = std::move(binding); | |
92 | |
93 if (roots_.empty()) | |
94 return; | |
95 | |
96 std::vector<const ServerWindow*> to_send; | |
97 CHECK_EQ(1u, roots_.size()); | |
98 const ServerWindow* root = *roots_.begin(); | |
99 GetUnknownWindowsFrom(root, &to_send); | |
100 | |
101 Display* display = GetDisplay(root); | |
102 int64_t display_id = | |
103 display ? display->id() : display::Display::kInvalidDisplayID; | |
104 const ServerWindow* focused_window = | |
105 display ? display->GetFocusedWindow() : nullptr; | |
106 if (focused_window) | |
107 focused_window = access_policy_->GetWindowForFocusChange(focused_window); | |
108 ClientWindowId focused_window_id; | |
109 if (focused_window) | |
110 IsWindowKnown(focused_window, &focused_window_id); | |
111 | |
112 const bool drawn = root->parent() && root->parent()->IsDrawn(); | |
113 client()->OnEmbed(id_, WindowToWindowData(to_send.front()), std::move(tree), | |
114 display_id, focused_window_id.id, drawn); | |
115 } | |
116 | |
117 void WindowTree::ConfigureWindowManager() { | |
118 DCHECK(!window_manager_internal_); | |
119 window_manager_internal_ = binding_->GetWindowManager(); | |
120 window_manager_internal_->OnConnect(id_); | |
121 window_manager_state_.reset(new WindowManagerState(this)); | |
122 } | |
123 | |
124 const ServerWindow* WindowTree::GetWindow(const WindowId& id) const { | |
125 if (id_ == id.client_id) { | |
126 auto iter = created_window_map_.find(id); | |
127 return iter == created_window_map_.end() ? nullptr : iter->second; | |
128 } | |
129 return window_server_->GetWindow(id); | |
130 } | |
131 | |
132 bool WindowTree::IsWindowKnown(const ServerWindow* window, | |
133 ClientWindowId* id) const { | |
134 if (!window) | |
135 return false; | |
136 auto iter = window_id_to_client_id_map_.find(window->id()); | |
137 if (iter == window_id_to_client_id_map_.end()) | |
138 return false; | |
139 if (id) | |
140 *id = iter->second; | |
141 return true; | |
142 } | |
143 | |
144 bool WindowTree::HasRoot(const ServerWindow* window) const { | |
145 return roots_.count(window) > 0; | |
146 } | |
147 | |
148 const ServerWindow* WindowTree::GetWindowByClientId( | |
149 const ClientWindowId& id) const { | |
150 auto iter = client_id_to_window_id_map_.find(id); | |
151 return iter == client_id_to_window_id_map_.end() ? nullptr | |
152 : GetWindow(iter->second); | |
153 } | |
154 | |
155 const Display* WindowTree::GetDisplay(const ServerWindow* window) const { | |
156 return window ? display_manager()->GetDisplayContaining(window) : nullptr; | |
157 } | |
158 | |
159 const WindowManagerDisplayRoot* WindowTree::GetWindowManagerDisplayRoot( | |
160 const ServerWindow* window) const { | |
161 return window ? display_manager()->GetWindowManagerDisplayRoot(window) | |
162 : nullptr; | |
163 } | |
164 | |
165 DisplayManager* WindowTree::display_manager() { | |
166 return window_server_->display_manager(); | |
167 } | |
168 | |
169 const DisplayManager* WindowTree::display_manager() const { | |
170 return window_server_->display_manager(); | |
171 } | |
172 | |
173 void WindowTree::AddRootForWindowManager(const ServerWindow* root) { | |
174 DCHECK(window_manager_internal_); | |
175 const ClientWindowId client_window_id(WindowIdToTransportId(root->id())); | |
176 DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id)); | |
177 client_id_to_window_id_map_[client_window_id] = root->id(); | |
178 window_id_to_client_id_map_[root->id()] = client_window_id; | |
179 roots_.insert(root); | |
180 | |
181 Display* display = GetDisplay(root); | |
182 DCHECK(display); | |
183 | |
184 window_manager_internal_->WmNewDisplayAdded(display->ToMojomDisplay(), | |
185 WindowToWindowData(root), | |
186 root->parent()->IsDrawn()); | |
187 } | |
188 | |
189 void WindowTree::OnWindowDestroyingTreeImpl(WindowTree* tree) { | |
190 if (window_manager_state_) | |
191 window_manager_state_->OnWillDestroyTree(tree); | |
192 | |
193 if (event_source_wms_ && event_source_wms_->window_tree() == tree) | |
194 event_source_wms_ = nullptr; | |
195 | |
196 // Notify our client if |tree| was embedded in any of our views. | |
197 for (const auto* tree_root : tree->roots_) { | |
198 const bool owns_tree_root = tree_root->id().client_id == id_; | |
199 if (owns_tree_root) { | |
200 client()->OnEmbeddedAppDisconnected( | |
201 ClientWindowIdForWindow(tree_root).id); | |
202 } | |
203 } | |
204 } | |
205 | |
206 void WindowTree::NotifyChangeCompleted( | |
207 uint32_t change_id, | |
208 mojom::WindowManagerErrorCode error_code) { | |
209 client()->OnChangeCompleted( | |
210 change_id, error_code == mojom::WindowManagerErrorCode::SUCCESS); | |
211 } | |
212 | |
213 bool WindowTree::SetCapture(const ClientWindowId& client_window_id) { | |
214 ServerWindow* window = GetWindowByClientId(client_window_id); | |
215 WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window); | |
216 ServerWindow* current_capture_window = | |
217 display_root ? display_root->window_manager_state()->capture_window() | |
218 : nullptr; | |
219 if (window && window->IsDrawn() && display_root && | |
220 display_root->window_manager_state()->IsActive() && | |
221 access_policy_->CanSetCapture(window) && | |
222 (!current_capture_window || | |
223 access_policy_->CanSetCapture(current_capture_window))) { | |
224 return display_root->window_manager_state()->SetCapture(window, id_); | |
225 } | |
226 return false; | |
227 } | |
228 | |
229 bool WindowTree::NewWindow( | |
230 const ClientWindowId& client_window_id, | |
231 const std::map<std::string, std::vector<uint8_t>>& properties) { | |
232 if (!IsValidIdForNewWindow(client_window_id)) | |
233 return false; | |
234 const WindowId window_id = GenerateNewWindowId(); | |
235 DCHECK(!GetWindow(window_id)); | |
236 ServerWindow* window = | |
237 window_server_->CreateServerWindow(window_id, properties); | |
238 created_window_map_[window_id] = window; | |
239 client_id_to_window_id_map_[client_window_id] = window_id; | |
240 window_id_to_client_id_map_[window_id] = client_window_id; | |
241 return true; | |
242 } | |
243 | |
244 bool WindowTree::AddWindow(const ClientWindowId& parent_id, | |
245 const ClientWindowId& child_id) { | |
246 ServerWindow* parent = GetWindowByClientId(parent_id); | |
247 ServerWindow* child = GetWindowByClientId(child_id); | |
248 if (parent && child && child->parent() != parent && | |
249 !child->Contains(parent) && access_policy_->CanAddWindow(parent, child)) { | |
250 Operation op(this, window_server_, OperationType::ADD_WINDOW); | |
251 parent->Add(child); | |
252 return true; | |
253 } | |
254 return false; | |
255 } | |
256 | |
257 bool WindowTree::AddTransientWindow(const ClientWindowId& window_id, | |
258 const ClientWindowId& transient_window_id) { | |
259 ServerWindow* window = GetWindowByClientId(window_id); | |
260 ServerWindow* transient_window = GetWindowByClientId(transient_window_id); | |
261 if (window && transient_window && !transient_window->Contains(window) && | |
262 access_policy_->CanAddTransientWindow(window, transient_window)) { | |
263 Operation op(this, window_server_, OperationType::ADD_TRANSIENT_WINDOW); | |
264 return window->AddTransientWindow(transient_window); | |
265 } | |
266 return false; | |
267 } | |
268 | |
269 bool WindowTree::SetModal(const ClientWindowId& window_id) { | |
270 ServerWindow* window = GetWindowByClientId(window_id); | |
271 if (window && access_policy_->CanSetModal(window)) { | |
272 WindowManagerDisplayRoot* display_root = | |
273 GetWindowManagerDisplayRoot(window); | |
274 if (window->transient_parent()) { | |
275 window->SetModal(); | |
276 } else if (user_id_ != InvalidUserId()) { | |
277 if (display_root) | |
278 display_root->window_manager_state()->AddSystemModalWindow(window); | |
279 } else { | |
280 return false; | |
281 } | |
282 if (display_root) | |
283 display_root->window_manager_state()->ReleaseCaptureBlockedByModalWindow( | |
284 window); | |
285 return true; | |
286 } | |
287 return false; | |
288 } | |
289 | |
290 std::vector<const ServerWindow*> WindowTree::GetWindowTree( | |
291 const ClientWindowId& window_id) const { | |
292 const ServerWindow* window = GetWindowByClientId(window_id); | |
293 std::vector<const ServerWindow*> windows; | |
294 if (window) | |
295 GetWindowTreeImpl(window, &windows); | |
296 return windows; | |
297 } | |
298 | |
299 bool WindowTree::SetWindowVisibility(const ClientWindowId& window_id, | |
300 bool visible) { | |
301 ServerWindow* window = GetWindowByClientId(window_id); | |
302 if (!window || !access_policy_->CanChangeWindowVisibility(window)) | |
303 return false; | |
304 if (window->visible() == visible) | |
305 return true; | |
306 Operation op(this, window_server_, OperationType::SET_WINDOW_VISIBILITY); | |
307 window->SetVisible(visible); | |
308 return true; | |
309 } | |
310 | |
311 bool WindowTree::SetWindowOpacity(const ClientWindowId& window_id, | |
312 float opacity) { | |
313 ServerWindow* window = GetWindowByClientId(window_id); | |
314 if (!window || !access_policy_->CanChangeWindowOpacity(window)) | |
315 return false; | |
316 if (window->opacity() == opacity) | |
317 return true; | |
318 Operation op(this, window_server_, OperationType::SET_WINDOW_OPACITY); | |
319 window->SetOpacity(opacity); | |
320 return true; | |
321 } | |
322 | |
323 bool WindowTree::SetFocus(const ClientWindowId& window_id) { | |
324 ServerWindow* window = GetWindowByClientId(window_id); | |
325 ServerWindow* currently_focused = window_server_->GetFocusedWindow(); | |
326 if (!currently_focused && !window) { | |
327 DVLOG(1) << "SetFocus failure, no focused window to clear."; | |
328 return false; | |
329 } | |
330 | |
331 Display* display = GetDisplay(window); | |
332 if (window && (!display || !window->can_focus() || !window->IsDrawn())) { | |
333 DVLOG(1) << "SetFocus failure, window cannot be focused."; | |
334 return false; | |
335 } | |
336 | |
337 if (!access_policy_->CanSetFocus(window)) { | |
338 DVLOG(1) << "SetFocus failure, blocked by access policy."; | |
339 return false; | |
340 } | |
341 | |
342 Operation op(this, window_server_, OperationType::SET_FOCUS); | |
343 bool success = window_server_->SetFocusedWindow(window); | |
344 if (!success) { | |
345 DVLOG(1) << "SetFocus failure, could not SetFocusedWindow."; | |
346 } | |
347 return success; | |
348 } | |
349 | |
350 bool WindowTree::Embed(const ClientWindowId& window_id, | |
351 mojom::WindowTreeClientPtr client, | |
352 uint32_t flags) { | |
353 if (!client || !CanEmbed(window_id)) | |
354 return false; | |
355 ServerWindow* window = GetWindowByClientId(window_id); | |
356 PrepareForEmbed(window); | |
357 // When embedding we don't know the user id of where the TreeClient came | |
358 // from. Use an invalid id, which limits what the client is able to do. | |
359 window_server_->EmbedAtWindow(window, InvalidUserId(), std::move(client), | |
360 flags, | |
361 base::WrapUnique(new DefaultAccessPolicy)); | |
362 return true; | |
363 } | |
364 | |
365 void WindowTree::DispatchInputEvent(ServerWindow* target, | |
366 const ui::Event& event) { | |
367 if (event_ack_id_) { | |
368 // This is currently waiting for an event ack. Add it to the queue. | |
369 event_queue_.push(base::WrapUnique(new TargetedEvent(target, event))); | |
370 // TODO(sad): If the |event_queue_| grows too large, then this should notify | |
371 // Display, so that it can stop sending events. | |
372 return; | |
373 } | |
374 | |
375 // If there are events in the queue, then store this new event in the queue, | |
376 // and dispatch the latest event from the queue instead that still has a live | |
377 // target. | |
378 if (!event_queue_.empty()) { | |
379 event_queue_.push(base::WrapUnique(new TargetedEvent(target, event))); | |
380 return; | |
381 } | |
382 | |
383 DispatchInputEventImpl(target, event); | |
384 } | |
385 | |
386 bool WindowTree::IsWaitingForNewTopLevelWindow(uint32_t wm_change_id) { | |
387 return waiting_for_top_level_window_info_ && | |
388 waiting_for_top_level_window_info_->wm_change_id == wm_change_id; | |
389 } | |
390 | |
391 void WindowTree::OnWindowManagerCreatedTopLevelWindow( | |
392 uint32_t wm_change_id, | |
393 uint32_t client_change_id, | |
394 const ServerWindow* window) { | |
395 DCHECK(IsWaitingForNewTopLevelWindow(wm_change_id)); | |
396 std::unique_ptr<WaitingForTopLevelWindowInfo> | |
397 waiting_for_top_level_window_info( | |
398 std::move(waiting_for_top_level_window_info_)); | |
399 binding_->SetIncomingMethodCallProcessingPaused(false); | |
400 // We were paused, so the id should still be valid. | |
401 DCHECK(IsValidIdForNewWindow( | |
402 waiting_for_top_level_window_info->client_window_id)); | |
403 client_id_to_window_id_map_[waiting_for_top_level_window_info | |
404 ->client_window_id] = window->id(); | |
405 window_id_to_client_id_map_[window->id()] = | |
406 waiting_for_top_level_window_info->client_window_id; | |
407 roots_.insert(window); | |
408 Display* display = GetDisplay(window); | |
409 int64_t display_id = | |
410 display ? display->id() : display::Display::kInvalidDisplayID; | |
411 const bool drawn = window->parent() && window->parent()->IsDrawn(); | |
412 client()->OnTopLevelCreated(client_change_id, WindowToWindowData(window), | |
413 display_id, drawn); | |
414 } | |
415 | |
416 void WindowTree::AddActivationParent(const ClientWindowId& window_id) { | |
417 ServerWindow* window = GetWindowByClientId(window_id); | |
418 if (window) { | |
419 Display* display = GetDisplay(window); | |
420 if (display) | |
421 display->AddActivationParent(window); | |
422 else | |
423 DVLOG(1) << "AddActivationParent window not associated with display"; | |
424 } else { | |
425 DVLOG(1) << "AddActivationParent supplied invalid window id"; | |
426 } | |
427 } | |
428 | |
429 void WindowTree::OnChangeCompleted(uint32_t change_id, bool success) { | |
430 client()->OnChangeCompleted(change_id, success); | |
431 } | |
432 | |
433 void WindowTree::OnAccelerator(uint32_t accelerator_id, | |
434 const ui::Event& event) { | |
435 DCHECK(window_manager_internal_); | |
436 // TODO(moshayedi): crbug.com/617167. Don't clone even once we map | |
437 // mojom::Event directly to ui::Event. | |
438 window_manager_internal_->OnAccelerator(accelerator_id, | |
439 ui::Event::Clone(event)); | |
440 } | |
441 | |
442 void WindowTree::ClientJankinessChanged(WindowTree* tree) { | |
443 tree->janky_ = !tree->janky_; | |
444 if (window_manager_internal_) { | |
445 window_manager_internal_->WmClientJankinessChanged( | |
446 tree->id(), tree->janky()); | |
447 } | |
448 } | |
449 | |
450 void WindowTree::ProcessWindowBoundsChanged(const ServerWindow* window, | |
451 const gfx::Rect& old_bounds, | |
452 const gfx::Rect& new_bounds, | |
453 bool originated_change) { | |
454 ClientWindowId client_window_id; | |
455 if (originated_change || !IsWindowKnown(window, &client_window_id)) | |
456 return; | |
457 client()->OnWindowBoundsChanged(client_window_id.id, old_bounds, new_bounds); | |
458 } | |
459 | |
460 void WindowTree::ProcessClientAreaChanged( | |
461 const ServerWindow* window, | |
462 const gfx::Insets& new_client_area, | |
463 const std::vector<gfx::Rect>& new_additional_client_areas, | |
464 bool originated_change) { | |
465 ClientWindowId client_window_id; | |
466 if (originated_change || !IsWindowKnown(window, &client_window_id)) | |
467 return; | |
468 client()->OnClientAreaChanged( | |
469 client_window_id.id, new_client_area, | |
470 std::vector<gfx::Rect>(new_additional_client_areas)); | |
471 } | |
472 | |
473 void WindowTree::ProcessWillChangeWindowHierarchy( | |
474 const ServerWindow* window, | |
475 const ServerWindow* new_parent, | |
476 const ServerWindow* old_parent, | |
477 bool originated_change) { | |
478 if (originated_change) | |
479 return; | |
480 | |
481 const bool old_drawn = window->IsDrawn(); | |
482 const bool new_drawn = | |
483 window->visible() && new_parent && new_parent->IsDrawn(); | |
484 if (old_drawn == new_drawn) | |
485 return; | |
486 | |
487 NotifyDrawnStateChanged(window, new_drawn); | |
488 } | |
489 | |
490 void WindowTree::ProcessWindowPropertyChanged( | |
491 const ServerWindow* window, | |
492 const std::string& name, | |
493 const std::vector<uint8_t>* new_data, | |
494 bool originated_change) { | |
495 if (originated_change) | |
496 return; | |
497 | |
498 ClientWindowId client_window_id; | |
499 if (!IsWindowKnown(window, &client_window_id)) | |
500 return; | |
501 | |
502 Array<uint8_t> data(nullptr); | |
503 if (new_data) | |
504 data = Array<uint8_t>::From(*new_data); | |
505 | |
506 client()->OnWindowSharedPropertyChanged(client_window_id.id, String(name), | |
507 std::move(data)); | |
508 } | |
509 | |
510 void WindowTree::ProcessWindowHierarchyChanged(const ServerWindow* window, | |
511 const ServerWindow* new_parent, | |
512 const ServerWindow* old_parent, | |
513 bool originated_change) { | |
514 const bool knows_new = new_parent && IsWindowKnown(new_parent); | |
515 if (originated_change && !IsWindowKnown(window) && knows_new) { | |
516 std::vector<const ServerWindow*> unused; | |
517 GetUnknownWindowsFrom(window, &unused); | |
518 } | |
519 if (originated_change || (window_server_->current_operation_type() == | |
520 OperationType::DELETE_WINDOW) || | |
521 (window_server_->current_operation_type() == OperationType::EMBED) || | |
522 window_server_->DidTreeMessageClient(id_)) { | |
523 return; | |
524 } | |
525 | |
526 if (!access_policy_->ShouldNotifyOnHierarchyChange(window, &new_parent, | |
527 &old_parent)) { | |
528 return; | |
529 } | |
530 // Inform the client of any new windows and update the set of windows we know | |
531 // about. | |
532 std::vector<const ServerWindow*> to_send; | |
533 if (!IsWindowKnown(window)) | |
534 GetUnknownWindowsFrom(window, &to_send); | |
535 const bool knows_old = old_parent && IsWindowKnown(old_parent); | |
536 if (!knows_old && !knows_new) | |
537 return; | |
538 | |
539 const ClientWindowId new_parent_client_window_id = | |
540 knows_new ? ClientWindowIdForWindow(new_parent) : ClientWindowId(); | |
541 const ClientWindowId old_parent_client_window_id = | |
542 knows_old ? ClientWindowIdForWindow(old_parent) : ClientWindowId(); | |
543 const ClientWindowId client_window_id = | |
544 window ? ClientWindowIdForWindow(window) : ClientWindowId(); | |
545 client()->OnWindowHierarchyChanged( | |
546 client_window_id.id, old_parent_client_window_id.id, | |
547 new_parent_client_window_id.id, WindowsToWindowDatas(to_send)); | |
548 window_server_->OnTreeMessagedClient(id_); | |
549 } | |
550 | |
551 void WindowTree::ProcessWindowReorder(const ServerWindow* window, | |
552 const ServerWindow* relative_window, | |
553 mojom::OrderDirection direction, | |
554 bool originated_change) { | |
555 DCHECK_EQ(window->parent(), relative_window->parent()); | |
556 ClientWindowId client_window_id, relative_client_window_id; | |
557 if (originated_change || !IsWindowKnown(window, &client_window_id) || | |
558 !IsWindowKnown(relative_window, &relative_client_window_id) || | |
559 window_server_->DidTreeMessageClient(id_)) | |
560 return; | |
561 | |
562 // Do not notify ordering changes of the root windows, since the client | |
563 // doesn't know about the ancestors of the roots, and so can't do anything | |
564 // about this ordering change of the root. | |
565 if (HasRoot(window) || HasRoot(relative_window)) | |
566 return; | |
567 | |
568 client()->OnWindowReordered(client_window_id.id, relative_client_window_id.id, | |
569 direction); | |
570 window_server_->OnTreeMessagedClient(id_); | |
571 } | |
572 | |
573 void WindowTree::ProcessWindowDeleted(const ServerWindow* window, | |
574 bool originated_change) { | |
575 if (window->id().client_id == id_) | |
576 created_window_map_.erase(window->id()); | |
577 | |
578 ClientWindowId client_window_id; | |
579 if (!IsWindowKnown(window, &client_window_id)) | |
580 return; | |
581 | |
582 if (HasRoot(window)) | |
583 RemoveRoot(window, RemoveRootReason::DELETED); | |
584 else | |
585 RemoveFromMaps(window); | |
586 | |
587 if (originated_change) | |
588 return; | |
589 | |
590 client()->OnWindowDeleted(client_window_id.id); | |
591 window_server_->OnTreeMessagedClient(id_); | |
592 } | |
593 | |
594 void WindowTree::ProcessWillChangeWindowVisibility(const ServerWindow* window, | |
595 bool originated_change) { | |
596 if (originated_change) | |
597 return; | |
598 | |
599 ClientWindowId client_window_id; | |
600 if (IsWindowKnown(window, &client_window_id)) { | |
601 client()->OnWindowVisibilityChanged(client_window_id.id, | |
602 !window->visible()); | |
603 return; | |
604 } | |
605 | |
606 bool window_target_drawn_state; | |
607 if (window->visible()) { | |
608 // Window is being hidden, won't be drawn. | |
609 window_target_drawn_state = false; | |
610 } else { | |
611 // Window is being shown. Window will be drawn if its parent is drawn. | |
612 window_target_drawn_state = window->parent() && window->parent()->IsDrawn(); | |
613 } | |
614 | |
615 NotifyDrawnStateChanged(window, window_target_drawn_state); | |
616 } | |
617 | |
618 void WindowTree::ProcessWindowOpacityChanged(const ServerWindow* window, | |
619 float old_opacity, | |
620 float new_opacity, | |
621 bool originated_change) { | |
622 if (originated_change) | |
623 return; | |
624 | |
625 ClientWindowId client_window_id; | |
626 if (IsWindowKnown(window, &client_window_id)) { | |
627 client()->OnWindowOpacityChanged(client_window_id.id, old_opacity, | |
628 new_opacity); | |
629 } | |
630 } | |
631 | |
632 void WindowTree::ProcessCursorChanged(const ServerWindow* window, | |
633 int32_t cursor_id, | |
634 bool originated_change) { | |
635 if (originated_change) | |
636 return; | |
637 ClientWindowId client_window_id; | |
638 if (!IsWindowKnown(window, &client_window_id)) | |
639 return; | |
640 | |
641 client()->OnWindowPredefinedCursorChanged(client_window_id.id, | |
642 mojom::Cursor(cursor_id)); | |
643 } | |
644 | |
645 void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window, | |
646 const ServerWindow* new_focused_window) { | |
647 if (window_server_->current_operation_type() == OperationType::SET_FOCUS && | |
648 window_server_->IsOperationSource(id_)) { | |
649 return; | |
650 } | |
651 const ServerWindow* window = | |
652 new_focused_window | |
653 ? access_policy_->GetWindowForFocusChange(new_focused_window) | |
654 : nullptr; | |
655 ClientWindowId client_window_id; | |
656 // If the window isn't known we'll supply null, which is ok. | |
657 IsWindowKnown(window, &client_window_id); | |
658 client()->OnWindowFocused(client_window_id.id); | |
659 } | |
660 | |
661 void WindowTree::ProcessTransientWindowAdded( | |
662 const ServerWindow* window, | |
663 const ServerWindow* transient_window, | |
664 bool originated_change) { | |
665 if (originated_change) | |
666 return; | |
667 | |
668 ClientWindowId client_window_id, transient_client_window_id; | |
669 if (!IsWindowKnown(window, &client_window_id) || | |
670 !IsWindowKnown(transient_window, &transient_client_window_id)) { | |
671 return; | |
672 } | |
673 client()->OnTransientWindowAdded(client_window_id.id, | |
674 transient_client_window_id.id); | |
675 } | |
676 | |
677 void WindowTree::ProcessTransientWindowRemoved( | |
678 const ServerWindow* window, | |
679 const ServerWindow* transient_window, | |
680 bool originated_change) { | |
681 if (originated_change) | |
682 return; | |
683 ClientWindowId client_window_id, transient_client_window_id; | |
684 if (!IsWindowKnown(window, &client_window_id) || | |
685 !IsWindowKnown(transient_window, &transient_client_window_id)) { | |
686 return; | |
687 } | |
688 client()->OnTransientWindowRemoved(client_window_id.id, | |
689 transient_client_window_id.id); | |
690 } | |
691 | |
692 bool WindowTree::ShouldRouteToWindowManager(const ServerWindow* window) const { | |
693 if (window_manager_state_) | |
694 return false; // We are the window manager, don't route to ourself. | |
695 | |
696 // If the client created this window, then do not route it through the WM. | |
697 if (window->id().client_id == id_) | |
698 return false; | |
699 | |
700 // If the client did not create the window, then it must be the root of the | |
701 // client. If not, that means the client should not know about this window, | |
702 // and so do not route the request to the WM. | |
703 if (roots_.count(window) == 0) | |
704 return false; | |
705 | |
706 // The WindowManager is attached to the root of the Display, if there isn't a | |
707 // WindowManager attached no need to route to it. | |
708 const WindowManagerDisplayRoot* display_root = | |
709 GetWindowManagerDisplayRoot(window); | |
710 if (!display_root) | |
711 return false; | |
712 | |
713 // Route to the windowmanager if the windowmanager created the window. | |
714 return display_root->window_manager_state()->window_tree()->id() == | |
715 window->id().client_id; | |
716 } | |
717 | |
718 void WindowTree::ProcessLostCapture(const ServerWindow* old_capture_window, | |
719 bool originated_change) { | |
720 if ((originated_change && | |
721 window_server_->current_operation_type() == | |
722 OperationType::RELEASE_CAPTURE) || | |
723 !IsWindowKnown(old_capture_window)) { | |
724 return; | |
725 } | |
726 client()->OnLostCapture(WindowIdToTransportId(old_capture_window->id())); | |
727 } | |
728 | |
729 ClientWindowId WindowTree::ClientWindowIdForWindow( | |
730 const ServerWindow* window) const { | |
731 auto iter = window_id_to_client_id_map_.find(window->id()); | |
732 DCHECK(iter != window_id_to_client_id_map_.end()); | |
733 return iter->second; | |
734 } | |
735 | |
736 bool WindowTree::IsValidIdForNewWindow(const ClientWindowId& id) const { | |
737 // Reserve 0 to indicate a null window. | |
738 return client_id_to_window_id_map_.count(id) == 0u && | |
739 access_policy_->IsValidIdForNewWindow(id) && id != ClientWindowId(); | |
740 } | |
741 | |
742 WindowId WindowTree::GenerateNewWindowId() { | |
743 // TODO(sky): deal with wrapping and uniqueness. | |
744 return WindowId(id_, next_window_id_++); | |
745 } | |
746 | |
747 bool WindowTree::CanReorderWindow(const ServerWindow* window, | |
748 const ServerWindow* relative_window, | |
749 mojom::OrderDirection direction) const { | |
750 if (!window || !relative_window) | |
751 return false; | |
752 | |
753 if (!window->parent() || window->parent() != relative_window->parent()) | |
754 return false; | |
755 | |
756 if (!access_policy_->CanReorderWindow(window, relative_window, direction)) | |
757 return false; | |
758 | |
759 std::vector<const ServerWindow*> children = window->parent()->GetChildren(); | |
760 const size_t child_i = | |
761 std::find(children.begin(), children.end(), window) - children.begin(); | |
762 const size_t target_i = | |
763 std::find(children.begin(), children.end(), relative_window) - | |
764 children.begin(); | |
765 if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) || | |
766 (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) { | |
767 return false; | |
768 } | |
769 | |
770 return true; | |
771 } | |
772 | |
773 bool WindowTree::DeleteWindowImpl(WindowTree* source, ServerWindow* window) { | |
774 DCHECK(window); | |
775 DCHECK_EQ(window->id().client_id, id_); | |
776 Operation op(source, window_server_, OperationType::DELETE_WINDOW); | |
777 delete window; | |
778 return true; | |
779 } | |
780 | |
781 void WindowTree::GetUnknownWindowsFrom( | |
782 const ServerWindow* window, | |
783 std::vector<const ServerWindow*>* windows) { | |
784 if (IsWindowKnown(window) || !access_policy_->CanGetWindowTree(window)) | |
785 return; | |
786 windows->push_back(window); | |
787 // There are two cases where this gets hit: | |
788 // . During init, in which case using the window id as the client id is | |
789 // fine. | |
790 // . When a window is moved to a parent of a window we know about. This is | |
791 // only encountered for the WM or embed roots. We assume such clients want | |
792 // to see the real id of the window and are only created ClientWindowIds | |
793 // with the client_id. | |
794 const ClientWindowId client_window_id(WindowIdToTransportId(window->id())); | |
795 DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id)); | |
796 client_id_to_window_id_map_[client_window_id] = window->id(); | |
797 window_id_to_client_id_map_[window->id()] = client_window_id; | |
798 if (!access_policy_->CanDescendIntoWindowForWindowTree(window)) | |
799 return; | |
800 std::vector<const ServerWindow*> children(window->GetChildren()); | |
801 for (size_t i = 0; i < children.size(); ++i) | |
802 GetUnknownWindowsFrom(children[i], windows); | |
803 } | |
804 | |
805 bool WindowTree::RemoveFromMaps(const ServerWindow* window) { | |
806 auto iter = window_id_to_client_id_map_.find(window->id()); | |
807 if (iter == window_id_to_client_id_map_.end()) | |
808 return false; | |
809 | |
810 client_id_to_window_id_map_.erase(iter->second); | |
811 window_id_to_client_id_map_.erase(iter); | |
812 return true; | |
813 } | |
814 | |
815 void WindowTree::RemoveFromKnown(const ServerWindow* window, | |
816 std::vector<ServerWindow*>* local_windows) { | |
817 if (window->id().client_id == id_) { | |
818 if (local_windows) | |
819 local_windows->push_back(GetWindow(window->id())); | |
820 return; | |
821 } | |
822 | |
823 RemoveFromMaps(window); | |
824 | |
825 std::vector<const ServerWindow*> children = window->GetChildren(); | |
826 for (size_t i = 0; i < children.size(); ++i) | |
827 RemoveFromKnown(children[i], local_windows); | |
828 } | |
829 | |
830 void WindowTree::RemoveRoot(const ServerWindow* window, | |
831 RemoveRootReason reason) { | |
832 DCHECK(roots_.count(window) > 0); | |
833 roots_.erase(window); | |
834 | |
835 const ClientWindowId client_window_id(ClientWindowIdForWindow(window)); | |
836 | |
837 // No need to do anything if we created the window. | |
838 if (window->id().client_id == id_) | |
839 return; | |
840 | |
841 if (reason == RemoveRootReason::EMBED) { | |
842 client()->OnUnembed(client_window_id.id); | |
843 client()->OnWindowDeleted(client_window_id.id); | |
844 window_server_->OnTreeMessagedClient(id_); | |
845 } | |
846 | |
847 // This client no longer knows about the window. Unparent any windows that | |
848 // were parented to windows in the root. | |
849 std::vector<ServerWindow*> local_windows; | |
850 RemoveFromKnown(window, &local_windows); | |
851 for (size_t i = 0; i < local_windows.size(); ++i) | |
852 local_windows[i]->parent()->Remove(local_windows[i]); | |
853 } | |
854 | |
855 Array<mojom::WindowDataPtr> WindowTree::WindowsToWindowDatas( | |
856 const std::vector<const ServerWindow*>& windows) { | |
857 Array<mojom::WindowDataPtr> array(windows.size()); | |
858 for (size_t i = 0; i < windows.size(); ++i) | |
859 array[i] = WindowToWindowData(windows[i]); | |
860 return array; | |
861 } | |
862 | |
863 mojom::WindowDataPtr WindowTree::WindowToWindowData( | |
864 const ServerWindow* window) { | |
865 DCHECK(IsWindowKnown(window)); | |
866 const ServerWindow* parent = window->parent(); | |
867 // If the parent isn't known, it means the parent is not visible to us (not | |
868 // in roots), and should not be sent over. | |
869 if (parent && !IsWindowKnown(parent)) | |
870 parent = nullptr; | |
871 mojom::WindowDataPtr window_data(mojom::WindowData::New()); | |
872 window_data->parent_id = | |
873 parent ? ClientWindowIdForWindow(parent).id : ClientWindowId().id; | |
874 window_data->window_id = | |
875 window ? ClientWindowIdForWindow(window).id : ClientWindowId().id; | |
876 window_data->bounds = window->bounds(); | |
877 window_data->properties = | |
878 mojo::Map<String, Array<uint8_t>>::From(window->properties()); | |
879 window_data->visible = window->visible(); | |
880 return window_data; | |
881 } | |
882 | |
883 void WindowTree::GetWindowTreeImpl( | |
884 const ServerWindow* window, | |
885 std::vector<const ServerWindow*>* windows) const { | |
886 DCHECK(window); | |
887 | |
888 if (!access_policy_->CanGetWindowTree(window)) | |
889 return; | |
890 | |
891 windows->push_back(window); | |
892 | |
893 if (!access_policy_->CanDescendIntoWindowForWindowTree(window)) | |
894 return; | |
895 | |
896 std::vector<const ServerWindow*> children(window->GetChildren()); | |
897 for (size_t i = 0; i < children.size(); ++i) | |
898 GetWindowTreeImpl(children[i], windows); | |
899 } | |
900 | |
901 void WindowTree::NotifyDrawnStateChanged(const ServerWindow* window, | |
902 bool new_drawn_value) { | |
903 // Even though we don't know about window, it may be an ancestor of our root, | |
904 // in which case the change may effect our roots drawn state. | |
905 if (roots_.empty()) | |
906 return; | |
907 | |
908 for (auto* root : roots_) { | |
909 if (window->Contains(root) && (new_drawn_value != root->IsDrawn())) { | |
910 client()->OnWindowParentDrawnStateChanged( | |
911 ClientWindowIdForWindow(root).id, new_drawn_value); | |
912 } | |
913 } | |
914 } | |
915 | |
916 void WindowTree::DestroyWindows() { | |
917 if (created_window_map_.empty()) | |
918 return; | |
919 | |
920 Operation op(this, window_server_, OperationType::DELETE_WINDOW); | |
921 // If we get here from the destructor we're not going to get | |
922 // ProcessWindowDeleted(). Copy the map and delete from the copy so that we | |
923 // don't have to worry about whether |created_window_map_| changes or not. | |
924 base::hash_map<WindowId, ServerWindow*> created_window_map_copy; | |
925 created_window_map_.swap(created_window_map_copy); | |
926 // A sibling can be a transient parent of another window so we detach windows | |
927 // from their transient parents to avoid double deletes. | |
928 for (auto& pair : created_window_map_copy) { | |
929 ServerWindow* transient_parent = pair.second->transient_parent(); | |
930 if (transient_parent) | |
931 transient_parent->RemoveTransientWindow(pair.second); | |
932 } | |
933 STLDeleteValues(&created_window_map_copy); | |
934 } | |
935 | |
936 bool WindowTree::CanEmbed(const ClientWindowId& window_id) const { | |
937 const ServerWindow* window = GetWindowByClientId(window_id); | |
938 return window && access_policy_->CanEmbed(window); | |
939 } | |
940 | |
941 void WindowTree::PrepareForEmbed(ServerWindow* window) { | |
942 DCHECK(window); | |
943 | |
944 // Only allow a node to be the root for one client. | |
945 WindowTree* existing_owner = window_server_->GetTreeWithRoot(window); | |
946 | |
947 Operation op(this, window_server_, OperationType::EMBED); | |
948 RemoveChildrenAsPartOfEmbed(window); | |
949 if (existing_owner) { | |
950 // Never message the originating client. | |
951 window_server_->OnTreeMessagedClient(id_); | |
952 existing_owner->RemoveRoot(window, RemoveRootReason::EMBED); | |
953 } | |
954 } | |
955 | |
956 void WindowTree::RemoveChildrenAsPartOfEmbed(ServerWindow* window) { | |
957 CHECK(window); | |
958 std::vector<ServerWindow*> children = window->GetChildren(); | |
959 for (size_t i = 0; i < children.size(); ++i) | |
960 window->Remove(children[i]); | |
961 } | |
962 | |
963 void WindowTree::DispatchInputEventImpl(ServerWindow* target, | |
964 const ui::Event& event) { | |
965 DCHECK(!event_ack_id_); | |
966 // We do not want to create a sequential id for each event, because that can | |
967 // leak some information to the client. So instead, manufacture the id | |
968 // randomly. | |
969 // TODO(moshayedi): Find a faster way to generate ids. | |
970 event_ack_id_ = 0x1000000 | (rand() & 0xffffff); | |
971 WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(target); | |
972 DCHECK(display_root); | |
973 event_source_wms_ = display_root->window_manager_state(); | |
974 // Should only get events from windows attached to a host. | |
975 DCHECK(event_source_wms_); | |
976 bool matched_observer = | |
977 event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event); | |
978 client()->OnWindowInputEvent( | |
979 event_ack_id_, ClientWindowIdForWindow(target).id, | |
980 ui::Event::Clone(event), matched_observer ? event_observer_id_ : 0); | |
981 } | |
982 | |
983 void WindowTree::SendToEventObserver(const ui::Event& event) { | |
984 if (event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event)) | |
985 client()->OnEventObserved(ui::Event::Clone(event), event_observer_id_); | |
986 } | |
987 | |
988 void WindowTree::NewWindow( | |
989 uint32_t change_id, | |
990 Id transport_window_id, | |
991 mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) { | |
992 std::map<std::string, std::vector<uint8_t>> properties; | |
993 if (!transport_properties.is_null()) { | |
994 properties = | |
995 transport_properties.To<std::map<std::string, std::vector<uint8_t>>>(); | |
996 } | |
997 client()->OnChangeCompleted( | |
998 change_id, NewWindow(ClientWindowId(transport_window_id), properties)); | |
999 } | |
1000 | |
1001 void WindowTree::NewTopLevelWindow( | |
1002 uint32_t change_id, | |
1003 Id transport_window_id, | |
1004 mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) { | |
1005 DCHECK(!waiting_for_top_level_window_info_); | |
1006 const ClientWindowId client_window_id(transport_window_id); | |
1007 // TODO(sky): need a way for client to provide context to figure out display. | |
1008 Display* display = display_manager()->displays().empty() | |
1009 ? nullptr | |
1010 : *(display_manager()->displays().begin()); | |
1011 // TODO(sky): move checks to accesspolicy. | |
1012 WindowManagerDisplayRoot* display_root = | |
1013 display && user_id_ != InvalidUserId() | |
1014 ? display->GetWindowManagerDisplayRootForUser(user_id_) | |
1015 : nullptr; | |
1016 if (!display_root || | |
1017 display_root->window_manager_state()->window_tree() == this || | |
1018 !IsValidIdForNewWindow(client_window_id)) { | |
1019 client()->OnChangeCompleted(change_id, false); | |
1020 return; | |
1021 } | |
1022 | |
1023 // The server creates the real window. Any further messages from the client | |
1024 // may try to alter the window. Pause incoming messages so that we know we | |
1025 // can't get a message for a window before the window is created. Once the | |
1026 // window is created we'll resume processing. | |
1027 binding_->SetIncomingMethodCallProcessingPaused(true); | |
1028 | |
1029 const uint32_t wm_change_id = | |
1030 window_server_->GenerateWindowManagerChangeId(this, change_id); | |
1031 | |
1032 waiting_for_top_level_window_info_.reset( | |
1033 new WaitingForTopLevelWindowInfo(client_window_id, wm_change_id)); | |
1034 | |
1035 display_root->window_manager_state() | |
1036 ->window_tree() | |
1037 ->window_manager_internal_->WmCreateTopLevelWindow( | |
1038 wm_change_id, id_, std::move(transport_properties)); | |
1039 } | |
1040 | |
1041 void WindowTree::DeleteWindow(uint32_t change_id, Id transport_window_id) { | |
1042 ServerWindow* window = | |
1043 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1044 bool success = false; | |
1045 bool should_close = window && (access_policy_->CanDeleteWindow(window) || | |
1046 ShouldRouteToWindowManager(window)); | |
1047 if (should_close) { | |
1048 WindowTree* tree = | |
1049 window_server_->GetTreeWithId(window->id().client_id); | |
1050 success = tree && tree->DeleteWindowImpl(this, window); | |
1051 } | |
1052 client()->OnChangeCompleted(change_id, success); | |
1053 } | |
1054 | |
1055 void WindowTree::AddWindow(uint32_t change_id, Id parent_id, Id child_id) { | |
1056 client()->OnChangeCompleted(change_id, AddWindow(ClientWindowId(parent_id), | |
1057 ClientWindowId(child_id))); | |
1058 } | |
1059 | |
1060 void WindowTree::RemoveWindowFromParent(uint32_t change_id, Id window_id) { | |
1061 bool success = false; | |
1062 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1063 if (window && window->parent() && | |
1064 access_policy_->CanRemoveWindowFromParent(window)) { | |
1065 success = true; | |
1066 Operation op(this, window_server_, | |
1067 OperationType::REMOVE_WINDOW_FROM_PARENT); | |
1068 window->parent()->Remove(window); | |
1069 } | |
1070 client()->OnChangeCompleted(change_id, success); | |
1071 } | |
1072 | |
1073 void WindowTree::AddTransientWindow(uint32_t change_id, | |
1074 Id window, | |
1075 Id transient_window) { | |
1076 client()->OnChangeCompleted( | |
1077 change_id, AddTransientWindow(ClientWindowId(window), | |
1078 ClientWindowId(transient_window))); | |
1079 } | |
1080 | |
1081 void WindowTree::RemoveTransientWindowFromParent(uint32_t change_id, | |
1082 Id transient_window_id) { | |
1083 bool success = false; | |
1084 ServerWindow* transient_window = | |
1085 GetWindowByClientId(ClientWindowId(transient_window_id)); | |
1086 if (transient_window && transient_window->transient_parent() && | |
1087 access_policy_->CanRemoveTransientWindowFromParent(transient_window)) { | |
1088 success = true; | |
1089 Operation op(this, window_server_, | |
1090 OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT); | |
1091 transient_window->transient_parent()->RemoveTransientWindow( | |
1092 transient_window); | |
1093 } | |
1094 client()->OnChangeCompleted(change_id, success); | |
1095 } | |
1096 | |
1097 void WindowTree::SetModal(uint32_t change_id, Id window_id) { | |
1098 client()->OnChangeCompleted(change_id, SetModal(ClientWindowId(window_id))); | |
1099 } | |
1100 | |
1101 void WindowTree::ReorderWindow(uint32_t change_id, | |
1102 Id window_id, | |
1103 Id relative_window_id, | |
1104 mojom::OrderDirection direction) { | |
1105 bool success = false; | |
1106 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1107 ServerWindow* relative_window = | |
1108 GetWindowByClientId(ClientWindowId(relative_window_id)); | |
1109 if (CanReorderWindow(window, relative_window, direction)) { | |
1110 success = true; | |
1111 Operation op(this, window_server_, OperationType::REORDER_WINDOW); | |
1112 window->Reorder(relative_window, direction); | |
1113 window_server_->ProcessWindowReorder(window, relative_window, direction); | |
1114 } | |
1115 client()->OnChangeCompleted(change_id, success); | |
1116 } | |
1117 | |
1118 void WindowTree::GetWindowTree( | |
1119 Id window_id, | |
1120 const base::Callback<void(Array<mojom::WindowDataPtr>)>& callback) { | |
1121 std::vector<const ServerWindow*> windows( | |
1122 GetWindowTree(ClientWindowId(window_id))); | |
1123 callback.Run(WindowsToWindowDatas(windows)); | |
1124 } | |
1125 | |
1126 void WindowTree::SetCapture(uint32_t change_id, Id window_id) { | |
1127 client()->OnChangeCompleted(change_id, SetCapture(ClientWindowId(window_id))); | |
1128 } | |
1129 | |
1130 void WindowTree::ReleaseCapture(uint32_t change_id, Id window_id) { | |
1131 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1132 WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window); | |
1133 ServerWindow* current_capture_window = | |
1134 display_root ? display_root->window_manager_state()->capture_window() | |
1135 : nullptr; | |
1136 bool success = window && display_root && | |
1137 display_root->window_manager_state()->IsActive() && | |
1138 (!current_capture_window || | |
1139 access_policy_->CanSetCapture(current_capture_window)) && | |
1140 window == current_capture_window; | |
1141 if (success) { | |
1142 Operation op(this, window_server_, OperationType::RELEASE_CAPTURE); | |
1143 success = display_root->window_manager_state()->SetCapture( | |
1144 nullptr, kInvalidClientId); | |
1145 } | |
1146 client()->OnChangeCompleted(change_id, success); | |
1147 } | |
1148 | |
1149 void WindowTree::SetEventObserver(mojom::EventMatcherPtr matcher, | |
1150 uint32_t observer_id) { | |
1151 if (matcher.is_null() || observer_id == 0) { | |
1152 // Clear any existing event observer. | |
1153 event_observer_matcher_.reset(); | |
1154 event_observer_id_ = 0; | |
1155 return; | |
1156 } | |
1157 | |
1158 // Do not allow key events to be observed, as a compromised app could register | |
1159 // itself as an event observer and spy on keystrokes to another app. | |
1160 if (!matcher->type_matcher) { | |
1161 DVLOG(1) << "SetEventObserver must specify an event type."; | |
1162 return; | |
1163 } | |
1164 const ui::mojom::EventType event_type_whitelist[] = { | |
1165 ui::mojom::EventType::POINTER_CANCEL, ui::mojom::EventType::POINTER_DOWN, | |
1166 ui::mojom::EventType::POINTER_MOVE, ui::mojom::EventType::POINTER_UP, | |
1167 ui::mojom::EventType::MOUSE_EXIT, ui::mojom::EventType::WHEEL, | |
1168 }; | |
1169 bool allowed = false; | |
1170 for (ui::mojom::EventType event_type : event_type_whitelist) { | |
1171 if (matcher->type_matcher->type == event_type) { | |
1172 allowed = true; | |
1173 break; | |
1174 } | |
1175 } | |
1176 if (!allowed) { | |
1177 DVLOG(1) << "SetEventObserver event type not allowed"; | |
1178 return; | |
1179 } | |
1180 | |
1181 event_observer_matcher_.reset(new EventMatcher(*matcher)); | |
1182 event_observer_id_ = observer_id; | |
1183 } | |
1184 | |
1185 void WindowTree::SetWindowBounds(uint32_t change_id, | |
1186 Id window_id, | |
1187 const gfx::Rect& bounds) { | |
1188 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1189 if (window && ShouldRouteToWindowManager(window)) { | |
1190 const uint32_t wm_change_id = | |
1191 window_server_->GenerateWindowManagerChangeId(this, change_id); | |
1192 // |window_id| may be a client id, use the id from the window to ensure | |
1193 // the windowmanager doesn't get an id it doesn't know about. | |
1194 WindowManagerDisplayRoot* display_root = | |
1195 GetWindowManagerDisplayRoot(window); | |
1196 WindowTree* wm_tree = display_root->window_manager_state()->window_tree(); | |
1197 wm_tree->window_manager_internal_->WmSetBounds( | |
1198 wm_change_id, wm_tree->ClientWindowIdForWindow(window).id, | |
1199 std::move(bounds)); | |
1200 return; | |
1201 } | |
1202 | |
1203 // Only the owner of the window can change the bounds. | |
1204 bool success = window && access_policy_->CanSetWindowBounds(window); | |
1205 if (success) { | |
1206 Operation op(this, window_server_, OperationType::SET_WINDOW_BOUNDS); | |
1207 window->SetBounds(bounds); | |
1208 } | |
1209 client()->OnChangeCompleted(change_id, success); | |
1210 } | |
1211 | |
1212 void WindowTree::SetWindowVisibility(uint32_t change_id, | |
1213 Id transport_window_id, | |
1214 bool visible) { | |
1215 client()->OnChangeCompleted( | |
1216 change_id, | |
1217 SetWindowVisibility(ClientWindowId(transport_window_id), visible)); | |
1218 } | |
1219 | |
1220 void WindowTree::SetWindowProperty(uint32_t change_id, | |
1221 Id transport_window_id, | |
1222 const mojo::String& name, | |
1223 mojo::Array<uint8_t> value) { | |
1224 ServerWindow* window = | |
1225 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1226 if (window && ShouldRouteToWindowManager(window)) { | |
1227 const uint32_t wm_change_id = | |
1228 window_server_->GenerateWindowManagerChangeId(this, change_id); | |
1229 WindowManagerDisplayRoot* display_root = | |
1230 GetWindowManagerDisplayRoot(window); | |
1231 WindowTree* wm_tree = display_root->window_manager_state()->window_tree(); | |
1232 wm_tree->window_manager_internal_->WmSetProperty( | |
1233 wm_change_id, wm_tree->ClientWindowIdForWindow(window).id, name, | |
1234 std::move(value)); | |
1235 return; | |
1236 } | |
1237 const bool success = window && access_policy_->CanSetWindowProperties(window); | |
1238 if (success) { | |
1239 Operation op(this, window_server_, OperationType::SET_WINDOW_PROPERTY); | |
1240 if (value.is_null()) { | |
1241 window->SetProperty(name, nullptr); | |
1242 } else { | |
1243 std::vector<uint8_t> data = value.To<std::vector<uint8_t>>(); | |
1244 window->SetProperty(name, &data); | |
1245 } | |
1246 } | |
1247 client()->OnChangeCompleted(change_id, success); | |
1248 } | |
1249 | |
1250 void WindowTree::SetWindowOpacity(uint32_t change_id, | |
1251 Id window_id, | |
1252 float opacity) { | |
1253 client()->OnChangeCompleted( | |
1254 change_id, SetWindowOpacity(ClientWindowId(window_id), opacity)); | |
1255 } | |
1256 | |
1257 void WindowTree::AttachSurface(Id transport_window_id, | |
1258 mojom::SurfaceType type, | |
1259 mojo::InterfaceRequest<mojom::Surface> surface, | |
1260 mojom::SurfaceClientPtr client) { | |
1261 ServerWindow* window = | |
1262 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1263 const bool success = | |
1264 window && access_policy_->CanSetWindowSurface(window, type); | |
1265 if (!success) | |
1266 return; | |
1267 window->CreateSurface(type, std::move(surface), std::move(client)); | |
1268 } | |
1269 | |
1270 void WindowTree::SetWindowTextInputState(Id transport_window_id, | |
1271 mojo::TextInputStatePtr state) { | |
1272 ServerWindow* window = | |
1273 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1274 bool success = window && access_policy_->CanSetWindowTextInputState(window); | |
1275 if (success) | |
1276 window->SetTextInputState(state.To<ui::TextInputState>()); | |
1277 } | |
1278 | |
1279 void WindowTree::SetImeVisibility(Id transport_window_id, | |
1280 bool visible, | |
1281 mojo::TextInputStatePtr state) { | |
1282 ServerWindow* window = | |
1283 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1284 bool success = window && access_policy_->CanSetWindowTextInputState(window); | |
1285 if (success) { | |
1286 if (!state.is_null()) | |
1287 window->SetTextInputState(state.To<ui::TextInputState>()); | |
1288 | |
1289 Display* display = GetDisplay(window); | |
1290 if (display) | |
1291 display->SetImeVisibility(window, visible); | |
1292 } | |
1293 } | |
1294 | |
1295 void WindowTree::OnWindowInputEventAck(uint32_t event_id, | |
1296 mojom::EventResult result) { | |
1297 if (event_ack_id_ == 0 || event_id != event_ack_id_) { | |
1298 // TODO(sad): Something bad happened. Kill the client? | |
1299 NOTIMPLEMENTED() << "Wrong event acked."; | |
1300 } | |
1301 event_ack_id_ = 0; | |
1302 | |
1303 if (janky_) | |
1304 event_source_wms_->window_tree()->ClientJankinessChanged(this); | |
1305 | |
1306 WindowManagerState* event_source_wms = event_source_wms_; | |
1307 event_source_wms_ = nullptr; | |
1308 if (event_source_wms) | |
1309 event_source_wms->OnEventAck(this, result); | |
1310 | |
1311 if (!event_queue_.empty()) { | |
1312 DCHECK(!event_ack_id_); | |
1313 ServerWindow* target = nullptr; | |
1314 std::unique_ptr<ui::Event> event; | |
1315 do { | |
1316 std::unique_ptr<TargetedEvent> targeted_event = | |
1317 std::move(event_queue_.front()); | |
1318 event_queue_.pop(); | |
1319 target = targeted_event->target(); | |
1320 event = targeted_event->TakeEvent(); | |
1321 } while (!event_queue_.empty() && !GetDisplay(target)); | |
1322 if (target) | |
1323 DispatchInputEventImpl(target, *event); | |
1324 } | |
1325 } | |
1326 | |
1327 void WindowTree::SetClientArea( | |
1328 Id transport_window_id, | |
1329 const gfx::Insets& insets, | |
1330 mojo::Array<gfx::Rect> transport_additional_client_areas) { | |
1331 ServerWindow* window = | |
1332 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1333 if (!window || !access_policy_->CanSetClientArea(window)) | |
1334 return; | |
1335 | |
1336 std::vector<gfx::Rect> additional_client_areas = | |
1337 transport_additional_client_areas.To<std::vector<gfx::Rect>>(); | |
1338 window->SetClientArea(insets, additional_client_areas); | |
1339 } | |
1340 | |
1341 void WindowTree::SetHitTestMask(Id transport_window_id, const gfx::Rect& mask) { | |
1342 ServerWindow* window = | |
1343 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1344 if (!window || !access_policy_->CanSetHitTestMask(window)) { | |
1345 DVLOG(1) << "SetHitTestMask failed"; | |
1346 return; | |
1347 } | |
1348 | |
1349 if (!mask.IsEmpty()) | |
1350 window->SetHitTestMask(mask); | |
1351 else | |
1352 window->ClearHitTestMask(); | |
1353 } | |
1354 | |
1355 void WindowTree::Embed(Id transport_window_id, | |
1356 mojom::WindowTreeClientPtr client, | |
1357 uint32_t flags, | |
1358 const EmbedCallback& callback) { | |
1359 callback.Run( | |
1360 Embed(ClientWindowId(transport_window_id), std::move(client), flags)); | |
1361 } | |
1362 | |
1363 void WindowTree::SetFocus(uint32_t change_id, Id transport_window_id) { | |
1364 client()->OnChangeCompleted(change_id, | |
1365 SetFocus(ClientWindowId(transport_window_id))); | |
1366 } | |
1367 | |
1368 void WindowTree::SetCanFocus(Id transport_window_id, bool can_focus) { | |
1369 ServerWindow* window = | |
1370 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1371 // TODO(sky): there should be an else case (it shouldn't route to wm and | |
1372 // policy allows, then set_can_focus). | |
1373 if (window && ShouldRouteToWindowManager(window)) | |
1374 window->set_can_focus(can_focus); | |
1375 } | |
1376 | |
1377 void WindowTree::SetPredefinedCursor(uint32_t change_id, | |
1378 Id transport_window_id, | |
1379 mus::mojom::Cursor cursor_id) { | |
1380 ServerWindow* window = | |
1381 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1382 | |
1383 // Only the owner of the window can change the bounds. | |
1384 bool success = window && access_policy_->CanSetCursorProperties(window); | |
1385 if (success) { | |
1386 Operation op(this, window_server_, | |
1387 OperationType::SET_WINDOW_PREDEFINED_CURSOR); | |
1388 window->SetPredefinedCursor(cursor_id); | |
1389 } | |
1390 client()->OnChangeCompleted(change_id, success); | |
1391 } | |
1392 | |
1393 void WindowTree::GetWindowManagerClient( | |
1394 mojo::AssociatedInterfaceRequest<mojom::WindowManagerClient> internal) { | |
1395 if (!access_policy_->CanSetWindowManager() || !window_manager_internal_ || | |
1396 window_manager_internal_client_binding_) { | |
1397 return; | |
1398 } | |
1399 window_manager_internal_client_binding_.reset( | |
1400 new mojo::AssociatedBinding<mojom::WindowManagerClient>( | |
1401 this, std::move(internal))); | |
1402 } | |
1403 | |
1404 void WindowTree::GetCursorLocationMemory( | |
1405 const GetCursorLocationMemoryCallback& callback) { | |
1406 callback.Run( | |
1407 window_server_->display_manager()->GetUserDisplayManager(user_id_)-> | |
1408 GetCursorLocationMemory()); | |
1409 } | |
1410 | |
1411 void WindowTree::AddAccelerator(uint32_t id, | |
1412 mojom::EventMatcherPtr event_matcher, | |
1413 const AddAcceleratorCallback& callback) { | |
1414 DCHECK(window_manager_state_); | |
1415 const bool success = | |
1416 window_manager_state_->event_dispatcher()->AddAccelerator( | |
1417 id, std::move(event_matcher)); | |
1418 callback.Run(success); | |
1419 } | |
1420 | |
1421 void WindowTree::RemoveAccelerator(uint32_t id) { | |
1422 window_manager_state_->event_dispatcher()->RemoveAccelerator(id); | |
1423 } | |
1424 | |
1425 void WindowTree::AddActivationParent(Id transport_window_id) { | |
1426 AddActivationParent(ClientWindowId(transport_window_id)); | |
1427 } | |
1428 | |
1429 void WindowTree::RemoveActivationParent(Id transport_window_id) { | |
1430 ServerWindow* window = | |
1431 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1432 if (window) { | |
1433 Display* display = GetDisplay(window); | |
1434 if (display) | |
1435 display->RemoveActivationParent(window); | |
1436 else | |
1437 DVLOG(1) << "RemoveActivationParent window not associated with display"; | |
1438 } else { | |
1439 DVLOG(1) << "RemoveActivationParent supplied invalid window id"; | |
1440 } | |
1441 } | |
1442 | |
1443 void WindowTree::ActivateNextWindow() { | |
1444 DCHECK(window_manager_state_); | |
1445 if (window_server_->user_id_tracker()->active_id() != user_id_) | |
1446 return; | |
1447 | |
1448 ServerWindow* focused_window = window_server_->GetFocusedWindow(); | |
1449 if (focused_window) { | |
1450 WindowManagerDisplayRoot* display_root = | |
1451 GetWindowManagerDisplayRoot(focused_window); | |
1452 if (display_root->window_manager_state() != window_manager_state_.get()) { | |
1453 // We aren't active. | |
1454 return; | |
1455 } | |
1456 display_root->display()->ActivateNextWindow(); | |
1457 return; | |
1458 } | |
1459 // Use the first display. | |
1460 std::set<Display*> displays = window_server_->display_manager()->displays(); | |
1461 if (displays.empty()) | |
1462 return; | |
1463 | |
1464 (*displays.begin())->ActivateNextWindow(); | |
1465 } | |
1466 | |
1467 void WindowTree::SetUnderlaySurfaceOffsetAndExtendedHitArea( | |
1468 Id window_id, | |
1469 int32_t x_offset, | |
1470 int32_t y_offset, | |
1471 const gfx::Insets& hit_area) { | |
1472 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1473 if (!window) | |
1474 return; | |
1475 | |
1476 window->SetUnderlayOffset(gfx::Vector2d(x_offset, y_offset)); | |
1477 window->set_extended_hit_test_region(hit_area); | |
1478 } | |
1479 | |
1480 void WindowTree::WmResponse(uint32_t change_id, bool response) { | |
1481 window_server_->WindowManagerChangeCompleted(change_id, response); | |
1482 } | |
1483 | |
1484 void WindowTree::WmRequestClose(Id transport_window_id) { | |
1485 ServerWindow* window = | |
1486 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1487 WindowTree* tree = window_server_->GetTreeWithRoot(window); | |
1488 if (tree && tree != this) { | |
1489 tree->client()->RequestClose(tree->ClientWindowIdForWindow(window).id); | |
1490 } | |
1491 // TODO(sky): think about what else case means. | |
1492 } | |
1493 | |
1494 void WindowTree::WmSetFrameDecorationValues( | |
1495 mojom::FrameDecorationValuesPtr values) { | |
1496 DCHECK(window_manager_state_); | |
1497 window_manager_state_->SetFrameDecorationValues(std::move(values)); | |
1498 } | |
1499 | |
1500 void WindowTree::WmSetNonClientCursor(uint32_t window_id, | |
1501 mojom::Cursor cursor_id) { | |
1502 DCHECK(window_manager_state_); | |
1503 ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); | |
1504 if (window) { | |
1505 window->SetNonClientCursor(cursor_id); | |
1506 } else { | |
1507 DVLOG(1) << "trying to update non-client cursor of invalid window"; | |
1508 } | |
1509 } | |
1510 | |
1511 void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id, | |
1512 Id transport_window_id) { | |
1513 ServerWindow* window = | |
1514 GetWindowByClientId(ClientWindowId(transport_window_id)); | |
1515 if (window && window->id().client_id != id_) { | |
1516 DVLOG(1) << "OnWmCreatedTopLevelWindow supplied invalid window id"; | |
1517 window_server_->WindowManagerSentBogusMessage(); | |
1518 window = nullptr; | |
1519 } | |
1520 window_server_->WindowManagerCreatedTopLevelWindow(this, change_id, window); | |
1521 } | |
1522 | |
1523 bool WindowTree::HasRootForAccessPolicy(const ServerWindow* window) const { | |
1524 return HasRoot(window); | |
1525 } | |
1526 | |
1527 bool WindowTree::IsWindowKnownForAccessPolicy( | |
1528 const ServerWindow* window) const { | |
1529 return IsWindowKnown(window); | |
1530 } | |
1531 | |
1532 bool WindowTree::IsWindowRootOfAnotherTreeForAccessPolicy( | |
1533 const ServerWindow* window) const { | |
1534 WindowTree* tree = window_server_->GetTreeWithRoot(window); | |
1535 return tree && tree != this; | |
1536 } | |
1537 | |
1538 } // namespace ws | |
1539 } // namespace mus | |
OLD | NEW |