summaryrefslogtreecommitdiffstats
path: root/chrome/views/focus_manager.h
blob: 4b994209bafbecfbfd664fa5e347d6862b2cebfe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef CHROME_VIEWS_FOCUS_MANAGER_H__
#define CHROME_VIEWS_FOCUS_MANAGER_H__

#include <windows.h>
#include <vector>
#include <map>

#include "base/basictypes.h"
#include "chrome/common/notification_service.h"
#include "chrome/views/accelerator.h"

// The FocusManager class is used to handle focus traversal, store/restore
// focused views and handle keyboard accelerators.
//
// There are 2 types of focus:
// - the native focus, which is the focus that an HWND has.
// - the view focus, which is the focus that a ChromeViews::View has.
//
// Each native view must register with their Focus Manager so the focus manager
// gets notified when they are focused (and keeps track of the native focus) and
// as well so that the tab key events can be intercepted.
// They can provide when they register a View that is kept in synch in term of
// focus. This is used in NativeControl for example, where a View wraps an
// actual native window.
// This is already done for you if you subclass the NativeControl class or if
// you use the HWNDView class.
//
// When creating a top window, if it derives from HWNDViewContainer, the
// |has_own_focus_manager| of the Init method lets you specify whether that
// window should have its own focus manager (so focus traversal stays confined
// in that window). If you are not deriving from HWNDViewContainer or one of its
// derived classes (Window, FramelessWindow, ConstrainedWindow), you must
// create a FocusManager when the window is created (it is automatically deleted
// when the window is destroyed).
//
// The FocusTraversable interface exposes the methods a class should implement
// in order to be able to be focus traversed when tab key is pressed.
// RootViews implement FocusTraversable.
// The FocusManager contains a top FocusTraversable instance, which is the top
// RootView.
//
// If you just use views, then the focus traversal is handled for you by the
// RootView. The default traversal order is the order in which the views have
// been added to their container. You can modify this order by using the View
// method SetNextFocusableView().
//
// If you are embedding a native view containing a nested RootView (for example
// by adding a NativeControl that contains a HWNDViewContainer as its native
// component), then you need to:
// - override the View::GetFocusTraversable() method in your outter component.
//   It should return the RootView of the inner component. This is used when
//   the focus traversal traverse down the focus hierarchy to enter the nested
//   RootView. In the example mentioned above, the NativeControl overrides
//   GetFocusTraversable() and returns hwnd_view_container_->GetRootView().
// - call RootView::SetFocusTraversableParent() on the nested RootView and point
//   it to the outter RootView. This is used when the focus goes out of the
//   nested RootView. In the example:
//   hwnd_view_container_->GetRootView()->SetFocusTraversableParent(
//      native_control->GetRootView());
// - call RootView::SetFocusTraversableParentView() on the nested RootView with
//   the parent view that directly contains the native window. This is needed
//   when traversing up from the nested RootView to know which view to start
//   with when going to the next/previous view.
//   In our example:
//   hwnd_view_container_->GetRootView()->SetFocusTraversableParent(
//      native_control);
//
// Note that FocusTraversable do not have to be RootViews: TabContents is
// FocusTraversable.

namespace ChromeViews {

class View;
class RootView;

// The FocusTraversable interface is used by components that want to process
// focus traversal events (due to Tab/Shift-Tab key events).
class FocusTraversable {
 public:
  // The direction in which the focus traversal is going.
  // TODO (jcampan): add support for lateral (left, right) focus traversal. The
  // goal is to switch to focusable views on the same level when using the arrow
  // keys (ala Windows: in a dialog box, arrow keys typically move between the
  // dialog OK, Cancel buttons).
  enum Direction {
    UP = 0,
    DOWN
  };

  // Should find the next view that should be focused and return it. If a
  // FocusTraversable is found while searching for the focusable view, NULL
  // should be returned, focus_traversable should be set to the FocusTraversable
  // and focus_traversable_view should be set to the view associated with the
  // FocusTraversable.
  // This call should return NULL if the end of the focus loop is reached.
  // - |starting_view| is the view that should be used as the starting point
  //   when looking for the previous/next view. It may be NULL (in which case
  //   the first/last view should be used depending if normal/reverse).
  // - |reverse| whether we should find the next (reverse is false) or the
  //   previous (reverse is true) view.
  // - |direction| specifies whether we are traversing down (meaning we should
  //   look into child views) or traversing up (don't look at child views).
  // - |dont_loop| if true specifies that if there is a loop in the focus
  //   hierarchy, we should keep traversing after the last view of the loop.
  // - |focus_traversable| is set to the focus traversable that should be
  //   traversed if one is found (in which case the call returns NULL).
  // - |focus_traversable_view| is set to the view associated with the
  //   FocusTraversable set in the previous parameter (it is used as the
  //   starting view when looking for the next focusable view).

