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

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: Created 6 years, 1 month 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) {
18 if (view->GetRoot() == view)
sky 2014/11/21 22:42:19 I don't get this logic. Isn't the same as: return
Elliot Glaysher 2014/11/24 20:29:53 Correct, this is equivalent.
19 return view->visible();
20
21 return ViewCanFocus(view->parent());
22 }
23
24 } // namespace
25
12 BasicFocusRules::BasicFocusRules(mojo::View* window_container) 26 BasicFocusRules::BasicFocusRules(mojo::View* window_container)
13 : window_container_(window_container) { 27 : window_container_(window_container) {
14 } 28 }
15 29
16 BasicFocusRules::~BasicFocusRules() {} 30 BasicFocusRules::~BasicFocusRules() {}
17 31
32 bool BasicFocusRules::SupportsChildActivation(mojo::View* view) const {
33 return true;
34 }
35
18 bool BasicFocusRules::IsToplevelView(mojo::View* view) const { 36 bool BasicFocusRules::IsToplevelView(mojo::View* view) const {
19 return view->parent() == window_container_; 37 // The window must be in a valid hierarchy.
38 if (!view->GetRoot())
sky 2014/11/21 22:42:19 I don't think this is the check you're after. GetR
Elliot Glaysher 2014/11/24 20:29:53 Made the old logic work on unit tests.
39 return false;
40
41 // The window must exist within a container that supports activation.
42 // The window cannot be blocked by a modal transient.
43 return SupportsChildActivation(view->parent());
20 } 44 }
21 45
22 bool BasicFocusRules::CanActivateView(mojo::View* view) const { 46 bool BasicFocusRules::CanActivateView(mojo::View* view) const {
23 // TODO(erg): This needs to check visibility, along with focus, and several 47 if (!view)
24 // other things (see wm::BaseFocusRules). 48 return true;
25 return view->parent() == window_container_; 49
50 // Only toplevel windows can be activated
51 if (!IsToplevelView(view))
52 return false;
53
54 // The view must be visible.
55 if (!view->visible())
56 return false;
57
58 // TODO(erg): The aura version of this class asks the aura::Window's
59 // ActivationDelegate whether the window is activatable.
60
61 // A window must be focusable to be activatable. We don't call
62 // CanFocusWindow() from here because it will call back to us via
63 // GetActivatableWindow().
64 if (!ViewCanFocus(view))
65 return false;
66
67 // TODO(erg): In the aura version, we also check whether the window is
68 // blocked by a modal transient window.
69
70 return true;
26 } 71 }
27 72
28 bool BasicFocusRules::CanFocusView(mojo::View* view) const { 73 bool BasicFocusRules::CanFocusView(mojo::View* view) const {
29 return true; 74 // It is possible to focus a NULL window, it is equivalent to clearing focus.
75 if (!view)
76 return true;
77
78 // The focused view is always inside the active view, so views that aren't
79 // activatable can't contain the focused view.
80 View* activatable = GetActivatableView(view);
81 if (!activatable || !activatable->Contains(view))
82 return false;
83 return ViewCanFocus(view);
30 } 84 }
31 85
32 mojo::View* BasicFocusRules::GetToplevelView(mojo::View* view) const { 86 mojo::View* BasicFocusRules::GetToplevelView(mojo::View* view) const {
33 while (view->parent() != window_container_) { 87 View* parent = view->parent();
34 view = view->parent(); 88 View* child = view;
35 // Unparented hierarchy, there is no "top level" window. 89 while (parent) {
36 if (!view) 90 if (IsToplevelView(child))
91 return child;
92
93 parent = parent->parent();
94 child = child->parent();
95 }
96
97 return nullptr;
98 }
99
100 mojo::View* BasicFocusRules::GetActivatableView(mojo::View* view) const {
101 View* parent = view->parent();
102 View* child = view;
103 while (parent) {
104 if (CanActivateView(child))
105 return child;
106
107 // TODO(erg): In the aura version of this class, we have a whole bunch of
108 // checks to support modal transient windows, and transient parents.
109
110 parent = parent->parent();
111 child = child->parent();
112 }
113
114 return nullptr;
115 }
116
117 mojo::View* BasicFocusRules::GetFocusableView(mojo::View* view) const {
118 if (CanFocusView(view))
119 return view;
120
121 // |view| may be in a hierarchy that is non-activatable, in which case we
122 // need to cut over to the activatable hierarchy.
123 View* activatable = GetActivatableView(view);
124 if (!activatable) {
125 // There may not be a related activatable hierarchy to cut over to, in which
126 // case we try an unrelated one.
127 View* toplevel = GetToplevelView(view);
128 if (toplevel)
129 activatable = GetNextActivatableView(toplevel);
130 if (!activatable)
37 return nullptr; 131 return nullptr;
38 } 132 }
39 133
40 return view; 134 if (!activatable->Contains(view)) {
41 } 135 // If there's already a child window focused in the activatable hierarchy,
136 // just use that (i.e. don't shift focus), otherwise we need to at least cut
137 // over to the activatable hierarchy.
138 View* focused = GetFocusableView(activatable);
139 return activatable->Contains(focused) ? focused : activatable;
140 }
42 141
43 mojo::View* BasicFocusRules::GetActivatableView(mojo::View* view) const { 142 while (view && !CanFocusView(view))
44 return GetToplevelView(view); 143 view = view->parent();
45 }
46
47 mojo::View* BasicFocusRules::GetFocusableView(mojo::View* view) const {
48 return view; 144 return view;
49 } 145 }
50 146
51 mojo::View* BasicFocusRules::GetNextActivatableView( 147 mojo::View* BasicFocusRules::GetNextActivatableView(
52 mojo::View* activatable) const { 148 mojo::View* activatable) const {
53 const mojo::View::Children& children = activatable->parent()->children(); 149 DCHECK(activatable);
54 for (mojo::View::Children::const_reverse_iterator it = children.rbegin(); 150
55 it != children.rend(); ++it) { 151 // In the basic scenarios handled by BasicFocusRules, the pool of activatable
56 if (*it != activatable) 152 // windows is limited to the |ignore|'s siblings.
57 return *it; 153 const View::Children& siblings = activatable->parent()->children();
154 DCHECK(!siblings.empty());
155
156 for (auto rit = siblings.rbegin(); rit != siblings.rend(); ++rit) {
157 View* cur = *rit;
158 if (cur == activatable)
159 continue;
160 if (CanActivateView(cur))
161 return cur;
58 } 162 }
59 return nullptr; 163 return nullptr;
60 } 164 }
61 165
62 } // namespace mojo 166 } // 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