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

Side by Side Diff: mojo/services/window_manager/basic_focus_rules.cc

Issue 747163002: Port more focus controller unit tests and fix our focus rules. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Add the window_manager_unittests suite to the list of unittest binaries to run. Created 6 years 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/services/window_manager/basic_focus_rules.h" 5 #include "mojo/services/window_manager/basic_focus_rules.h"
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "mojo/services/public/cpp/view_manager/view.h" 8 #include "mojo/services/public/cpp/view_manager/view.h"
9 9
10 namespace mojo { 10 namespace mojo {
11 11
12 namespace {
13
14 // TODO(erg): aura::Window::CanFocus() exists. mojo::View::CanFocus() does
15 // not. This is a hack that does everything that Window::CanFocus() currently
16 // does that doesn't require a delegate or an EventClient.
17 bool ViewCanFocus(View* view) {
sky 2014/11/24 21:49:27 This name is awful. CanFocusView is much better, b
18 // TODO(erg): In unit tests, views will never be drawn, so we can't rely on
19 // IsDrawn() here.
20 if (view->GetRoot() == view)
sky 2014/11/24 21:49:27 GetRoot() is not the same as aura::Window::IsRootW
Elliot Glaysher 2014/11/25 00:15:26 Done. To support this, I extracted the actual Vie
21 return view->visible();
22
23 // TODO(erg): Add the intermediary delegate and event client checks once we
sky 2014/11/24 21:49:27 This TODO makes it clearer why you have this struc
24 // have those.
25
26 return ViewCanFocus(view->parent());
27 }
28
29 } // namespace
30
12 BasicFocusRules::BasicFocusRules(mojo::View* window_container) 31 BasicFocusRules::BasicFocusRules(mojo::View* window_container)
13 : window_container_(window_container) { 32 : window_container_(window_container) {
14 } 33 }
15 34
16 BasicFocusRules::~BasicFocusRules() {} 35 BasicFocusRules::~BasicFocusRules() {}
17 36
37 bool BasicFocusRules::SupportsChildActivation(mojo::View* view) const {
38 return true;
39 }
40
18 bool BasicFocusRules::IsToplevelView(mojo::View* view) const { 41 bool BasicFocusRules::IsToplevelView(mojo::View* view) const {
19 return view->parent() == window_container_; 42 if (view->parent() != window_container_)
43 return false;
44
45 // The window must exist within a container that supports activation.
46 // The window cannot be blocked by a modal transient.
47 return SupportsChildActivation(view->parent());
20 } 48 }
21 49
22 bool BasicFocusRules::CanActivateView(mojo::View* view) const { 50 bool BasicFocusRules::CanActivateView(mojo::View* view) const {
23 // TODO(erg): This needs to check visibility, along with focus, and several 51 if (!view)
24 // other things (see wm::BaseFocusRules). 52 return true;
25 return view->parent() == window_container_; 53
54 // Only toplevel windows can be activated
55 if (!IsToplevelView(view))
56 return false;
57
58 // The view must be visible.
59 if (!view->visible())
60 return false;
61
62 // TODO(erg): The aura version of this class asks the aura::Window's
63 // ActivationDelegate whether the window is activatable.
64
65 // A window must be focusable to be activatable. We don't call
66 // CanFocusWindow() from here because it will call back to us via
67 // GetActivatableWindow().
68 if (!ViewCanFocus(view))
69 return false;
70
71 // TODO(erg): In the aura version, we also check whether the window is
72 // blocked by a modal transient window.
73
74 return true;
26 } 75 }
27 76
28 bool BasicFocusRules::CanFocusView(mojo::View* view) const { 77 bool BasicFocusRules::CanFocusView(mojo::View* view) const {
29 return true; 78 // It is possible to focus a NULL window, it is equivalent to clearing focus.
79 if (!view)
80 return true;
81
82 // The focused view is always inside the active view, so views that aren't
83 // activatable can't contain the focused view.
84 View* activatable = GetActivatableView(view);
85 if (!activatable || !activatable->Contains(view))
86 return false;
87 return ViewCanFocus(view);
30 } 88 }
31 89
32 mojo::View* BasicFocusRules::GetToplevelView(mojo::View* view) const { 90 mojo::View* BasicFocusRules::GetToplevelView(mojo::View* view) const {
33 while (view->parent() != window_container_) { 91 View* parent = view->parent();
34 view = view->parent(); 92 View* child = view;
35 // Unparented hierarchy, there is no "top level" window. 93 while (parent) {
36 if (!view) 94 if (IsToplevelView(child))
95 return child;
96
97 parent = parent->parent();
98 child = child->parent();
99 }
100
101 return nullptr;
102 }
103
104 mojo::View* BasicFocusRules::GetActivatableView(mojo::View* view) const {
105 View* parent = view->parent();
106 View* child = view;
107 while (parent) {
108 if (CanActivateView(child))
109 return child;
110
111 // TODO(erg): In the aura version of this class, we have a whole bunch of
112 // checks to support modal transient windows, and transient parents.
113
114 parent = parent->parent();
115 child = child->parent();
116 }
117
118 return nullptr;
119 }
120
121 mojo::View* BasicFocusRules::GetFocusableView(mojo::View* view) const {
122 if (CanFocusView(view))
123 return view;
124
125 // |view| may be in a hierarchy that is non-activatable, in which case we
126 // need to cut over to the activatable hierarchy.
127 View* activatable = GetActivatableView(view);
128 if (!activatable) {
129 // There may not be a related activatable hierarchy to cut over to, in which
130 // case we try an unrelated one.
131 View* toplevel = GetToplevelView(view);
132 if (toplevel)
133 activatable = GetNextActivatableView(toplevel);
134 if (!activatable)
37 return nullptr; 135 return nullptr;
38 } 136 }
39 137
40 return view; 138 if (!activatable->Contains(view)) {
41 } 139 // If there's already a child window focused in the activatable hierarchy,
140 // just use that (i.e. don't shift focus), otherwise we need to at least cut
141 // over to the activatable hierarchy.
142 View* focused = GetFocusableView(activatable);
143 return activatable->Contains(focused) ? focused : activatable;
144 }
42 145
43 mojo::View* BasicFocusRules::GetActivatableView(mojo::View* view) const { 146 while (view && !CanFocusView(view))
44 return GetToplevelView(view); 147 view = view->parent();
45 }
46
47 mojo::View* BasicFocusRules::GetFocusableView(mojo::View* view) const {
48 return view; 148 return view;
49 } 149 }
50 150
51 mojo::View* BasicFocusRules::GetNextActivatableView( 151 mojo::View* BasicFocusRules::GetNextActivatableView(
52 mojo::View* activatable) const { 152 mojo::View* activatable) const {
53 const mojo::View::Children& children = activatable->parent()->children(); 153 DCHECK(activatable);
54 for (mojo::View::Children::const_reverse_iterator it = children.rbegin(); 154
55 it != children.rend(); ++it) { 155 // In the basic scenarios handled by BasicFocusRules, the pool of activatable
56 if (*it != activatable) 156 // windows is limited to the |ignore|'s siblings.
57 return *it; 157 const View::Children& siblings = activatable->parent()->children();
158 DCHECK(!siblings.empty());
159
160 for (auto rit = siblings.rbegin(); rit != siblings.rend(); ++rit) {
161 View* cur = *rit;
162 if (cur == activatable)
163 continue;
164 if (CanActivateView(cur))
165 return cur;
58 } 166 }
59 return nullptr; 167 return nullptr;
60 } 168 }
61 169
62 } // namespace mojo 170 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/window_manager/basic_focus_rules.h ('k') | mojo/services/window_manager/focus_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698