  virtual View* FindNextFocusableView(View* starting_view,
                                      bool reverse,
                                      Direction direction,
                                      bool dont_loop,
                                      FocusTraversable** focus_traversable,
                                      View** focus_traversable_view) = 0;

  // Should return the parent FocusTraversable.
  // The top RootView which is the top FocusTraversable returns NULL.
  virtual FocusTraversable* GetFocusTraversableParent() = 0;

  // This should return the View this FocusTraversable belongs to.
  // It is used when walking up the view hierarchy tree to find which view
  // should be used as the starting view for finding the next/previous view.
  virtual View* GetFocusTraversableParentView() = 0;
};

// The KeystrokeListener interface is used by components (such as the
// ExternalTabContainer class) which need a crack at handling all
// keystrokes.
class KeystrokeListener {
 public:
  // If this returns true, then the component handled the keystroke and ate
  // it.
  virtual bool ProcessKeyDown(HWND window, UINT message, WPARAM wparam,
                              LPARAM lparam) = 0;
};

// This interface should be implemented by classes that want to be notified when
// the focus is about to change.  See the Add/RemoveFocusChangeListener methods.
class FocusChangeListener {
 public:
  virtual void FocusWillChange(View* focused_before, View* focused_now) = 0;
};

class FocusManager : public NotificationObserver {
 public:
  // Creates a FocusManager for the specified window. Top level windows
  // must invoked this when created.
  // The RootView specified should be the top RootView of the window.
  // This also invokes InstallFocusSubclass.
  static FocusManager* CreateFocusManager(HWND window, RootView* root_view);

  // Subclasses the specified window. The subclassed window procedure listens
  // for WM_SETFOCUS notification and keeps the FocusManager's focus owner
  // property in sync.
  // It's not necessary to explicitly invoke Uninstall, it's automatically done
  // when the window is destroyed and Uninstall wasn't invoked.
  static void InstallFocusSubclass(HWND window, View* view);

  // Uninstalls the window subclass installed by InstallFocusSubclass.
  static void UninstallFocusSubclass(HWND window);

  static FocusManager* GetFocusManager(HWND window);


  // Message handlers (for messages received from registered windows).
  // Should return true if the message should be forwarded to the window
  // original proc function, false otherwise.
  bool OnSetFocus(HWND window);
  bool OnNCDestroy(HWND window);
  // OnKeyDown covers WM_KEYDOWN and WM_SYSKEYDOWN.
  bool OnKeyDown(HWND window,
                 UINT message,
                 WPARAM wparam,
                 LPARAM lparam);
  // OnPostActivate is called after WM_ACTIVATE has been propagated to the
  // DefWindowProc.
  bool OnPostActivate(HWND window, int activation_state, int minimized_state);

  // Returns true is the specified is part of the hierarchy of the window
  // associated with this FocusManager.
  bool ContainsView(View* view);

  // Advances the focus (backward if reverse is true).
  void AdvanceFocus(bool reverse);

  // The FocusManager is handling the selected view for the RootView.
  View* GetFocusedView() const { return focused_view_; }
  void SetFocusedView(View* view);

  // Clears the focused view. The window associated with the top root view gets
  // the native focus (so we still get keyboard events).
  void ClearFocus();

  // Clears the HWND that has the focus by focusing the HWND from the top
  // RootView (so we still get keyboard events).
  // Note that this does not change the currently focused view.
  void ClearHWNDFocus();

  // Focus the specified |hwnd| without changing the focused view.
  void FocusHWND(HWND hwnd);

  // Validates the focused view, clearing it if the window it belongs too is not
  // attached to the window hierarchy anymore.
  void ValidateFocusedView();

