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 "services/ui/public/cpp/window.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <set> | |
11 #include <string> | |
12 | |
13 #include "base/bind.h" | |
14 #include "base/macros.h" | |
15 #include "services/ui/common/transient_window_utils.h" | |
16 #include "services/ui/public/cpp/property_type_converters.h" | |
17 #include "services/ui/public/cpp/window_compositor_frame_sink.h" | |
18 #include "services/ui/public/cpp/window_observer.h" | |
19 #include "services/ui/public/cpp/window_private.h" | |
20 #include "services/ui/public/cpp/window_property.h" | |
21 #include "services/ui/public/cpp/window_tracker.h" | |
22 #include "services/ui/public/cpp/window_tree_client.h" | |
23 #include "services/ui/public/interfaces/window_manager.mojom.h" | |
24 #include "ui/display/display.h" | |
25 #include "ui/display/types/display_constants.h" | |
26 #include "ui/gfx/geometry/rect.h" | |
27 #include "ui/gfx/geometry/size.h" | |
28 | |
29 namespace ui { | |
30 | |
31 namespace { | |
32 | |
33 void NotifyWindowTreeChangeAtReceiver( | |
34 Window* receiver, | |
35 const WindowObserver::TreeChangeParams& params, | |
36 bool change_applied) { | |
37 WindowObserver::TreeChangeParams local_params = params; | |
38 local_params.receiver = receiver; | |
39 if (change_applied) { | |
40 for (auto& observer : *WindowPrivate(receiver).observers()) | |
41 observer.OnTreeChanged(local_params); | |
42 } else { | |
43 for (auto& observer : *WindowPrivate(receiver).observers()) | |
44 observer.OnTreeChanging(local_params); | |
45 } | |
46 } | |
47 | |
48 void NotifyWindowTreeChangeUp(Window* start_at, | |
49 const WindowObserver::TreeChangeParams& params, | |
50 bool change_applied) { | |
51 for (Window* current = start_at; current; current = current->parent()) | |
52 NotifyWindowTreeChangeAtReceiver(current, params, change_applied); | |
53 } | |
54 | |
55 void NotifyWindowTreeChangeDown(Window* start_at, | |
56 const WindowObserver::TreeChangeParams& params, | |
57 bool change_applied) { | |
58 NotifyWindowTreeChangeAtReceiver(start_at, params, change_applied); | |
59 Window::Children::const_iterator it = start_at->children().begin(); | |
60 for (; it != start_at->children().end(); ++it) | |
61 NotifyWindowTreeChangeDown(*it, params, change_applied); | |
62 } | |
63 | |
64 void NotifyWindowTreeChange(const WindowObserver::TreeChangeParams& params, | |
65 bool change_applied) { | |
66 NotifyWindowTreeChangeDown(params.target, params, change_applied); | |
67 if (params.old_parent) | |
68 NotifyWindowTreeChangeUp(params.old_parent, params, change_applied); | |
69 if (params.new_parent) | |
70 NotifyWindowTreeChangeUp(params.new_parent, params, change_applied); | |
71 } | |
72 | |
73 class ScopedTreeNotifier { | |
74 public: | |
75 ScopedTreeNotifier(Window* target, Window* old_parent, Window* new_parent) { | |
76 params_.target = target; | |
77 params_.old_parent = old_parent; | |
78 params_.new_parent = new_parent; | |
79 NotifyWindowTreeChange(params_, false); | |
80 } | |
81 ~ScopedTreeNotifier() { NotifyWindowTreeChange(params_, true); } | |
82 | |
83 private: | |
84 WindowObserver::TreeChangeParams params_; | |
85 | |
86 DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); | |
87 }; | |
88 | |
89 void RemoveChildImpl(Window* child, Window::Children* children) { | |
90 Window::Children::iterator it = | |
91 std::find(children->begin(), children->end(), child); | |
92 if (it != children->end()) { | |
93 children->erase(it); | |
94 WindowPrivate(child).ClearParent(); | |
95 } | |
96 } | |
97 | |
98 class OrderChangedNotifier { | |
99 public: | |
100 OrderChangedNotifier(Window* window, | |
101 Window* relative_window, | |
102 mojom::OrderDirection direction) | |
103 : window_(window), | |
104 relative_window_(relative_window), | |
105 direction_(direction) {} | |
106 | |
107 ~OrderChangedNotifier() {} | |
108 | |
109 void NotifyWindowReordering() { | |
110 for (auto& observer : *WindowPrivate(window_).observers()) | |
111 observer.OnWindowReordering(window_, relative_window_, direction_); | |
112 } | |
113 | |
114 void NotifyWindowReordered() { | |
115 for (auto& observer : *WindowPrivate(window_).observers()) | |
116 observer.OnWindowReordered(window_, relative_window_, direction_); | |
117 } | |
118 | |
119 private: | |
120 Window* window_; | |
121 Window* relative_window_; | |
122 mojom::OrderDirection direction_; | |
123 | |
124 DISALLOW_COPY_AND_ASSIGN(OrderChangedNotifier); | |
125 }; | |
126 | |
127 class ScopedSetBoundsNotifier { | |
128 public: | |
129 ScopedSetBoundsNotifier(Window* window, | |
130 const gfx::Rect& old_bounds, | |
131 const gfx::Rect& new_bounds) | |
132 : window_(window), old_bounds_(old_bounds), new_bounds_(new_bounds) { | |
133 for (auto& observer : *WindowPrivate(window_).observers()) | |
134 observer.OnWindowBoundsChanging(window_, old_bounds_, new_bounds_); | |
135 } | |
136 ~ScopedSetBoundsNotifier() { | |
137 for (auto& observer : *WindowPrivate(window_).observers()) | |
138 observer.OnWindowBoundsChanged(window_, old_bounds_, new_bounds_); | |
139 } | |
140 | |
141 private: | |
142 Window* window_; | |
143 const gfx::Rect old_bounds_; | |
144 const gfx::Rect new_bounds_; | |
145 | |
146 DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); | |
147 }; | |
148 | |
149 bool IsClientRoot(Window* window) { | |
150 return window->window_tree() && | |
151 window->window_tree()->GetRoots().count(window) > 0; | |
152 } | |
153 | |
154 bool WasCreatedByThisClientOrIsRoot(Window* window) { | |
155 return window->WasCreatedByThisClient() || IsClientRoot(window); | |
156 } | |
157 | |
158 void EmptyEmbedCallback(bool result) {} | |
159 | |
160 } // namespace | |
161 | |
162 //////////////////////////////////////////////////////////////////////////////// | |
163 // Window, public: | |
164 | |
165 void Window::Destroy() { | |
166 if (!WasCreatedByThisClientOrIsRoot(this)) | |
167 return; | |
168 | |
169 if (client_) | |
170 client_->DestroyWindow(this); | |
171 while (!children_.empty()) { | |
172 Window* child = children_.front(); | |
173 if (!child->WasCreatedByThisClient()) { | |
174 WindowPrivate(child).ClearParent(); | |
175 children_.erase(children_.begin()); | |
176 } else { | |
177 child->Destroy(); | |
178 DCHECK(std::find(children_.begin(), children_.end(), child) == | |
179 children_.end()); | |
180 } | |
181 } | |
182 LocalDestroy(); | |
183 } | |
184 | |
185 bool Window::WasCreatedByThisClient() const { | |
186 return !client_ || client_->WasCreatedByThisClient(this); | |
187 } | |
188 | |
189 void Window::SetBounds(const gfx::Rect& bounds) { | |
190 if (!WasCreatedByThisClientOrIsRoot(this)) | |
191 return; | |
192 if (bounds_ == bounds) | |
193 return; | |
194 if (client_) | |
195 client_->SetBounds(this, bounds_, bounds); | |
196 LocalSetBounds(bounds_, bounds); | |
197 } | |
198 | |
199 gfx::Rect Window::GetBoundsInRoot() const { | |
200 gfx::Vector2d offset; | |
201 for (const Window* w = parent(); w != nullptr; w = w->parent()) | |
202 offset += w->bounds().OffsetFromOrigin(); | |
203 return bounds() + offset; | |
204 } | |
205 | |
206 void Window::SetClientArea( | |
207 const gfx::Insets& client_area, | |
208 const std::vector<gfx::Rect>& additional_client_areas) { | |
209 if (!WasCreatedByThisClientOrIsRoot(this)) | |
210 return; | |
211 | |
212 if (client_) | |
213 client_->SetClientArea(server_id_, client_area, | |
214 additional_client_areas); | |
215 LocalSetClientArea(client_area, additional_client_areas); | |
216 } | |
217 | |
218 void Window::SetHitTestMask(const gfx::Rect& mask) { | |
219 if (!WasCreatedByThisClientOrIsRoot(this)) | |
220 return; | |
221 | |
222 if (hit_test_mask_ && *hit_test_mask_ == mask) | |
223 return; | |
224 | |
225 if (client_) | |
226 client_->SetHitTestMask(server_id_, mask); | |
227 hit_test_mask_.reset(new gfx::Rect(mask)); | |
228 } | |
229 | |
230 void Window::ClearHitTestMask() { | |
231 if (!WasCreatedByThisClientOrIsRoot(this)) | |
232 return; | |
233 | |
234 if (!hit_test_mask_) | |
235 return; | |
236 | |
237 if (client_) | |
238 client_->ClearHitTestMask(server_id_); | |
239 hit_test_mask_.reset(); | |
240 } | |
241 | |
242 void Window::SetVisible(bool value) { | |
243 if (visible_ == value) | |
244 return; | |
245 | |
246 if (client_) | |
247 client_->SetVisible(this, value); | |
248 LocalSetVisible(value); | |
249 } | |
250 | |
251 void Window::SetOpacity(float opacity) { | |
252 if (client_) | |
253 client_->SetOpacity(this, opacity); | |
254 LocalSetOpacity(opacity); | |
255 } | |
256 | |
257 void Window::SetPredefinedCursor(ui::mojom::Cursor cursor_id) { | |
258 if (cursor_id_ == cursor_id) | |
259 return; | |
260 | |
261 if (client_) | |
262 client_->SetPredefinedCursor(server_id_, cursor_id); | |
263 LocalSetPredefinedCursor(cursor_id); | |
264 } | |
265 | |
266 bool Window::IsDrawn() const { | |
267 if (!visible_) | |
268 return false; | |
269 return parent_ ? parent_->IsDrawn() : parent_drawn_; | |
270 } | |
271 | |
272 std::unique_ptr<WindowCompositorFrameSink> Window::RequestCompositorFrameSink( | |
273 scoped_refptr<cc::ContextProvider> context_provider, | |
274 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) { | |
275 std::unique_ptr<WindowCompositorFrameSinkBinding> | |
276 compositor_frame_sink_binding; | |
277 std::unique_ptr<WindowCompositorFrameSink> compositor_frame_sink = | |
278 WindowCompositorFrameSink::Create( | |
279 cc::FrameSinkId(server_id(), 0), std::move(context_provider), | |
280 gpu_memory_buffer_manager, &compositor_frame_sink_binding); | |
281 AttachCompositorFrameSink(std::move(compositor_frame_sink_binding)); | |
282 return compositor_frame_sink; | |
283 } | |
284 | |
285 void Window::AttachCompositorFrameSink( | |
286 std::unique_ptr<WindowCompositorFrameSinkBinding> | |
287 compositor_frame_sink_binding) { | |
288 window_tree()->AttachCompositorFrameSink( | |
289 server_id_, | |
290 std::move(compositor_frame_sink_binding->compositor_frame_sink_request_), | |
291 mojo::MakeProxy(std::move( | |
292 compositor_frame_sink_binding->compositor_frame_sink_client_))); | |
293 } | |
294 | |
295 void Window::ClearSharedProperty(const std::string& name) { | |
296 SetSharedPropertyInternal(name, nullptr); | |
297 } | |
298 | |
299 bool Window::HasSharedProperty(const std::string& name) const { | |
300 return properties_.count(name) > 0; | |
301 } | |
302 | |
303 void Window::AddObserver(WindowObserver* observer) { | |
304 observers_.AddObserver(observer); | |
305 } | |
306 | |
307 void Window::RemoveObserver(WindowObserver* observer) { | |
308 observers_.RemoveObserver(observer); | |
309 } | |
310 | |
311 const Window* Window::GetRoot() const { | |
312 const Window* root = this; | |
313 for (const Window* parent = this; parent; parent = parent->parent()) | |
314 root = parent; | |
315 return root; | |
316 } | |
317 | |
318 void Window::AddChild(Window* child) { | |
319 // TODO(beng): not necessarily valid to all clients, but possibly to the | |
320 // embeddee in an embedder-embeddee relationship. | |
321 if (client_) | |
322 CHECK_EQ(child->client_, client_); | |
323 // Roots can not be added as children of other windows. | |
324 if (window_tree() && window_tree()->IsRoot(child)) | |
325 return; | |
326 LocalAddChild(child); | |
327 if (client_) | |
328 client_->AddChild(this, child->server_id()); | |
329 } | |
330 | |
331 void Window::RemoveChild(Window* child) { | |
332 // TODO(beng): not necessarily valid to all clients, but possibly to the | |
333 // embeddee in an embedder-embeddee relationship. | |
334 if (client_) | |
335 CHECK_EQ(child->client_, client_); | |
336 LocalRemoveChild(child); | |
337 if (client_) | |
338 client_->RemoveChild(this, child->server_id()); | |
339 } | |
340 | |
341 void Window::Reorder(Window* relative, mojom::OrderDirection direction) { | |
342 if (!LocalReorder(relative, direction)) | |
343 return; | |
344 if (client_) | |
345 client_->Reorder(this, relative->server_id(), direction); | |
346 } | |
347 | |
348 void Window::MoveToFront() { | |
349 if (!parent_ || parent_->children_.back() == this) | |
350 return; | |
351 Reorder(parent_->children_.back(), mojom::OrderDirection::ABOVE); | |
352 } | |
353 | |
354 void Window::MoveToBack() { | |
355 if (!parent_ || parent_->children_.front() == this) | |
356 return; | |
357 Reorder(parent_->children_.front(), mojom::OrderDirection::BELOW); | |
358 } | |
359 | |
360 bool Window::Contains(const Window* child) const { | |
361 if (!child) | |
362 return false; | |
363 if (child == this) | |
364 return true; | |
365 if (client_) | |
366 CHECK_EQ(child->client_, client_); | |
367 for (const Window* p = child->parent(); p; p = p->parent()) { | |
368 if (p == this) | |
369 return true; | |
370 } | |
371 return false; | |
372 } | |
373 | |
374 void Window::AddTransientWindow(Window* transient_window) { | |
375 // A system modal window cannot become a transient child. | |
376 DCHECK(!transient_window->is_modal() || transient_window->transient_parent()); | |
377 | |
378 if (client_) | |
379 CHECK_EQ(transient_window->client_, client_); | |
380 LocalAddTransientWindow(transient_window); | |
381 if (client_) | |
382 client_->AddTransientWindow(this, transient_window->server_id()); | |
383 } | |
384 | |
385 void Window::RemoveTransientWindow(Window* transient_window) { | |
386 if (client_) | |
387 CHECK_EQ(transient_window->window_tree(), client_); | |
388 LocalRemoveTransientWindow(transient_window); | |
389 if (client_) | |
390 client_->RemoveTransientWindowFromParent(transient_window); | |
391 } | |
392 | |
393 void Window::SetModal() { | |
394 if (is_modal_) | |
395 return; | |
396 | |
397 LocalSetModal(); | |
398 if (client_) | |
399 client_->SetModal(this); | |
400 } | |
401 | |
402 Window* Window::GetChildByLocalId(int id) { | |
403 if (id == local_id_) | |
404 return this; | |
405 // TODO(beng): this could be improved depending on how we decide to own | |
406 // windows. | |
407 for (Window* child : children_) { | |
408 Window* matching_child = child->GetChildByLocalId(id); | |
409 if (matching_child) | |
410 return matching_child; | |
411 } | |
412 return nullptr; | |
413 } | |
414 | |
415 void Window::SetTextInputState(mojo::TextInputStatePtr state) { | |
416 if (client_) | |
417 client_->SetWindowTextInputState(server_id_, std::move(state)); | |
418 } | |
419 | |
420 void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) { | |
421 // SetImeVisibility() shouldn't be used if the window is not editable. | |
422 DCHECK(state.is_null() || state->type != mojo::TextInputType::NONE); | |
423 if (client_) | |
424 client_->SetImeVisibility(server_id_, visible, std::move(state)); | |
425 } | |
426 | |
427 bool Window::HasCapture() const { | |
428 return client_ && client_->GetCaptureWindow() == this; | |
429 } | |
430 | |
431 void Window::SetCapture() { | |
432 if (client_) | |
433 client_->SetCapture(this); | |
434 } | |
435 | |
436 void Window::ReleaseCapture() { | |
437 if (client_) | |
438 client_->ReleaseCapture(this); | |
439 } | |
440 | |
441 void Window::SetFocus() { | |
442 if (client_ && IsDrawn()) | |
443 client_->SetFocus(this); | |
444 } | |
445 | |
446 bool Window::HasFocus() const { | |
447 return client_ && client_->GetFocusedWindow() == this; | |
448 } | |
449 | |
450 void Window::SetCanFocus(bool can_focus) { | |
451 if (client_) | |
452 client_->SetCanFocus(server_id_, can_focus); | |
453 } | |
454 | |
455 void Window::SetCanAcceptDrops(WindowDropTarget* drop_target) { | |
456 if (drop_target_ == drop_target) | |
457 return; | |
458 drop_target_ = drop_target; | |
459 if (client_) | |
460 client_->SetCanAcceptDrops(server_id_, !!drop_target_); | |
461 } | |
462 | |
463 void Window::SetCanAcceptEvents(bool can_accept_events) { | |
464 if (can_accept_events_ == can_accept_events) | |
465 return; | |
466 can_accept_events_ = can_accept_events; | |
467 if (client_) | |
468 client_->SetCanAcceptEvents(server_id_, can_accept_events_); | |
469 } | |
470 | |
471 void Window::Embed(ui::mojom::WindowTreeClientPtr client, uint32_t flags) { | |
472 Embed(std::move(client), base::Bind(&EmptyEmbedCallback), flags); | |
473 } | |
474 | |
475 void Window::Embed(ui::mojom::WindowTreeClientPtr client, | |
476 const EmbedCallback& callback, | |
477 uint32_t flags) { | |
478 if (PrepareForEmbed()) | |
479 client_->Embed(server_id_, std::move(client), flags, callback); | |
480 else | |
481 callback.Run(false); | |
482 } | |
483 | |
484 void Window::RequestClose() { | |
485 if (client_) | |
486 client_->RequestClose(this); | |
487 } | |
488 | |
489 void Window::PerformDragDrop( | |
490 const std::map<std::string, std::vector<uint8_t>>& drag_data, | |
491 int drag_operation, | |
492 const gfx::Point& cursor_location, | |
493 const SkBitmap& bitmap, | |
494 const base::Callback<void(bool, uint32_t)>& callback) { | |
495 client_->PerformDragDrop(this, drag_data, drag_operation, cursor_location, | |
496 bitmap, callback); | |
497 } | |
498 | |
499 void Window::CancelDragDrop() { | |
500 client_->CancelDragDrop(this); | |
501 } | |
502 | |
503 void Window::PerformWindowMove(mojom::MoveLoopSource source, | |
504 const gfx::Point& cursor_location, | |
505 const base::Callback<void(bool)>& callback) { | |
506 client_->PerformWindowMove(this, source, cursor_location, callback); | |
507 } | |
508 | |
509 void Window::CancelWindowMove() { | |
510 client_->CancelWindowMove(this); | |
511 } | |
512 | |
513 std::string Window::GetName() const { | |
514 if (HasSharedProperty(mojom::WindowManager::kName_Property)) | |
515 return GetSharedProperty<std::string>(mojom::WindowManager::kName_Property); | |
516 | |
517 return std::string(); | |
518 } | |
519 | |
520 //////////////////////////////////////////////////////////////////////////////// | |
521 // Window, protected: | |
522 | |
523 Window::Window() : Window(nullptr, static_cast<Id>(-1)) {} | |
524 | |
525 Window::~Window() { | |
526 for (auto& observer : observers_) | |
527 observer.OnWindowDestroying(this); | |
528 if (client_) | |
529 client_->OnWindowDestroying(this); | |
530 | |
531 if (HasFocus()) { | |
532 // The focused window is being removed. When this happens the server | |
533 // advances focus. We don't want to randomly pick a Window to get focus, so | |
534 // we update local state only, and wait for the next focus change from the | |
535 // server. | |
536 client_->LocalSetFocus(nullptr); | |
537 } | |
538 | |
539 // Remove from transient parent. | |
540 if (transient_parent_) | |
541 transient_parent_->LocalRemoveTransientWindow(this); | |
542 | |
543 // Return the surface reference if there is one. | |
544 if (surface_info_.id().is_valid()) | |
545 LocalSetSurfaceInfo(cc::SurfaceInfo()); | |
546 | |
547 // Remove transient children. | |
548 while (!transient_children_.empty()) { | |
549 Window* transient_child = transient_children_.front(); | |
550 LocalRemoveTransientWindow(transient_child); | |
551 transient_child->LocalDestroy(); | |
552 DCHECK(transient_children_.empty() || | |
553 transient_children_.front() != transient_child); | |
554 } | |
555 | |
556 if (parent_) | |
557 parent_->LocalRemoveChild(this); | |
558 | |
559 // We may still have children. This can happen if the embedder destroys the | |
560 // root while we're still alive. | |
561 while (!children_.empty()) { | |
562 Window* child = children_.front(); | |
563 LocalRemoveChild(child); | |
564 DCHECK(children_.empty() || children_.front() != child); | |
565 } | |
566 | |
567 // Notify observers before clearing properties (order matches aura::Window). | |
568 for (auto& observer : observers_) | |
569 observer.OnWindowDestroyed(this); | |
570 | |
571 // Clear properties. | |
572 for (auto& pair : prop_map_) { | |
573 if (pair.second.deallocator) | |
574 (*pair.second.deallocator)(pair.second.value); | |
575 } | |
576 prop_map_.clear(); | |
577 | |
578 // Invoke after observers so that can clean up any internal state observers | |
579 // may have changed. | |
580 if (window_tree()) | |
581 window_tree()->OnWindowDestroyed(this); | |
582 } | |
583 | |
584 //////////////////////////////////////////////////////////////////////////////// | |
585 // Window, private: | |
586 | |
587 Window::Window(WindowTreeClient* client, Id id) | |
588 : client_(client), | |
589 server_id_(id), | |
590 parent_(nullptr), | |
591 stacking_target_(nullptr), | |
592 transient_parent_(nullptr), | |
593 is_modal_(false), | |
594 // Matches aura, see aura::Window for details. | |
595 observers_(base::ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY), | |
596 input_event_handler_(nullptr), | |
597 visible_(false), | |
598 opacity_(1.0f), | |
599 display_id_(display::kInvalidDisplayId), | |
600 cursor_id_(mojom::Cursor::CURSOR_NULL), | |
601 parent_drawn_(false) {} | |
602 | |
603 void Window::SetSharedPropertyInternal(const std::string& name, | |
604 const std::vector<uint8_t>* value) { | |
605 if (!WasCreatedByThisClientOrIsRoot(this)) | |
606 return; | |
607 | |
608 if (client_) { | |
609 base::Optional<std::vector<uint8_t>> transport_value; | |
610 if (value) { | |
611 transport_value.emplace(value->size()); | |
612 if (value->size()) | |
613 memcpy(&transport_value.value().front(), &(value->front()), | |
614 value->size()); | |
615 } | |
616 // TODO: add test coverage of this (450303). | |
617 client_->SetProperty(this, name, std::move(transport_value)); | |
618 } | |
619 LocalSetSharedProperty(name, value); | |
620 } | |
621 | |
622 int64_t Window::SetLocalPropertyInternal(const void* key, | |
623 const char* name, | |
624 PropertyDeallocator deallocator, | |
625 int64_t value, | |
626 int64_t default_value) { | |
627 int64_t old = GetLocalPropertyInternal(key, default_value); | |
628 if (value == default_value) { | |
629 prop_map_.erase(key); | |
630 } else { | |
631 Value prop_value; | |
632 prop_value.name = name; | |
633 prop_value.value = value; | |
634 prop_value.deallocator = deallocator; | |
635 prop_map_[key] = prop_value; | |
636 } | |
637 for (auto& observer : observers_) | |
638 observer.OnWindowLocalPropertyChanged(this, key, old); | |
639 return old; | |
640 } | |
641 | |
642 int64_t Window::GetLocalPropertyInternal(const void* key, | |
643 int64_t default_value) const { | |
644 std::map<const void*, Value>::const_iterator iter = prop_map_.find(key); | |
645 if (iter == prop_map_.end()) | |
646 return default_value; | |
647 return iter->second.value; | |
648 } | |
649 | |
650 void Window::LocalDestroy() { | |
651 delete this; | |
652 } | |
653 | |
654 void Window::LocalAddChild(Window* child) { | |
655 ScopedTreeNotifier notifier(child, child->parent(), this); | |
656 if (child->parent()) | |
657 RemoveChildImpl(child, &child->parent_->children_); | |
658 children_.push_back(child); | |
659 child->parent_ = this; | |
660 child->display_id_ = display_id_; | |
661 } | |
662 | |
663 void Window::LocalRemoveChild(Window* child) { | |
664 DCHECK_EQ(this, child->parent()); | |
665 ScopedTreeNotifier notifier(child, this, nullptr); | |
666 RemoveChildImpl(child, &children_); | |
667 } | |
668 | |
669 void Window::LocalAddTransientWindow(Window* transient_window) { | |
670 if (transient_window->transient_parent()) | |
671 RemoveTransientWindowImpl(transient_window); | |
672 transient_children_.push_back(transient_window); | |
673 transient_window->transient_parent_ = this; | |
674 | |
675 // Restack |transient_window| properly above its transient parent, if they | |
676 // share the same parent. | |
677 if (transient_window->parent() == parent()) | |
678 RestackTransientDescendants(this, &GetStackingTarget, | |
679 &ReorderWithoutNotification); | |
680 | |
681 for (auto& observer : observers_) | |
682 observer.OnTransientChildAdded(this, transient_window); | |
683 } | |
684 | |
685 void Window::LocalRemoveTransientWindow(Window* transient_window) { | |
686 DCHECK_EQ(this, transient_window->transient_parent()); | |
687 RemoveTransientWindowImpl(transient_window); | |
688 for (auto& observer : observers_) | |
689 observer.OnTransientChildRemoved(this, transient_window); | |
690 } | |
691 | |
692 void Window::LocalSetModal() { | |
693 is_modal_ = true; | |
694 } | |
695 | |
696 bool Window::LocalReorder(Window* relative, mojom::OrderDirection direction) { | |
697 OrderChangedNotifier notifier(this, relative, direction); | |
698 return ReorderImpl(this, relative, direction, ¬ifier); | |
699 } | |
700 | |
701 void Window::LocalSetBounds(const gfx::Rect& old_bounds, | |
702 const gfx::Rect& new_bounds) { | |
703 // If this client owns the window, then it should be the only one to change | |
704 // the bounds. | |
705 DCHECK(!WasCreatedByThisClient() || old_bounds == bounds_); | |
706 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds); | |
707 bounds_ = new_bounds; | |
708 } | |
709 | |
710 void Window::LocalSetClientArea( | |
711 const gfx::Insets& new_client_area, | |
712 const std::vector<gfx::Rect>& additional_client_areas) { | |
713 const std::vector<gfx::Rect> old_additional_client_areas = | |
714 additional_client_areas_; | |
715 const gfx::Insets old_client_area = client_area_; | |
716 client_area_ = new_client_area; | |
717 additional_client_areas_ = additional_client_areas; | |
718 for (auto& observer : observers_) { | |
719 observer.OnWindowClientAreaChanged(this, old_client_area, | |
720 old_additional_client_areas); | |
721 } | |
722 } | |
723 | |
724 void Window::LocalSetDisplay(int64_t display_id) { | |
725 display_id_ = display_id; | |
726 // TODO(sad): Notify observers (of this window, and of the descendant windows) | |
727 // when a window moves from one display into another. https://crbug.com/614887 | |
728 } | |
729 | |
730 void Window::LocalSetParentDrawn(bool value) { | |
731 if (parent_drawn_ == value) | |
732 return; | |
733 | |
734 // As IsDrawn() is derived from |visible_| and |parent_drawn_|, only send | |
735 // drawn notification is the value of IsDrawn() is really changing. | |
736 if (IsDrawn() == value) { | |
737 parent_drawn_ = value; | |
738 return; | |
739 } | |
740 for (auto& observer : observers_) | |
741 observer.OnWindowDrawnChanging(this); | |
742 parent_drawn_ = value; | |
743 for (auto& observer : observers_) | |
744 observer.OnWindowDrawnChanged(this); | |
745 } | |
746 | |
747 void Window::LocalSetVisible(bool visible) { | |
748 if (visible_ == visible) | |
749 return; | |
750 | |
751 for (auto& observer : observers_) | |
752 observer.OnWindowVisibilityChanging(this, visible); | |
753 visible_ = visible; | |
754 if (parent_) { | |
755 for (auto& observer : parent_->observers_) | |
756 observer.OnChildWindowVisibilityChanged(this, visible); | |
757 } | |
758 | |
759 NotifyWindowVisibilityChanged(this, visible); | |
760 } | |
761 | |
762 void Window::LocalSetOpacity(float opacity) { | |
763 if (opacity_ == opacity) | |
764 return; | |
765 | |
766 float old_opacity = opacity_; | |
767 opacity_ = opacity; | |
768 for (auto& observer : observers_) | |
769 observer.OnWindowOpacityChanged(this, old_opacity, opacity_); | |
770 } | |
771 | |
772 void Window::LocalSetPredefinedCursor(mojom::Cursor cursor_id) { | |
773 if (cursor_id_ == cursor_id) | |
774 return; | |
775 | |
776 cursor_id_ = cursor_id; | |
777 for (auto& observer : observers_) | |
778 observer.OnWindowPredefinedCursorChanged(this, cursor_id); | |
779 } | |
780 | |
781 void Window::LocalSetSharedProperty(const std::string& name, | |
782 const std::vector<uint8_t>* value) { | |
783 std::vector<uint8_t> old_value; | |
784 std::vector<uint8_t>* old_value_ptr = nullptr; | |
785 auto it = properties_.find(name); | |
786 if (it != properties_.end()) { | |
787 old_value = it->second; | |
788 old_value_ptr = &old_value; | |
789 | |
790 if (value && old_value == *value) | |
791 return; | |
792 } else if (!value) { | |
793 // This property isn't set in |properties_| and |value| is nullptr, so | |
794 // there's no change. | |
795 return; | |
796 } | |
797 | |
798 if (value) { | |
799 properties_[name] = *value; | |
800 } else if (it != properties_.end()) { | |
801 properties_.erase(it); | |
802 } | |
803 | |
804 for (auto& observer : observers_) | |
805 observer.OnWindowSharedPropertyChanged(this, name, old_value_ptr, value); | |
806 } | |
807 | |
808 void Window::LocalSetSurfaceInfo(const cc::SurfaceInfo& surface_info) { | |
809 if (surface_info_.id().is_valid()) { | |
810 const cc::SurfaceId& existing_surface_id = surface_info_.id(); | |
811 const cc::SurfaceId& new_surface_id = surface_info.id(); | |
812 if (existing_surface_id.is_valid() && | |
813 existing_surface_id != new_surface_id) { | |
814 // TODO(kylechar): Start return reference here? | |
815 } | |
816 } | |
817 surface_info_ = surface_info; | |
818 } | |
819 | |
820 void Window::NotifyWindowStackingChanged() { | |
821 if (stacking_target_) { | |
822 Children::const_iterator window_i = std::find( | |
823 parent()->children().begin(), parent()->children().end(), this); | |
824 DCHECK(window_i != parent()->children().end()); | |
825 if (window_i != parent()->children().begin() && | |
826 (*(window_i - 1) == stacking_target_)) | |
827 return; | |
828 } | |
829 RestackTransientDescendants(this, &GetStackingTarget, | |
830 &ReorderWithoutNotification); | |
831 } | |
832 | |
833 void Window::NotifyWindowVisibilityChanged(Window* target, bool visible) { | |
834 if (!NotifyWindowVisibilityChangedDown(target, visible)) | |
835 return; // |this| has been deleted. | |
836 | |
837 NotifyWindowVisibilityChangedUp(target, visible); | |
838 } | |
839 | |
840 bool Window::NotifyWindowVisibilityChangedAtReceiver(Window* target, | |
841 bool visible) { | |
842 // |this| may be deleted during a call to OnWindowVisibilityChanged() on one | |
843 // of the observers. We create an local observer for that. In that case we | |
844 // exit without further access to any members. | |
845 WindowTracker tracker; | |
846 tracker.Add(this); | |
847 for (auto& observer : observers_) | |
848 observer.OnWindowVisibilityChanged(target, visible); | |
849 return tracker.Contains(this); | |
850 } | |
851 | |
852 bool Window::NotifyWindowVisibilityChangedDown(Window* target, bool visible) { | |
853 if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) | |
854 return false; // |this| was deleted. | |
855 std::set<const Window*> child_already_processed; | |
856 bool child_destroyed = false; | |
857 do { | |
858 child_destroyed = false; | |
859 for (Window::Children::const_iterator it = children_.begin(); | |
860 it != children_.end(); ++it) { | |
861 if (!child_already_processed.insert(*it).second) | |
862 continue; | |
863 if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { | |
864 // |*it| was deleted, |it| is invalid and |children_| has changed. We | |
865 // exit the current for-loop and enter a new one. | |
866 child_destroyed = true; | |
867 break; | |
868 } | |
869 } | |
870 } while (child_destroyed); | |
871 return true; | |
872 } | |
873 | |
874 void Window::NotifyWindowVisibilityChangedUp(Window* target, bool visible) { | |
875 // Start with the parent as we already notified |this| | |
876 // in NotifyWindowVisibilityChangedDown. | |
877 for (Window* window = parent(); window; window = window->parent()) { | |
878 bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible); | |
879 DCHECK(ret); | |
880 } | |
881 } | |
882 | |
883 bool Window::PrepareForEmbed() { | |
884 if (!WasCreatedByThisClient()) | |
885 return false; | |
886 | |
887 while (!children_.empty()) | |
888 RemoveChild(children_[0]); | |
889 return true; | |
890 } | |
891 | |
892 void Window::RemoveTransientWindowImpl(Window* transient_window) { | |
893 Window::Children::iterator it = std::find( | |
894 transient_children_.begin(), transient_children_.end(), transient_window); | |
895 if (it != transient_children_.end()) { | |
896 transient_children_.erase(it); | |
897 transient_window->transient_parent_ = nullptr; | |
898 } | |
899 // If |transient_window| and its former transient parent share the same | |
900 // parent, |transient_window| should be restacked properly so it is not among | |
901 // transient children of its former parent, anymore. | |
902 if (parent() == transient_window->parent()) | |
903 RestackTransientDescendants(this, &GetStackingTarget, | |
904 &ReorderWithoutNotification); | |
905 | |
906 // TOOD(fsamuel): We might want to notify observers here. | |
907 } | |
908 | |
909 // static | |
910 void Window::ReorderWithoutNotification(Window* window, | |
911 Window* relative, | |
912 mojom::OrderDirection direction) { | |
913 ReorderImpl(window, relative, direction, nullptr); | |
914 } | |
915 | |
916 // static | |
917 bool Window::ReorderImpl(Window* window, | |
918 Window* relative, | |
919 mojom::OrderDirection direction, | |
920 OrderChangedNotifier* notifier) { | |
921 DCHECK(relative); | |
922 DCHECK_NE(window, relative); | |
923 DCHECK_EQ(window->parent(), relative->parent()); | |
924 DCHECK(window->parent()); | |
925 | |
926 if (!AdjustStackingForTransientWindows(&window, &relative, &direction, | |
927 window->stacking_target_)) | |
928 return false; | |
929 | |
930 const size_t child_i = std::find(window->parent_->children_.begin(), | |
931 window->parent_->children_.end(), window) - | |
932 window->parent_->children_.begin(); | |
933 const size_t target_i = | |
934 std::find(window->parent_->children_.begin(), | |
935 window->parent_->children_.end(), relative) - | |
936 window->parent_->children_.begin(); | |
937 if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) || | |
938 (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) { | |
939 return false; | |
940 } | |
941 | |
942 if (notifier) | |
943 notifier->NotifyWindowReordering(); | |
944 | |
945 const size_t dest_i = direction == mojom::OrderDirection::ABOVE | |
946 ? (child_i < target_i ? target_i : target_i + 1) | |
947 : (child_i < target_i ? target_i - 1 : target_i); | |
948 window->parent_->children_.erase(window->parent_->children_.begin() + | |
949 child_i); | |
950 window->parent_->children_.insert(window->parent_->children_.begin() + dest_i, | |
951 window); | |
952 | |
953 window->NotifyWindowStackingChanged(); | |
954 | |
955 if (notifier) | |
956 notifier->NotifyWindowReordered(); | |
957 | |
958 return true; | |
959 } | |
960 | |
961 // static | |
962 Window** Window::GetStackingTarget(Window* window) { | |
963 return &window->stacking_target_; | |
964 } | |
965 } // namespace ui | |
OLD | NEW |