Home | History | Annotate | Download | only in corewm
      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/views/corewm/window_modality_controller.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "ui/aura/client/aura_constants.h"
     10 #include "ui/aura/client/capture_client.h"
     11 #include "ui/aura/env.h"
     12 #include "ui/aura/root_window.h"
     13 #include "ui/aura/window.h"
     14 #include "ui/aura/window_property.h"
     15 #include "ui/base/events/event.h"
     16 #include "ui/base/ui_base_types.h"
     17 #include "ui/views/corewm/window_animations.h"
     18 #include "ui/views/corewm/window_util.h"
     19 
     20 namespace views {
     21 namespace corewm {
     22 
     23 // Transient child's modal parent.
     24 extern const aura::WindowProperty<aura::Window*>* const kModalParentKey;
     25 DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kModalParentKey, NULL);
     26 
     27 namespace {
     28 
     29 bool HasAncestor(aura::Window* window, aura::Window* ancestor) {
     30   if (!window)
     31     return false;
     32   if (window == ancestor)
     33     return true;
     34   return HasAncestor(window->parent(), ancestor);
     35 }
     36 
     37 bool TransientChildIsWindowModal(aura::Window* window) {
     38   return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW;
     39 }
     40 
     41 bool TransientChildIsSystemModal(aura::Window* window) {
     42   return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
     43 }
     44 
     45 bool TransientChildIsChildModal(aura::Window* window) {
     46   return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_CHILD;
     47 }
     48 
     49 aura::Window* GetModalParent(aura::Window* window) {
     50   return window->GetProperty(kModalParentKey);
     51 }
     52 
     53 bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
     54   return transient->IsVisible() &&
     55       (TransientChildIsWindowModal(transient) ||
     56        TransientChildIsSystemModal(transient) ||
     57        (TransientChildIsChildModal(transient) &&
     58         (HasAncestor(original, GetModalParent(transient)))));
     59 }
     60 
     61 aura::Window* GetModalTransientChild(
     62     aura::Window* activatable,
     63     aura::Window* original) {
     64   aura::Window::Windows::const_iterator it;
     65   for (it = activatable->transient_children().begin();
     66        it != activatable->transient_children().end();
     67        ++it) {
     68     aura::Window* transient = *it;
     69     if (IsModalTransientChild(transient, original)) {
     70       return transient->transient_children().empty() ?
     71           transient : GetModalTransientChild(transient, original);
     72     }
     73   }
     74   return NULL;
     75 }
     76 
     77 }  // namespace
     78 
     79 void SetModalParent(aura::Window* child, aura::Window* parent) {
     80   child->SetProperty(kModalParentKey, parent);
     81 }
     82 
     83 aura::Window* GetModalTransient(aura::Window* window) {
     84   if (!window)
     85     return NULL;
     86 
     87   // We always want to check the for the transient child of the toplevel window.
     88   aura::Window* toplevel = GetToplevelWindow(window);
     89   if (!toplevel)
     90     return NULL;
     91 
     92   return GetModalTransientChild(toplevel, window);
     93 }
     94 
     95 ////////////////////////////////////////////////////////////////////////////////
     96 // WindowModalityController, public:
     97 
     98 WindowModalityController::WindowModalityController() {
     99   aura::Env::GetInstance()->AddObserver(this);
    100 }
    101 
    102 WindowModalityController::~WindowModalityController() {
    103   aura::Env::GetInstance()->RemoveObserver(this);
    104   for (size_t i = 0; i < windows_.size(); ++i)
    105     windows_[i]->RemoveObserver(this);
    106 }
    107 
    108 ////////////////////////////////////////////////////////////////////////////////
    109 // WindowModalityController, aura::EventFilter implementation:
    110 
    111 void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
    112   aura::Window* target = static_cast<aura::Window*>(event->target());
    113   if (GetModalTransient(target))
    114     event->StopPropagation();
    115 }
    116 
    117 void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
    118   aura::Window* target = static_cast<aura::Window*>(event->target());
    119   if (ProcessLocatedEvent(target, event))
    120    event->StopPropagation();
    121 }
    122 
    123 void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
    124   aura::Window* target = static_cast<aura::Window*>(event->target());
    125   if (ProcessLocatedEvent(target, event))
    126     event->StopPropagation();
    127 }
    128 
    129 ////////////////////////////////////////////////////////////////////////////////
    130 // WindowModalityController, aura::EnvObserver implementation:
    131 
    132 void WindowModalityController::OnWindowInitialized(aura::Window* window) {
    133   windows_.push_back(window);
    134   window->AddObserver(this);
    135 }
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 // WindowModalityController, aura::WindowObserver implementation:
    139 
    140 void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
    141                                                        const void* key,
    142                                                        intptr_t old) {
    143   // In tests, we sometimes create the modality relationship after a window is
    144   // visible.
    145   if (key == aura::client::kModalKey &&
    146       window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
    147       window->IsVisible()) {
    148     ActivateWindow(window);
    149   }
    150 }
    151 
    152 void WindowModalityController::OnWindowVisibilityChanged(
    153     aura::Window* window,
    154     bool visible) {
    155   if (visible && window->GetProperty(aura::client::kModalKey) ==
    156       ui::MODAL_TYPE_WINDOW) {
    157     // Make sure no other window has capture, otherwise |window| won't get mouse
    158     // events.
    159     aura::Window* capture_window = aura::client::GetCaptureWindow(window);
    160     if (capture_window)
    161       capture_window->ReleaseCapture();
    162   }
    163 }
    164 
    165 void WindowModalityController::OnWindowDestroyed(aura::Window* window) {
    166   windows_.erase(std::find(windows_.begin(), windows_.end(), window));
    167   window->RemoveObserver(this);
    168 }
    169 
    170 bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
    171                                                    ui::LocatedEvent* event) {
    172   aura::Window* modal_transient_child = GetModalTransient(target);
    173   if (modal_transient_child && (event->type() == ui::ET_MOUSE_PRESSED ||
    174                                 event->type() == ui::ET_TOUCH_PRESSED)) {
    175     AnimateWindow(modal_transient_child, WINDOW_ANIMATION_TYPE_BOUNCE);
    176   }
    177   return !!modal_transient_child;
    178 }
    179 
    180 }  // namespace corewm
    181 }  // namespace views
    182