  // Returns the view associated with the specified window if any.
  // If |look_in_parents| is true, it goes up the window parents until it find
  // a view.
  static View* GetViewForWindow(HWND window, bool look_in_parents);

  // Stores and restores the focused view. Used when the window becomes
  // active/inactive.
  void StoreFocusedView();
  void RestoreFocusedView();

  // Clears the stored focused view.
  void ClearStoredFocusedView();

  // Returns the FocusManager of the parent window of the window that is the
  // root of this FocusManager. This is useful with ConstrainedWindows that have
  // their own FocusManager and need to return focus to the browser when closed.
  FocusManager* GetParentFocusManager() const;

  // Register a keyboard accelerator for the specified target.  If an
  // AcceleratorTarget is already registered for that accelerator, it is
  // returned.
  // Note that we are currently limited to accelerators that are either:
  // - a key combination including Ctrl or Alt
  // - the escape key
  // - the enter key
  // - any F key (F1, F2, F3 ...)
  // - any browser specific keys (as available on special keyboards)
  AcceleratorTarget* RegisterAccelerator(const Accelerator& accelerator,
                                         AcceleratorTarget* target);

  // Unregister all keyboard accelerator for the specified target.
  void UnregisterAccelerators(AcceleratorTarget* target);

  // Activate the target associated with the specified accelerator if any.
  // If |prioritary_accelerators_only| is true, only the following accelerators
  // are allowed:
  // - a key combination including Ctrl or Alt
  // - the escape key
  // - the enter key
  // - any F key (F1, F2, F3 ...)
  // - any browser specific keys (as available on special keyboards)
  // Returns true if an accelerator was activated.
  bool ProcessAccelerator(const Accelerator& accelerator,
                          bool prioritary_accelerators_only);

  // NotificationObserver method.
  void Observe(NotificationType type,
               const NotificationSource& source,
               const NotificationDetails& details);

  void AddKeystrokeListener(KeystrokeListener* listener);
  void RemoveKeystrokeListener(KeystrokeListener* listener);

  // Adds/removes a listener.  The FocusChangeListener is notified every time
  // the focused view is about to change.
  void AddFocusChangeListener(FocusChangeListener* listener);
  void RemoveFocusChangeListener(FocusChangeListener* listener);

  // Returns the AcceleratorTarget that should be activated for the specified
  // keyboard accelerator, or NULL if no view is registered for that keyboard
  // accelerator.
  // TODO(finnur): http://b/1307173 Make this private once the bug is fixed.
  AcceleratorTarget* GetTargetForAccelerator(
      const Accelerator& accelerator) const;

 private:
  explicit FocusManager(HWND root, RootView* root_view);
  ~FocusManager();

  // Returns the next focusable view.
  View* GetNextFocusableView(View* starting_view, bool reverse, bool dont_loop);

  // Returns the last view of the focus traversal hierarchy.
  View* FindLastFocusableView();

  // Returns the focusable view found in the FocusTraversable specified starting
  // at the specified view. This traverses down along the FocusTraversable
  // hierarchy.
  // Returns NULL if no focusable view were found.
  View* FindFocusableView(FocusTraversable* focus_traversable,
                          View* starting_view,
                          bool reverse,
                          bool dont_loop);

  // The RootView of the window associated with this FocusManager.
  RootView* top_root_view_;

  // The view that currently is focused.
  View* focused_view_;

  // The storage id used in the ViewStorage to store/restore the view that last
  // had focus.
  int stored_focused_view_storage_id_;

  // The window associated with this focus manager.
  HWND root_;

  // Used to allow setting the focus on an HWND without changing the currently
  // focused view.
  bool ignore_set_focus_msg_;

  // The accelerators and associated targets.
  typedef std::map<Accelerator, AcceleratorTarget*> AcceleratorMap;
  AcceleratorMap accelerators_;

  // The list of registered keystroke listeners
  typedef std::vector<KeystrokeListener*> KeystrokeListenerList;
  KeystrokeListenerList keystroke_listeners_;

  // The list of registered FocusChange listeners.
  typedef std::vector<FocusChangeListener*> FocusChangeListenerList;
  FocusChangeListenerList focus_change_listeners_;

  DISALLOW_EVIL_CONSTRUCTORS(FocusManager);
};

}

#endif  // CHROME_VIEWS_FOCUS_MANAGER_H__