- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / corewm / base_focus_rules.cc
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/base_focus_rules.h"
6
7 #include "ui/aura/client/activation_delegate.h"
8 #include "ui/aura/client/focus_client.h"
9 #include "ui/aura/root_window.h"
10 #include "ui/aura/window.h"
11 #include "ui/views/corewm/window_modality_controller.h"
12
13 namespace views {
14 namespace corewm {
15 namespace {
16
17 aura::Window* GetFocusedWindow(aura::Window* context) {
18   aura::client::FocusClient* focus_client =
19       aura::client::GetFocusClient(context);
20   return focus_client ? focus_client->GetFocusedWindow() : NULL;
21 }
22
23 }  // namespace
24
25 ////////////////////////////////////////////////////////////////////////////////
26 // BaseFocusRules, protected:
27
28 BaseFocusRules::BaseFocusRules() {
29 }
30
31 BaseFocusRules::~BaseFocusRules() {
32 }
33
34 bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
35     aura::Window* window) const {
36   return window->IsVisible();
37 }
38
39 ////////////////////////////////////////////////////////////////////////////////
40 // BaseFocusRules, FocusRules implementation:
41
42 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
43   // The window must in a valid hierarchy.
44   if (!window->GetRootWindow())
45     return false;
46
47   // The window must exist within a container that supports activation.
48   // The window cannot be blocked by a modal transient.
49   return SupportsChildActivation(window->parent());
50 }
51
52 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
53   // It is possible to activate a NULL window, it is equivalent to clearing
54   // activation.
55   if (!window)
56     return true;
57
58   // Only toplevel windows can be activated.
59   if (!IsToplevelWindow(window))
60     return false;
61
62   // The window must be visible.
63   if (!IsWindowConsideredVisibleForActivation(window))
64     return false;
65
66   // The window's activation delegate must allow this window to be activated.
67   if (aura::client::GetActivationDelegate(window) &&
68       !aura::client::GetActivationDelegate(window)->ShouldActivate()) {
69     return false;
70   }
71
72   // A window must be focusable to be activatable. We don't call
73   // CanFocusWindow() from here because it will call back to us via
74   // GetActivatableWindow().
75   if (!window->CanFocus())
76     return false;
77
78   // The window cannot be blocked by a modal transient.
79   return !GetModalTransient(window);
80 }
81
82 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
83   // It is possible to focus a NULL window, it is equivalent to clearing focus.
84   if (!window)
85     return true;
86
87   // The focused window is always inside the active window, so windows that
88   // aren't activatable can't contain the focused window.
89   aura::Window* activatable = GetActivatableWindow(window);
90   if (!activatable || !activatable->Contains(window))
91     return false;
92   return window->CanFocus();
93 }
94
95 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
96   aura::Window* parent = window->parent();
97   aura::Window* child = window;
98   while (parent) {
99     if (IsToplevelWindow(child))
100       return child;
101
102     parent = parent->parent();
103     child = child->parent();
104   }
105   return NULL;
106 }
107
108 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
109   aura::Window* parent = window->parent();
110   aura::Window* child = window;
111   while (parent) {
112     if (CanActivateWindow(child))
113       return child;
114
115     // CanActivateWindow() above will return false if |child| is blocked by a
116     // modal transient. In this case the modal is or contains the activatable
117     // window. We recurse because the modal may itself be blocked by a modal
118     // transient.
119     aura::Window* modal_transient = GetModalTransient(child);
120     if (modal_transient)
121       return GetActivatableWindow(modal_transient);
122
123     if (child->transient_parent()) {
124       // To avoid infinite recursion, if |child| has a transient parent
125       // whose own modal transient is |child| itself, just return |child|.
126       aura::Window* parent_modal_transient =
127           GetModalTransient(child->transient_parent());
128       if (parent_modal_transient == child)
129         return child;
130
131       return GetActivatableWindow(child->transient_parent());
132     }
133
134     parent = parent->parent();
135     child = child->parent();
136   }
137   return NULL;
138 }
139
140 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
141   if (CanFocusWindow(window))
142     return window;
143
144   // |window| may be in a hierarchy that is non-activatable, in which case we
145   // need to cut over to the activatable hierarchy.
146   aura::Window* activatable = GetActivatableWindow(window);
147   if (!activatable) {
148     // There may not be a related activatable hierarchy to cut over to, in which
149     // case we try an unrelated one.
150     aura::Window* toplevel = GetToplevelWindow(window);
151     if (toplevel)
152       activatable = GetNextActivatableWindow(toplevel);
153     if (!activatable)
154       return NULL;
155   }
156
157   if (!activatable->Contains(window)) {
158     // If there's already a child window focused in the activatable hierarchy,
159     // just use that (i.e. don't shift focus), otherwise we need to at least cut
160     // over to the activatable hierarchy.
161     aura::Window* focused = GetFocusedWindow(activatable);
162     return activatable->Contains(focused) ? focused : activatable;
163   }
164
165   while (window && !CanFocusWindow(window))
166     window = window->parent();
167   return window;
168 }
169
170 aura::Window* BaseFocusRules::GetNextActivatableWindow(
171     aura::Window* ignore) const {
172   DCHECK(ignore);
173
174   // Can be called from the RootWindow's destruction, which has a NULL parent.
175   if (!ignore->parent())
176     return NULL;
177
178   // In the basic scenarios handled by BasicFocusRules, the pool of activatable
179   // windows is limited to the |ignore|'s siblings.
180   const aura::Window::Windows& siblings = ignore->parent()->children();
181   DCHECK(!siblings.empty());
182
183   for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
184        rit != siblings.rend();
185        ++rit) {
186     aura::Window* cur = *rit;
187     if (cur == ignore)
188       continue;
189     if (CanActivateWindow(cur))
190       return cur;
191   }
192   return NULL;
193 }
194
195 }  // namespace corewm
196 }  // namespace views