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

Side by Side Diff: components/mus/public/cpp/lib/window.cc

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

Powered by Google App Engine
This is Rietveld 408576698