window.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright (c) 2012 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 "ui/aura/window.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/logging.h"
13#include "base/stl_util.h"
14#include "base/strings/string_util.h"
15#include "base/strings/stringprintf.h"
16#include "ui/aura/client/capture_client.h"
17#include "ui/aura/client/event_client.h"
18#include "ui/aura/client/screen_position_client.h"
19#include "ui/aura/client/stacking_client.h"
20#include "ui/aura/client/visibility_client.h"
21#include "ui/aura/env.h"
22#include "ui/aura/focus_manager.h"
23#include "ui/aura/layout_manager.h"
24#include "ui/aura/root_window.h"
25#include "ui/aura/window_delegate.h"
26#include "ui/aura/window_destruction_observer.h"
27#include "ui/aura/window_observer.h"
28#include "ui/base/animation/multi_animation.h"
29#include "ui/compositor/compositor.h"
30#include "ui/compositor/layer.h"
31#include "ui/gfx/canvas.h"
32#include "ui/gfx/path.h"
33#include "ui/gfx/screen.h"
34
35namespace aura {
36
37namespace {
38
39void MailboxReleaseCallback(scoped_ptr<base::SharedMemory> shared_memory,
40                            unsigned sync_point, bool lost_resource) {
41  // NOTE: shared_memory will get released when we go out of scope.
42}
43
44}  // namespace
45
46Window::Window(WindowDelegate* delegate)
47    : type_(client::WINDOW_TYPE_UNKNOWN),
48      owned_by_parent_(true),
49      delegate_(delegate),
50      parent_(NULL),
51      transient_parent_(NULL),
52      visible_(false),
53      id_(-1),
54      transparent_(false),
55      user_data_(NULL),
56      ignore_events_(false),
57      // Don't notify newly added observers during notification. This causes
58      // problems for code that adds an observer as part of an observer
59      // notification (such as the workspace code).
60      observers_(ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY) {
61  set_target_handler(delegate_);
62}
63
64Window::~Window() {
65  // layer_ can be NULL if Init() wasn't invoked, which can happen
66  // only in tests.
67  if (layer_)
68    layer_->SuppressPaint();
69
70  // Let the delegate know we're in the processing of destroying.
71  if (delegate_)
72    delegate_->OnWindowDestroying();
73  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
74
75  // Let the root know so that it can remove any references to us.
76  RootWindow* root_window = GetRootWindow();
77  if (root_window)
78    root_window->OnWindowDestroying(this);
79
80  // Then destroy the children.
81  while (!children_.empty()) {
82    Window* child = children_[0];
83    if (child->owned_by_parent_) {
84      delete child;
85      // Deleting the child so remove it from out children_ list.
86      DCHECK(std::find(children_.begin(), children_.end(), child) ==
87             children_.end());
88    } else {
89      // Even if we can't delete the child, we still need to remove it from the
90      // parent so that relevant bookkeeping (parent_ back-pointers etc) are
91      // updated.
92      RemoveChild(child);
93    }
94  }
95
96  // Removes ourselves from our transient parent (if it hasn't been done by the
97  // RootWindow).
98  if (transient_parent_)
99    transient_parent_->RemoveTransientChild(this);
100
101  // The window needs to be removed from the parent before calling the
102  // WindowDestroyed callbacks of delegate and the observers.
103  if (parent_)
104    parent_->RemoveChild(this);
105
106  // And let the delegate do any post cleanup.
107  // TODO(beng): Figure out if this notification needs to happen here, or if it
108  // can be moved down adjacent to the observer notification. If it has to be
109  // done here, the reason why should be documented.
110  if (delegate_)
111    delegate_->OnWindowDestroyed();
112
113  // Destroy transient children, only after we've removed ourselves from our
114  // parent, as destroying an active transient child may otherwise attempt to
115  // refocus us.
116  Windows transient_children(transient_children_);
117  STLDeleteElements(&transient_children);
118  DCHECK(transient_children_.empty());
119
120  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
121
122  // Clear properties.
123  for (std::map<const void*, Value>::const_iterator iter = prop_map_.begin();
124       iter != prop_map_.end();
125       ++iter) {
126    if (iter->second.deallocator)
127      (*iter->second.deallocator)(iter->second.value);
128  }
129  prop_map_.clear();
130
131  // If we have layer it will either be destroyed by layer_owner_'s dtor, or by
132  // whoever acquired it. We don't have a layer if Init() wasn't invoked, which
133  // can happen in tests.
134  if (layer_)
135    layer_->set_delegate(NULL);
136  layer_ = NULL;
137}
138
139void Window::Init(ui::LayerType layer_type) {
140  layer_ = new ui::Layer(layer_type);
141  layer_owner_.reset(layer_);
142  layer_->SetVisible(false);
143  layer_->set_delegate(this);
144  UpdateLayerName(name_);
145  layer_->SetFillsBoundsOpaquely(!transparent_);
146
147  Env::GetInstance()->NotifyWindowInitialized(this);
148}
149
150ui::Layer* Window::RecreateLayer() {
151  // Disconnect the old layer, but don't delete it.
152  ui::Layer* old_layer = AcquireLayer();
153  if (!old_layer)
154    return NULL;
155
156  old_layer->set_delegate(NULL);
157  float mailbox_scale_factor;
158  cc::TextureMailbox old_mailbox =
159      old_layer->GetTextureMailbox(&mailbox_scale_factor);
160  scoped_refptr<ui::Texture> old_texture = old_layer->external_texture();
161  if (delegate_ && old_texture.get())
162    old_layer->SetExternalTexture(delegate_->CopyTexture());
163
164  layer_ = new ui::Layer(old_layer->type());
165  layer_owner_.reset(layer_);
166  layer_->SetVisible(old_layer->visible());
167  layer_->set_scale_content(old_layer->scale_content());
168  layer_->set_delegate(this);
169  layer_->SetMasksToBounds(old_layer->GetMasksToBounds());
170  // Move the original texture to the new layer if the old layer has a
171  // texture and we could copy it into the old layer,
172  // crbug.com/175211.
173  if (delegate_ && old_texture.get()) {
174    layer_->SetExternalTexture(old_texture.get());
175  } else if (old_mailbox.IsSharedMemory()) {
176    base::SharedMemory* old_buffer = old_mailbox.shared_memory();
177    const size_t size = old_mailbox.shared_memory_size_in_bytes();
178
179    scoped_ptr<base::SharedMemory> new_buffer(new base::SharedMemory);
180    new_buffer->CreateAndMapAnonymous(size);
181
182    if (old_buffer->memory() && new_buffer->memory()) {
183      memcpy(new_buffer->memory(), old_buffer->memory(), size);
184      base::SharedMemory* new_buffer_raw_ptr = new_buffer.get();
185      cc::TextureMailbox::ReleaseCallback callback =
186          base::Bind(MailboxReleaseCallback, Passed(&new_buffer));
187      cc::TextureMailbox new_mailbox(new_buffer_raw_ptr,
188                                     old_mailbox.shared_memory_size(),
189                                     callback);
190      layer_->SetTextureMailbox(new_mailbox, mailbox_scale_factor);
191    }
192  }
193
194  UpdateLayerName(name_);
195  layer_->SetFillsBoundsOpaquely(!transparent_);
196  // Install new layer as a sibling of the old layer, stacked below it.
197  if (old_layer->parent()) {
198    old_layer->parent()->Add(layer_);
199    old_layer->parent()->StackBelow(layer_, old_layer);
200  }
201  // Migrate all the child layers over to the new layer. Copy the list because
202  // the items are removed during iteration.
203  std::vector<ui::Layer*> children_copy = old_layer->children();
204  for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin();
205       it != children_copy.end();
206       ++it) {
207    ui::Layer* child = *it;
208    layer_->Add(child);
209  }
210  return old_layer;
211}
212
213void Window::SetType(client::WindowType type) {
214  // Cannot change type after the window is initialized.
215  DCHECK(!layer());
216  type_ = type;
217}
218
219void Window::SetName(const std::string& name) {
220  name_ = name;
221
222  if (layer())
223    UpdateLayerName(name_);
224}
225
226void Window::SetTransparent(bool transparent) {
227  // Cannot change transparent flag after the window is initialized.
228  DCHECK(!layer());
229  transparent_ = transparent;
230}
231
232RootWindow* Window::GetRootWindow() {
233  return const_cast<RootWindow*>(
234      static_cast<const Window*>(this)->GetRootWindow());
235}
236
237const RootWindow* Window::GetRootWindow() const {
238  return parent_ ? parent_->GetRootWindow() : NULL;
239}
240
241void Window::Show() {
242  SetVisible(true);
243}
244
245void Window::Hide() {
246  for (Windows::iterator it = transient_children_.begin();
247       it != transient_children_.end(); ++it) {
248    (*it)->Hide();
249  }
250  SetVisible(false);
251  ReleaseCapture();
252}
253
254bool Window::IsVisible() const {
255  // Layer visibility can be inconsistent with window visibility, for example
256  // when a Window is hidden, we want this function to return false immediately
257  // after, even though the client may decide to animate the hide effect (and
258  // so the layer will be visible for some time after Hide() is called).
259  return visible_ && layer_ && layer_->IsDrawn();
260}
261
262gfx::Rect Window::GetBoundsInRootWindow() const {
263  // TODO(beng): There may be a better way to handle this, and the existing code
264  //             is likely wrong anyway in a multi-display world, but this will
265  //             do for now.
266  if (!GetRootWindow())
267    return bounds();
268  gfx::Point origin = bounds().origin();
269  ConvertPointToTarget(parent_, GetRootWindow(), &origin);
270  return gfx::Rect(origin, bounds().size());
271}
272
273gfx::Rect Window::GetBoundsInScreen() const {
274  gfx::Rect bounds(GetBoundsInRootWindow());
275  const RootWindow* root = GetRootWindow();
276  if (root) {
277    aura::client::ScreenPositionClient* screen_position_client =
278        aura::client::GetScreenPositionClient(root);
279    if (screen_position_client) {
280      gfx::Point origin = bounds.origin();
281      screen_position_client->ConvertPointToScreen(root, &origin);
282      bounds.set_origin(origin);
283    }
284  }
285  return bounds;
286}
287
288void Window::SetTransform(const gfx::Transform& transform) {
289  RootWindow* root_window = GetRootWindow();
290  bool contained_mouse = IsVisible() && root_window &&
291      ContainsPointInRoot(root_window->GetLastMouseLocationInRoot());
292  layer()->SetTransform(transform);
293  if (root_window)
294    root_window->OnWindowTransformed(this, contained_mouse);
295}
296
297void Window::SetLayoutManager(LayoutManager* layout_manager) {
298  if (layout_manager == layout_manager_)
299    return;
300  layout_manager_.reset(layout_manager);
301  if (!layout_manager)
302    return;
303  // If we're changing to a new layout manager, ensure it is aware of all the
304  // existing child windows.
305  for (Windows::const_iterator it = children_.begin();
306       it != children_.end();
307       ++it)
308    layout_manager_->OnWindowAddedToLayout(*it);
309}
310
311void Window::SetBounds(const gfx::Rect& new_bounds) {
312  if (parent_ && parent_->layout_manager())
313    parent_->layout_manager()->SetChildBounds(this, new_bounds);
314  else
315    SetBoundsInternal(new_bounds);
316}
317
318void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen,
319                               const gfx::Display& dst_display) {
320  RootWindow* root = GetRootWindow();
321  if (root) {
322    gfx::Point origin = new_bounds_in_screen.origin();
323    aura::client::ScreenPositionClient* screen_position_client =
324        aura::client::GetScreenPositionClient(root);
325    screen_position_client->SetBounds(this, new_bounds_in_screen, dst_display);
326    return;
327  }
328  SetBounds(new_bounds_in_screen);
329}
330
331gfx::Rect Window::GetTargetBounds() const {
332  return layer_->GetTargetBounds();
333}
334
335const gfx::Rect& Window::bounds() const {
336  return layer_->bounds();
337}
338
339void Window::SchedulePaintInRect(const gfx::Rect& rect) {
340  if (layer_->SchedulePaint(rect)) {
341    FOR_EACH_OBSERVER(
342        WindowObserver, observers_, OnWindowPaintScheduled(this, rect));
343  }
344}
345
346void Window::SetDefaultParentByRootWindow(RootWindow* root_window,
347                                          const gfx::Rect& bounds_in_screen) {
348  DCHECK(root_window);
349
350  // Stacking clients are mandatory on RootWindow objects.
351  client::StackingClient* client = client::GetStackingClient(root_window);
352  DCHECK(client);
353
354  aura::Window* default_parent = client->GetDefaultParent(
355      root_window, this, bounds_in_screen);
356  default_parent->AddChild(this);
357}
358
359void Window::StackChildAtTop(Window* child) {
360  if (children_.size() <= 1 || child == children_.back())
361    return;  // In the front already.
362  StackChildAbove(child, children_.back());
363}
364
365void Window::StackChildAbove(Window* child, Window* target) {
366  StackChildRelativeTo(child, target, STACK_ABOVE);
367}
368
369void Window::StackChildAtBottom(Window* child) {
370  if (children_.size() <= 1 || child == children_.front())
371    return;  // At the bottom already.
372  StackChildBelow(child, children_.front());
373}
374
375void Window::StackChildBelow(Window* child, Window* target) {
376  StackChildRelativeTo(child, target, STACK_BELOW);
377}
378
379void Window::AddChild(Window* child) {
380  WindowObserver::HierarchyChangeParams params;
381  params.target = child;
382  params.new_parent = this;
383  params.old_parent = child->parent();
384  params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
385  NotifyWindowHierarchyChange(params);
386
387  RootWindow* old_root = child->GetRootWindow();
388
389  DCHECK(std::find(children_.begin(), children_.end(), child) ==
390      children_.end());
391  if (child->parent())
392    child->parent()->RemoveChildImpl(child, this);
393  child->parent_ = this;
394
395  layer_->Add(child->layer_);
396
397  children_.push_back(child);
398  if (layout_manager_)
399    layout_manager_->OnWindowAddedToLayout(child);
400  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowAdded(child));
401  child->OnParentChanged();
402
403  RootWindow* root_window = GetRootWindow();
404  if (root_window && old_root != root_window) {
405    root_window->OnWindowAddedToRootWindow(child);
406    child->NotifyAddedToRootWindow();
407  }
408
409  params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
410  NotifyWindowHierarchyChange(params);
411}
412
413void Window::RemoveChild(Window* child) {
414  WindowObserver::HierarchyChangeParams params;
415  params.target = child;
416  params.new_parent = NULL;
417  params.old_parent = this;
418  params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
419  NotifyWindowHierarchyChange(params);
420
421  RemoveChildImpl(child, NULL);
422
423  params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
424  NotifyWindowHierarchyChange(params);
425}
426
427bool Window::Contains(const Window* other) const {
428  for (const Window* parent = other; parent; parent = parent->parent_) {
429    if (parent == this)
430      return true;
431  }
432  return false;
433}
434
435void Window::AddTransientChild(Window* child) {
436  if (child->transient_parent_)
437    child->transient_parent_->RemoveTransientChild(child);
438  DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
439                   child) == transient_children_.end());
440  transient_children_.push_back(child);
441  child->transient_parent_ = this;
442  FOR_EACH_OBSERVER(WindowObserver, observers_,
443                    OnAddTransientChild(this, child));
444}
445
446void Window::RemoveTransientChild(Window* child) {
447  Windows::iterator i =
448      std::find(transient_children_.begin(), transient_children_.end(), child);
449  DCHECK(i != transient_children_.end());
450  transient_children_.erase(i);
451  if (child->transient_parent_ == this)
452    child->transient_parent_ = NULL;
453  FOR_EACH_OBSERVER(WindowObserver, observers_,
454                    OnRemoveTransientChild(this, child));
455}
456
457Window* Window::GetChildById(int id) {
458  return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id));
459}
460
461const Window* Window::GetChildById(int id) const {
462  Windows::const_iterator i;
463  for (i = children_.begin(); i != children_.end(); ++i) {
464    if ((*i)->id() == id)
465      return *i;
466    const Window* result = (*i)->GetChildById(id);
467    if (result)
468      return result;
469  }
470  return NULL;
471}
472
473// static
474void Window::ConvertPointToTarget(const Window* source,
475                                  const Window* target,
476                                  gfx::Point* point) {
477  if (!source)
478    return;
479  if (source->GetRootWindow() != target->GetRootWindow()) {
480    client::ScreenPositionClient* source_client =
481        GetScreenPositionClient(source->GetRootWindow());
482    source_client->ConvertPointToScreen(source, point);
483
484    client::ScreenPositionClient* target_client =
485        GetScreenPositionClient(target->GetRootWindow());
486    target_client->ConvertPointFromScreen(target, point);
487  } else {
488    ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point);
489  }
490}
491
492void Window::MoveCursorTo(const gfx::Point& point_in_window) {
493  RootWindow* root_window = GetRootWindow();
494  DCHECK(root_window);
495  gfx::Point point_in_root(point_in_window);
496  ConvertPointToTarget(this, root_window, &point_in_root);
497  root_window->MoveCursorTo(point_in_root);
498}
499
500gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const {
501  return delegate_ ? delegate_->GetCursor(point) : gfx::kNullCursor;
502}
503
504void Window::SetEventFilter(ui::EventHandler* event_filter) {
505  if (event_filter_)
506    RemovePreTargetHandler(event_filter_.get());
507  event_filter_.reset(event_filter);
508  if (event_filter)
509    AddPreTargetHandler(event_filter);
510}
511
512void Window::AddObserver(WindowObserver* observer) {
513  observers_.AddObserver(observer);
514}
515
516void Window::RemoveObserver(WindowObserver* observer) {
517  observers_.RemoveObserver(observer);
518}
519
520bool Window::HasObserver(WindowObserver* observer) {
521  return observers_.HasObserver(observer);
522}
523
524bool Window::ContainsPointInRoot(const gfx::Point& point_in_root) const {
525  const Window* root_window = GetRootWindow();
526  if (!root_window)
527    return false;
528  gfx::Point local_point(point_in_root);
529  ConvertPointToTarget(root_window, this, &local_point);
530  return gfx::Rect(GetTargetBounds().size()).Contains(local_point);
531}
532
533bool Window::ContainsPoint(const gfx::Point& local_point) const {
534  return gfx::Rect(bounds().size()).Contains(local_point);
535}
536
537bool Window::HitTest(const gfx::Point& local_point) {
538  // Expand my bounds for hit testing (override is usually zero but it's
539  // probably cheaper to do the math every time than to branch).
540  gfx::Rect local_bounds(gfx::Point(), bounds().size());
541  local_bounds.Inset(aura::Env::GetInstance()->is_touch_down() ?
542      hit_test_bounds_override_outer_touch_ :
543      hit_test_bounds_override_outer_mouse_);
544
545  if (!delegate_ || !delegate_->HasHitTestMask())
546    return local_bounds.Contains(local_point);
547
548  gfx::Path mask;
549  delegate_->GetHitTestMask(&mask);
550
551  SkRegion clip_region;
552  clip_region.setRect(local_bounds.x(), local_bounds.y(),
553                      local_bounds.width(), local_bounds.height());
554  SkRegion mask_region;
555  return mask_region.setPath(mask, clip_region) &&
556      mask_region.contains(local_point.x(), local_point.y());
557}
558
559Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) {
560  return GetWindowForPoint(local_point, true, true);
561}
562
563Window* Window::GetTopWindowContainingPoint(const gfx::Point& local_point) {
564  return GetWindowForPoint(local_point, false, false);
565}
566
567Window* Window::GetToplevelWindow() {
568  Window* topmost_window_with_delegate = NULL;
569  for (aura::Window* window = this; window != NULL; window = window->parent()) {
570    if (window->delegate())
571      topmost_window_with_delegate = window;
572  }
573  return topmost_window_with_delegate;
574}
575
576void Window::Focus() {
577  client::FocusClient* client = client::GetFocusClient(this);
578  DCHECK(client);
579  client->FocusWindow(this);
580}
581
582void Window::Blur() {
583  client::FocusClient* client = client::GetFocusClient(this);
584  DCHECK(client);
585  client->FocusWindow(NULL);
586}
587
588bool Window::HasFocus() const {
589  client::FocusClient* client = client::GetFocusClient(this);
590  return client && client->GetFocusedWindow() == this;
591}
592
593bool Window::CanFocus() const {
594  // NOTE: as part of focusing the window the ActivationClient may make the
595  // window visible (by way of making a hidden ancestor visible). For this
596  // reason we can't check visibility here and assume the client is doing it.
597  if (!parent_ || (delegate_ && !delegate_->CanFocus()))
598    return false;
599
600  // The client may forbid certain windows from receiving focus at a given point
601  // in time.
602  client::EventClient* client = client::GetEventClient(GetRootWindow());
603  if (client && !client->CanProcessEventsWithinSubtree(this))
604    return false;
605
606  return parent_->CanFocus();
607}
608
609bool Window::CanReceiveEvents() const {
610  // The client may forbid certain windows from receiving events at a given
611  // point in time.
612  client::EventClient* client = client::GetEventClient(GetRootWindow());
613  if (client && !client->CanProcessEventsWithinSubtree(this))
614    return false;
615
616  return parent_ && IsVisible() && parent_->CanReceiveEvents();
617}
618
619void Window::SetCapture() {
620  if (!IsVisible())
621    return;
622
623  RootWindow* root_window = GetRootWindow();
624  if (!root_window)
625    return;
626  client::GetCaptureClient(root_window)->SetCapture(this);
627}
628
629void Window::ReleaseCapture() {
630  RootWindow* root_window = GetRootWindow();
631  if (!root_window)
632    return;
633  client::GetCaptureClient(root_window)->ReleaseCapture(this);
634}
635
636bool Window::HasCapture() {
637  RootWindow* root_window = GetRootWindow();
638  return root_window &&
639      client::GetCaptureClient(root_window)->GetCaptureWindow() == this;
640}
641
642void Window::SuppressPaint() {
643  layer_->SuppressPaint();
644}
645
646// {Set,Get,Clear}Property are implemented in window_property.h.
647
648void Window::SetNativeWindowProperty(const char* key, void* value) {
649  SetPropertyInternal(
650      key, key, NULL, reinterpret_cast<int64>(value), 0);
651}
652
653void* Window::GetNativeWindowProperty(const char* key) const {
654  return reinterpret_cast<void*>(GetPropertyInternal(key, 0));
655}
656
657void Window::OnDeviceScaleFactorChanged(float device_scale_factor) {
658  if (delegate_)
659    delegate_->OnDeviceScaleFactorChanged(device_scale_factor);
660}
661
662#ifndef NDEBUG
663std::string Window::GetDebugInfo() const {
664  return base::StringPrintf(
665      "%s<%d> bounds(%d, %d, %d, %d) %s %s opacity=%.1f",
666      name().empty() ? "Unknown" : name().c_str(), id(),
667      bounds().x(), bounds().y(), bounds().width(), bounds().height(),
668      visible_ ? "WindowVisible" : "WindowHidden",
669      layer_->GetTargetVisibility() ? "LayerVisible" : "LayerHidden",
670      layer_->opacity());
671}
672
673void Window::PrintWindowHierarchy(int depth) const {
674  printf("%*s%s\n", depth * 2, "", GetDebugInfo().c_str());
675  for (Windows::const_iterator it = children_.begin();
676       it != children_.end(); ++it) {
677    Window* child = *it;
678    child->PrintWindowHierarchy(depth + 1);
679  }
680}
681#endif
682
683///////////////////////////////////////////////////////////////////////////////
684// Window, private:
685
686int64 Window::SetPropertyInternal(const void* key,
687                                  const char* name,
688                                  PropertyDeallocator deallocator,
689                                  int64 value,
690                                  int64 default_value) {
691  int64 old = GetPropertyInternal(key, default_value);
692  if (value == default_value) {
693    prop_map_.erase(key);
694  } else {
695    Value prop_value;
696    prop_value.name = name;
697    prop_value.value = value;
698    prop_value.deallocator = deallocator;
699    prop_map_[key] = prop_value;
700  }
701  FOR_EACH_OBSERVER(WindowObserver, observers_,
702                    OnWindowPropertyChanged(this, key, old));
703  return old;
704}
705
706int64 Window::GetPropertyInternal(const void* key,
707                                  int64 default_value) const {
708  std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
709  if (iter == prop_map_.end())
710    return default_value;
711  return iter->second.value;
712}
713
714void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
715  gfx::Rect actual_new_bounds(new_bounds);
716
717  // Ensure we don't go smaller than our minimum bounds.
718  if (delegate_) {
719    const gfx::Size& min_size = delegate_->GetMinimumSize();
720    actual_new_bounds.set_width(
721        std::max(min_size.width(), actual_new_bounds.width()));
722    actual_new_bounds.set_height(
723        std::max(min_size.height(), actual_new_bounds.height()));
724  }
725
726  gfx::Rect old_bounds = GetTargetBounds();
727
728  // Always need to set the layer's bounds -- even if it is to the same thing.
729  // This may cause important side effects such as stopping animation.
730  layer_->SetBounds(actual_new_bounds);
731
732  // If we are currently not the layer's delegate, we will not get bounds
733  // changed notification from the layer (this typically happens after animating
734  // hidden). We must notify ourselves.
735  if (layer_->delegate() != this)
736    OnLayerBoundsChanged(old_bounds, ContainsMouse());
737}
738
739void Window::SetVisible(bool visible) {
740  if (visible == layer_->GetTargetVisibility())
741    return;  // No change.
742
743  FOR_EACH_OBSERVER(WindowObserver, observers_,
744                    OnWindowVisibilityChanging(this, visible));
745
746  RootWindow* root_window = GetRootWindow();
747  if (root_window)
748    root_window->DispatchMouseExitToHidingWindow(this);
749
750  client::VisibilityClient* visibility_client =
751      client::GetVisibilityClient(this);
752  if (visibility_client)
753    visibility_client->UpdateLayerVisibility(this, visible);
754  else
755    layer_->SetVisible(visible);
756  visible_ = visible;
757  SchedulePaint();
758  if (parent_ && parent_->layout_manager_)
759    parent_->layout_manager_->OnChildWindowVisibilityChanged(this, visible);
760
761  if (delegate_)
762    delegate_->OnWindowTargetVisibilityChanged(visible);
763
764  NotifyWindowVisibilityChanged(this, visible);
765
766  if (root_window)
767    root_window->OnWindowVisibilityChanged(this, visible);
768}
769
770void Window::SchedulePaint() {
771  SchedulePaintInRect(gfx::Rect(0, 0, bounds().width(), bounds().height()));
772}
773
774Window* Window::GetWindowForPoint(const gfx::Point& local_point,
775                                  bool return_tightest,
776                                  bool for_event_handling) {
777  if (!IsVisible())
778    return NULL;
779
780  if ((for_event_handling && !HitTest(local_point)) ||
781      (!for_event_handling && !ContainsPoint(local_point)))
782    return NULL;
783
784  // Check if I should claim this event and not pass it to my children because
785  // the location is inside my hit test override area.  For details, see
786  // set_hit_test_bounds_override_inner().
787  if (for_event_handling && !hit_test_bounds_override_inner_.empty()) {
788    gfx::Rect inset_local_bounds(gfx::Point(), bounds().size());
789    inset_local_bounds.Inset(hit_test_bounds_override_inner_);
790    // We know we're inside the normal local bounds, so if we're outside the
791    // inset bounds we must be in the special hit test override area.
792    DCHECK(HitTest(local_point));
793    if (!inset_local_bounds.Contains(local_point))
794      return delegate_ ? this : NULL;
795  }
796
797  if (!return_tightest && delegate_)
798    return this;
799
800  for (Windows::const_reverse_iterator it = children_.rbegin(),
801           rend = children_.rend();
802       it != rend; ++it) {
803    Window* child = *it;
804
805    if (for_event_handling) {
806      // The client may not allow events to be processed by certain subtrees.
807      client::EventClient* client = client::GetEventClient(GetRootWindow());
808      if (client && !client->CanProcessEventsWithinSubtree(child))
809        continue;
810    }
811
812    // We don't process events for invisible windows or those that have asked
813    // to ignore events.
814    if (!child->IsVisible() || (for_event_handling && child->ignore_events_))
815      continue;
816
817    gfx::Point point_in_child_coords(local_point);
818    ConvertPointToTarget(this, child, &point_in_child_coords);
819    if (for_event_handling && delegate_ &&
820        !delegate_->ShouldDescendIntoChildForEventHandling(
821            child, local_point)) {
822      continue;
823    }
824
825    Window* match = child->GetWindowForPoint(point_in_child_coords,
826                                             return_tightest,
827                                             for_event_handling);
828    if (match)
829      return match;
830  }
831
832  return delegate_ ? this : NULL;
833}
834
835void Window::RemoveChildImpl(Window* child, Window* new_parent) {
836  if (layout_manager_)
837    layout_manager_->OnWillRemoveWindowFromLayout(child);
838  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child));
839  RootWindow* root_window = child->GetRootWindow();
840  RootWindow* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL;
841  if (root_window && root_window != new_root_window) {
842    root_window->OnWindowRemovedFromRootWindow(child, new_root_window);
843    child->NotifyRemovingFromRootWindow();
844  }
845  child->parent_ = NULL;
846  // We should only remove the child's layer if the child still owns that layer.
847  // Someone else may have acquired ownership of it via AcquireLayer() and may
848  // expect the hierarchy to go unchanged as the Window is destroyed.
849  if (child->layer_owner_)
850    layer_->Remove(child->layer_);
851  Windows::iterator i = std::find(children_.begin(), children_.end(), child);
852  DCHECK(i != children_.end());
853  children_.erase(i);
854  child->OnParentChanged();
855  if (layout_manager_)
856    layout_manager_->OnWindowRemovedFromLayout(child);
857}
858
859void Window::OnParentChanged() {
860  FOR_EACH_OBSERVER(
861      WindowObserver, observers_, OnWindowParentChanged(this, parent_));
862}
863
864void Window::StackChildRelativeTo(Window* child,
865                                  Window* target,
866                                  StackDirection direction) {
867  DCHECK_NE(child, target);
868  DCHECK(child);
869  DCHECK(target);
870  DCHECK_EQ(this, child->parent());
871  DCHECK_EQ(this, target->parent());
872
873  const size_t target_i =
874      std::find(children_.begin(), children_.end(), target) - children_.begin();
875
876  // By convention we don't stack on top of windows with layers with NULL
877  // delegates.  Walk backward to find a valid target window.
878  // See tests WindowTest.StackingMadrigal and StackOverClosingTransient
879  // for an explanation of this.
880  size_t final_target_i = target_i;
881  while (final_target_i > 0 &&
882         children_[final_target_i]->layer()->delegate() == NULL) {
883    --final_target_i;
884  }
885
886  // Allow stacking immediately below a window with a NULL layer.
887  if (direction == STACK_BELOW && target_i != final_target_i)
888    direction = STACK_ABOVE;
889
890  Window* final_target = children_[final_target_i];
891
892  // If we couldn't find a valid target position, don't move anything.
893  if (final_target->layer()->delegate() == NULL)
894    return;
895
896  // Don't try to stack a child above itself.
897  if (child == final_target)
898    return;
899
900  // Move the child and all its transients.
901  StackChildRelativeToImpl(child, final_target, direction);
902}
903
904void Window::StackChildRelativeToImpl(Window* child,
905                                      Window* target,
906                                      StackDirection direction) {
907  DCHECK_NE(child, target);
908  DCHECK(child);
909  DCHECK(target);
910  DCHECK_EQ(this, child->parent());
911  DCHECK_EQ(this, target->parent());
912
913  const size_t child_i =
914      std::find(children_.begin(), children_.end(), child) - children_.begin();
915  const size_t target_i =
916      std::find(children_.begin(), children_.end(), target) - children_.begin();
917
918  // Don't move the child if it is already in the right place.
919  if ((direction == STACK_ABOVE && child_i == target_i + 1) ||
920      (direction == STACK_BELOW && child_i + 1 == target_i))
921    return;
922
923  const size_t dest_i =
924      direction == STACK_ABOVE ?
925      (child_i < target_i ? target_i : target_i + 1) :
926      (child_i < target_i ? target_i - 1 : target_i);
927  children_.erase(children_.begin() + child_i);
928  children_.insert(children_.begin() + dest_i, child);
929
930  if (direction == STACK_ABOVE)
931    layer()->StackAbove(child->layer(), target->layer());
932  else
933    layer()->StackBelow(child->layer(), target->layer());
934
935  // Stack any transient children that share the same parent to be in front of
936  // 'child'.
937  Window* last_transient = child;
938  for (Windows::iterator it = child->transient_children_.begin();
939       it != child->transient_children_.end(); ++it) {
940    Window* transient_child = *it;
941    if (transient_child->parent_ == this) {
942      StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE);
943      last_transient = transient_child;
944    }
945  }
946
947  child->OnStackingChanged();
948}
949
950void Window::OnStackingChanged() {
951  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowStackingChanged(this));
952}
953
954void Window::NotifyRemovingFromRootWindow() {
955  FOR_EACH_OBSERVER(WindowObserver, observers_,
956                    OnWindowRemovingFromRootWindow(this));
957  for (Window::Windows::const_iterator it = children_.begin();
958       it != children_.end(); ++it) {
959    (*it)->NotifyRemovingFromRootWindow();
960  }
961}
962
963void Window::NotifyAddedToRootWindow() {
964  FOR_EACH_OBSERVER(WindowObserver, observers_,
965                    OnWindowAddedToRootWindow(this));
966  for (Window::Windows::const_iterator it = children_.begin();
967       it != children_.end(); ++it) {
968    (*it)->NotifyAddedToRootWindow();
969  }
970}
971
972void Window::NotifyWindowHierarchyChange(
973    const WindowObserver::HierarchyChangeParams& params) {
974  params.target->NotifyWindowHierarchyChangeDown(params);
975  switch (params.phase) {
976  case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING:
977    if (params.old_parent)
978      params.old_parent->NotifyWindowHierarchyChangeUp(params);
979    break;
980  case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED:
981    if (params.new_parent)
982      params.new_parent->NotifyWindowHierarchyChangeUp(params);
983    break;
984  default:
985    NOTREACHED();
986    break;
987  }
988}
989
990void Window::NotifyWindowHierarchyChangeDown(
991    const WindowObserver::HierarchyChangeParams& params) {
992  NotifyWindowHierarchyChangeAtReceiver(params);
993  for (Window::Windows::const_iterator it = children_.begin();
994       it != children_.end(); ++it) {
995    (*it)->NotifyWindowHierarchyChangeDown(params);
996  }
997}
998
999void Window::NotifyWindowHierarchyChangeUp(
1000    const WindowObserver::HierarchyChangeParams& params) {
1001  for (Window* window = this; window; window = window->parent())
1002    window->NotifyWindowHierarchyChangeAtReceiver(params);
1003}
1004
1005void Window::NotifyWindowHierarchyChangeAtReceiver(
1006    const WindowObserver::HierarchyChangeParams& params) {
1007  WindowObserver::HierarchyChangeParams local_params = params;
1008  local_params.receiver = this;
1009
1010  switch (params.phase) {
1011  case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING:
1012    FOR_EACH_OBSERVER(WindowObserver, observers_,
1013                      OnWindowHierarchyChanging(local_params));
1014    break;
1015  case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED:
1016    FOR_EACH_OBSERVER(WindowObserver, observers_,
1017                      OnWindowHierarchyChanged(local_params));
1018    break;
1019  default:
1020    NOTREACHED();
1021    break;
1022  }
1023}
1024
1025void Window::NotifyWindowVisibilityChanged(aura::Window* target,
1026                                           bool visible) {
1027  if (!NotifyWindowVisibilityChangedDown(target, visible)) {
1028    return; // |this| has been deleted.
1029  }
1030  NotifyWindowVisibilityChangedUp(target, visible);
1031}
1032
1033bool Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target,
1034                                                     bool visible) {
1035  // |this| may be deleted during a call to OnWindowVisibilityChanged
1036  // on one of the observers. We create an local observer for that. In
1037  // that case we exit without further access to any members.
1038  WindowDestructionObserver destruction_observer(this);
1039  FOR_EACH_OBSERVER(WindowObserver, observers_,
1040                    OnWindowVisibilityChanged(target, visible));
1041  return !destruction_observer.destroyed();
1042}
1043
1044bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target,
1045                                               bool visible) {
1046  if (!NotifyWindowVisibilityChangedAtReceiver(target, visible))
1047    return false; // |this| was deleted.
1048  std::set<const Window*> child_already_processed;
1049  bool child_destroyed = false;
1050  do {
1051    child_destroyed = false;
1052    for (Window::Windows::const_iterator it = children_.begin();
1053         it != children_.end(); ++it) {
1054      if (!child_already_processed.insert(*it).second)
1055        continue;
1056      if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) {
1057        // |*it| was deleted, |it| is invalid and |children_| has changed.
1058        // We exit the current for-loop and enter a new one.
1059        child_destroyed = true;
1060        break;
1061      }
1062    }
1063  } while (child_destroyed);
1064  return true;
1065}
1066
1067void Window::NotifyWindowVisibilityChangedUp(aura::Window* target,
1068                                             bool visible) {
1069  for (Window* window = this; window; window = window->parent()) {
1070    bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible);
1071    DCHECK(ret);
1072  }
1073}
1074
1075void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds,
1076                                  bool contained_mouse) {
1077  if (layout_manager_)
1078    layout_manager_->OnWindowResized();
1079  if (delegate_)
1080    delegate_->OnBoundsChanged(old_bounds, bounds());
1081  FOR_EACH_OBSERVER(WindowObserver,
1082                    observers_,
1083                    OnWindowBoundsChanged(this, old_bounds, bounds()));
1084  RootWindow* root_window = GetRootWindow();
1085  if (root_window)
1086    root_window->OnWindowBoundsChanged(this, contained_mouse);
1087}
1088
1089void Window::OnPaintLayer(gfx::Canvas* canvas) {
1090  if (delegate_)
1091    delegate_->OnPaint(canvas);
1092}
1093
1094base::Closure Window::PrepareForLayerBoundsChange() {
1095  return base::Bind(&Window::OnLayerBoundsChanged, base::Unretained(this),
1096                    bounds(), ContainsMouse());
1097}
1098
1099bool Window::CanAcceptEvent(const ui::Event& event) {
1100  // The client may forbid certain windows from receiving events at a given
1101  // point in time.
1102  client::EventClient* client = client::GetEventClient(GetRootWindow());
1103  if (client && !client->CanProcessEventsWithinSubtree(this))
1104    return false;
1105
1106  bool visible = event.dispatch_to_hidden_targets() || IsVisible();
1107  return visible && (!parent_ || parent_->CanAcceptEvent(event));
1108}
1109
1110ui::EventTarget* Window::GetParentTarget() {
1111  return parent_;
1112}
1113
1114void Window::UpdateLayerName(const std::string& name) {
1115#if !defined(NDEBUG)
1116  DCHECK(layer());
1117
1118  std::string layer_name(name_);
1119  if (layer_name.empty())
1120    layer_name.append("Unnamed Window");
1121
1122  if (id_ != -1) {
1123    char id_buf[10];
1124    base::snprintf(id_buf, sizeof(id_buf), " %d", id_);
1125    layer_name.append(id_buf);
1126  }
1127  layer()->set_name(layer_name);
1128#endif
1129}
1130
1131bool Window::ContainsMouse() {
1132  bool contains_mouse = false;
1133  if (IsVisible()) {
1134    RootWindow* root_window = GetRootWindow();
1135    contains_mouse = root_window &&
1136        ContainsPointInRoot(root_window->GetLastMouseLocationInRoot());
1137  }
1138  return contains_mouse;
1139}
1140
1141}  // namespace aura
1142