diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-29 23:15:10 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-29 23:15:10 +0000 |
commit | 0aaec000440c2453f20265a7b580efc4ad10b282 (patch) | |
tree | c1739e498cf814750a0c63495a3ebca358117261 /views | |
parent | f5c8a1596de89f2f3010186b03cc2378d23254ae (diff) | |
download | chromium_src-0aaec000440c2453f20265a7b580efc4ad10b282.zip chromium_src-0aaec000440c2453f20265a7b580efc4ad10b282.tar.gz chromium_src-0aaec000440c2453f20265a7b580efc4ad10b282.tar.bz2 |
Relanding the NativeViewHost refactoring (it was breaking the ChromeOS build).
Refactoring some of the NativeViewHost and NativeControl focus management so their consumers don't have to explicitly set the focused view.
See original review:
http://codereview.chromium.org/235011/show
BUG=None
TEST=Run all tests. Make sure focus is stored/restored properly in Chrome.
TBR=ben
Review URL: http://codereview.chromium.org/246032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27563 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/native/native_view_host.cc | 40 | ||||
-rw-r--r-- | views/controls/native/native_view_host.h | 35 | ||||
-rw-r--r-- | views/controls/native/native_view_host_gtk.cc | 27 | ||||
-rw-r--r-- | views/controls/native/native_view_host_gtk.h | 8 | ||||
-rw-r--r-- | views/controls/native/native_view_host_win.cc | 46 | ||||
-rw-r--r-- | views/controls/native/native_view_host_win.h | 18 | ||||
-rw-r--r-- | views/controls/native/native_view_host_wrapper.h | 3 | ||||
-rw-r--r-- | views/controls/native_control.cc | 2 | ||||
-rw-r--r-- | views/controls/native_control_gtk.cc | 20 | ||||
-rw-r--r-- | views/controls/native_control_gtk.h | 4 | ||||
-rw-r--r-- | views/controls/native_control_win.cc | 31 | ||||
-rw-r--r-- | views/focus/focus_manager_unittest.cc | 104 |
12 files changed, 242 insertions, 96 deletions
diff --git a/views/controls/native/native_view_host.cc b/views/controls/native/native_view_host.cc index 9cbeaf7..b5eb509 100644 --- a/views/controls/native/native_view_host.cc +++ b/views/controls/native/native_view_host.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "app/gfx/canvas.h" #include "views/controls/native/native_view_host_wrapper.h" +#include "views/focus/focus_manager.h" #include "views/widget/widget.h" namespace views { @@ -20,7 +21,10 @@ const char NativeViewHost::kViewClassName[] = "views/NativeViewHost"; NativeViewHost::NativeViewHost() : native_view_(NULL), fast_resize_(false), - focus_view_(NULL) { + focus_native_view_(NULL) { + // By default we make this view the one that should be set as the focused view + // when the native view gets the focus. + focus_view_ = this; // The native widget is placed relative to the root. As such, we need to // know when the position of any ancestor changes, or our visibility relative // to other views changed as it'll effect our position relative to the root. @@ -33,10 +37,12 @@ NativeViewHost::~NativeViewHost() { void NativeViewHost::Attach(gfx::NativeView native_view) { DCHECK(!native_view_); native_view_ = native_view; - // If set_focus_view() has not been invoked, this view is the one that should - // be seen as focused when the native view receives focus. - if (!focus_view_) - focus_view_ = this; + // If this NativeViewHost is the focus view, than it should obviously be + // focusable. If it is not, then it acts as a container and we don't want it + // to get focus through tab-traversal, so we make it not focusable. + SetFocusable(focus_view_ == this); + if (!focus_native_view_) + focus_native_view_ = native_view; native_wrapper_->NativeViewAttached(); } @@ -44,6 +50,7 @@ void NativeViewHost::Detach() { DCHECK(native_view_); native_wrapper_->NativeViewDetaching(); native_view_ = NULL; + focus_native_view_ = NULL; } void NativeViewHost::SetPreferredSize(const gfx::Size& size) { @@ -57,6 +64,22 @@ void NativeViewHost::NativeViewDestroyed() { native_view_ = NULL; } +void NativeViewHost::GotNativeFocus() { + // Some NativeViewHost may not have an associated focus view. This is the + // case for containers for example. They might still get the native focus, + // if one non native view they contain gets focused. In that case, we should + // not change the focused view. + if (!focus_view_ || !focus_view_->IsFocusable()) + return; + + FocusManager* focus_manager = GetFocusManager(); + if (!focus_manager) { + NOTREACHED(); + return; + } + focus_manager->SetFocusedView(focus_view_); +} + //////////////////////////////////////////////////////////////////////////////// // NativeViewHost, View overrides: @@ -134,7 +157,12 @@ std::string NativeViewHost::GetClassName() const { } void NativeViewHost::Focus() { - native_wrapper_->SetFocus(); + FocusManager* focus_manager = GetFocusManager(); + if (!focus_manager) { + NOTREACHED(); + return; + } + focus_manager->FocusNativeView(focus_native_view_); } } // namespace views diff --git a/views/controls/native/native_view_host.h b/views/controls/native/native_view_host.h index 679e176..d27a816e 100644 --- a/views/controls/native/native_view_host.h +++ b/views/controls/native/native_view_host.h @@ -42,15 +42,27 @@ class NativeViewHost : public View { // Sets a preferred size for the native view attached to this View. void SetPreferredSize(const gfx::Size& size); - // A NativeViewHost has an associated focus View so that the focus of the - // native control and of the View are kept in sync. In simple cases where the - // NativeViewHost directly wraps a native window as is, the associated view - // is this View. In other cases where the NativeViewHost is part of another - // view (such as TextField), the actual View is not the NativeViewHost and - // this method must be called to set that. - // This method must be called before Attach(). + // A NativeViewHost must keep the focused view in the focus manager and the + // native focus with in sync . There are 2 aspects to this: + // - when the native view receives focus, the focus manager must be notified + // that the associated view is now the focused view. + // In simple cases where the NativeViewHost directly wraps a native window + // as is, the associated view is this NativeViewHost. In other cases where + // the NativeViewHost is part of another view (such as for the TextField + // class), the actual View is not the NativeViewHost and set_focus_view() + // must be called to set the associated view before Attach() is called. + // - when the view is focused (by calling View::RequestFocus()), it must focus + // the appropriate native view. In simple cases where the native view does + // not have children or is the native view that should really get the focus, + // this works without doing anything. In case where the native view that + // should get the focus is not the native view passed to Attach(), then + // the appropriate native view should be specified to + // set_focus_native_view() before Attach() is called. void set_focus_view(View* view) { focus_view_ = view; } - View* focus_view() { return focus_view_; } + void set_focus_native_view(gfx::NativeView native_view) { + focus_native_view_ = native_view; + } + gfx::NativeView focus_native_view() const { return focus_native_view_; } // Fast resizing will move the native view and clip its visible region, this // will result in white areas and will not resize the content (so scrollbars @@ -64,6 +76,10 @@ class NativeViewHost : public View { // Accessor for |native_view_|. gfx::NativeView native_view() const { return native_view_; } + // Called by the NativeViewHostWrapper to notify that the |focus_native_view_| + // got focus. + void GotNativeFocus(); + void NativeViewDestroyed(); // Overridden from View: @@ -96,6 +112,9 @@ class NativeViewHost : public View { // The view that should be given focus when this NativeViewHost is focused. View* focus_view_; + // The native view that should get the focus when this View gets focused. + gfx::NativeView focus_native_view_; + DISALLOW_COPY_AND_ASSIGN(NativeViewHost); }; diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc index 581f08d..ac761b88 100644 --- a/views/controls/native/native_view_host_gtk.cc +++ b/views/controls/native/native_view_host_gtk.cc @@ -48,7 +48,7 @@ void NativeViewHostGtk::NativeViewAttached() { } if (!focus_signal_id_) { - focus_signal_id_ = g_signal_connect(G_OBJECT(host_->native_view()), + focus_signal_id_ = g_signal_connect(G_OBJECT(host_->focus_native_view()), "focus-in-event", G_CALLBACK(CallFocusIn), this); } @@ -70,7 +70,7 @@ void NativeViewHostGtk::NativeViewDetaching() { destroy_signal_id_); destroy_signal_id_ = 0; - g_signal_handler_disconnect(G_OBJECT(host_->native_view()), + g_signal_handler_disconnect(G_OBJECT(host_->focus_native_view()), focus_signal_id_); focus_signal_id_ = 0; @@ -165,11 +165,6 @@ void NativeViewHostGtk::HideWidget() { gtk_widget_hide(fixed_); } -void NativeViewHostGtk::SetFocus() { - DCHECK(host_->native_view()); - gtk_widget_grab_focus(host_->native_view()); -} - //////////////////////////////////////////////////////////////////////////////// // NativeViewHostGtk, private: @@ -216,19 +211,11 @@ void NativeViewHostGtk::CallDestroy(GtkObject* object, } // static -void NativeViewHostGtk::CallFocusIn(GtkWidget* widget, - GdkEventFocus* event, - NativeViewHostGtk* host) { - FocusManager* focus_manager = - FocusManager::GetFocusManagerForNativeView(widget); - if (!focus_manager) { - // TODO(jcampan): http://crbug.com/21378 Reenable this NOTREACHED() when the - // options page is only based on views. - // NOTREACHED(); - NOTIMPLEMENTED(); - return; - } - focus_manager->SetFocusedView(host->host_->focus_view()); +gboolean NativeViewHostGtk::CallFocusIn(GtkWidget* widget, + GdkEventFocus* event, + NativeViewHostGtk* host) { + host->host_->GotNativeFocus(); + return false; } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/native/native_view_host_gtk.h b/views/controls/native/native_view_host_gtk.h index 81a2a7a1..2e58bef 100644 --- a/views/controls/native/native_view_host_gtk.h +++ b/views/controls/native/native_view_host_gtk.h @@ -36,7 +36,6 @@ class NativeViewHostGtk : public NativeViewHostWrapper { virtual void UninstallClip(); virtual void ShowWidget(int x, int y, int w, int h); virtual void HideWidget(); - virtual void SetFocus(); private: // Create and Destroy the GtkFixed that performs clipping on our hosted @@ -55,9 +54,9 @@ class NativeViewHostGtk : public NativeViewHostWrapper { static void CallDestroy(GtkObject* object, NativeViewHostGtk* host); // Invoked from the 'focus-in-event' signal. - static void CallFocusIn(GtkWidget* widget, - GdkEventFocus* event, - NativeViewHostGtk* button); + static gboolean CallFocusIn(GtkWidget* widget, + GdkEventFocus* event, + NativeViewHostGtk* button); // Our associated NativeViewHost. NativeViewHost* host_; @@ -86,4 +85,3 @@ class NativeViewHostGtk : public NativeViewHostWrapper { } // namespace views #endif // VIEWS_CONTROLS_NATIVE_HOST_VIEW_GTK_H_ - diff --git a/views/controls/native/native_view_host_win.cc b/views/controls/native/native_view_host_win.cc index d1a5217..3c05e2a 100644 --- a/views/controls/native/native_view_host_win.cc +++ b/views/controls/native/native_view_host_win.cc @@ -6,10 +6,13 @@ #include "app/gfx/canvas.h" #include "base/logging.h" +#include "base/win_util.h" #include "views/controls/native/native_view_host.h" #include "views/focus/focus_manager.h" #include "views/widget/widget.h" +const wchar_t* kNativeViewHostWinKey = L"__NATIVE_VIEW_HOST_WIN__"; + namespace views { //////////////////////////////////////////////////////////////////////////////// @@ -17,7 +20,8 @@ namespace views { NativeViewHostWin::NativeViewHostWin(NativeViewHost* host) : host_(host), - installed_clip_(false) { + installed_clip_(false), + original_wndproc_(NULL) { } NativeViewHostWin::~NativeViewHostWin() { @@ -37,10 +41,32 @@ void NativeViewHostWin::NativeViewAttached() { // Need to set the HWND's parent before changing its size to avoid flashing. SetParent(host_->native_view(), host_->GetWidget()->GetNativeView()); host_->Layout(); + + // Subclass the appropriate HWND to get focus notifications. + HWND focus_hwnd = host_->focus_native_view(); + DCHECK(focus_hwnd == host_->native_view() || + ::IsChild(host_->native_view(), focus_hwnd)); + original_wndproc_ = + win_util::SetWindowProc(focus_hwnd, + &NativeViewHostWin::NativeViewHostWndProc); + + // We use a property to retrieve the NativeViewHostWin from the window + // procedure. + ::SetProp(focus_hwnd, kNativeViewHostWinKey, this); } void NativeViewHostWin::NativeViewDetaching() { installed_clip_ = false; + + // Restore the original Windows procedure. + DCHECK(original_wndproc_); + WNDPROC wndproc = win_util::SetWindowProc(host_->focus_native_view(), + original_wndproc_); + DCHECK(wndproc == &NativeViewHostWin::NativeViewHostWndProc); + + // Also remove the property, it's not needed anymore. + HANDLE h = ::RemoveProp(host_->focus_native_view(), kNativeViewHostWinKey); + DCHECK(h == this); } void NativeViewHostWin::AddedToWidget() { @@ -116,8 +142,22 @@ void NativeViewHostWin::HideWidget() { SWP_NOREDRAW | SWP_NOOWNERZORDER); } -void NativeViewHostWin::SetFocus() { - ::SetFocus(host_->native_view()); +// static +LRESULT CALLBACK NativeViewHostWin::NativeViewHostWndProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + NativeViewHostWin* native_view_host = + static_cast<NativeViewHostWin*>(::GetProp(window, kNativeViewHostWinKey)); + DCHECK(native_view_host); + + if (message == WM_SETFOCUS) + native_view_host->host_->GotNativeFocus(); + if (message == WM_DESTROY) + native_view_host->host_->Detach(); + + return CallWindowProc(native_view_host->original_wndproc_, + window, message, w_param, l_param); } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/native/native_view_host_win.h b/views/controls/native/native_view_host_win.h index 51bc616..6224693 100644 --- a/views/controls/native/native_view_host_win.h +++ b/views/controls/native/native_view_host_win.h @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef VIEWS_CONTROLS_HWND_VIEW_H_ -#define VIEWS_CONTROLS_HWND_VIEW_H_ +#ifndef VIEWS_CONTROL_NATIVE_NATIVE_VIEW_HOST_WIN_H_ +#define VIEWS_CONTROL_NATIVE_NATIVE_VIEW_HOST_WIN_H_ + +#include "windows.h" #include "base/logging.h" #include "views/controls/native/native_view_host_wrapper.h" @@ -28,9 +30,14 @@ class NativeViewHostWin : public NativeViewHostWrapper { virtual void UninstallClip(); virtual void ShowWidget(int x, int y, int w, int h); virtual void HideWidget(); - virtual void SetFocus(); private: + // Our subclass window procedure. + static LRESULT CALLBACK NativeViewHostWndProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param); + // Our associated NativeViewHost. NativeViewHost* host_; @@ -38,9 +45,12 @@ class NativeViewHostWin : public NativeViewHostWrapper { // visible portion of the gfx::NativeView ? bool installed_clip_; + // The window procedure before we subclassed. + WNDPROC original_wndproc_; + DISALLOW_COPY_AND_ASSIGN(NativeViewHostWin); }; } // namespace views -#endif // VIEWS_CONTROLS_HWND_VIEW_H_ +#endif // VIEWS_CONTROL_NATIVE_NATIVE_VIEW_HOST_WIN_H_ diff --git a/views/controls/native/native_view_host_wrapper.h b/views/controls/native/native_view_host_wrapper.h index 948f0ce..483aff5 100644 --- a/views/controls/native/native_view_host_wrapper.h +++ b/views/controls/native/native_view_host_wrapper.h @@ -51,9 +51,6 @@ class NativeViewHostWrapper { // is already hidden. virtual void HideWidget() = 0; - // Sets focus to the gfx::NativeView. - virtual void SetFocus() = 0; - // Creates a platform-specific instance of an object implementing this // interface. static NativeViewHostWrapper* CreateWrapper(NativeViewHost* host); diff --git a/views/controls/native_control.cc b/views/controls/native_control.cc index 700da66..b23d150 100644 --- a/views/controls/native_control.cc +++ b/views/controls/native_control.cc @@ -287,8 +287,6 @@ HWND NativeControl::GetNativeControlHWND() { } void NativeControl::NativeControlDestroyed() { - if (hwnd_view_) - hwnd_view_->Detach(); container_ = NULL; } diff --git a/views/controls/native_control_gtk.cc b/views/controls/native_control_gtk.cc index 49453ef..4aa6411 100644 --- a/views/controls/native_control_gtk.cc +++ b/views/controls/native_control_gtk.cc @@ -73,26 +73,6 @@ void NativeControlGtk::NativeControlCreated(GtkWidget* native_control) { // Update the newly created GtkWdigetwith any resident enabled state. gtk_widget_set_sensitive(native_view(), IsEnabled()); - - // Listen for focus change event to update the FocusManager focused view. - g_signal_connect(G_OBJECT(native_control), "focus-in-event", - G_CALLBACK(CallFocusIn), this); -} - -// static -void NativeControlGtk::CallFocusIn(GtkWidget* widget, - GdkEventFocus* event, - NativeControlGtk* control) { - FocusManager* focus_manager = - FocusManager::GetFocusManagerForNativeView(widget); - if (!focus_manager) { - // TODO(jcampan): http://crbug.com/21378 Reenable this NOTREACHED() when the - // options page is only based on views. - // NOTREACHED(); - NOTIMPLEMENTED(); - return; - } - focus_manager->SetFocusedView(control->focus_view()); } } // namespace views diff --git a/views/controls/native_control_gtk.h b/views/controls/native_control_gtk.h index ce2f187..69f650d 100644 --- a/views/controls/native_control_gtk.h +++ b/views/controls/native_control_gtk.h @@ -36,10 +36,6 @@ class NativeControlGtk : public NativeViewHost { virtual void NativeControlCreated(GtkWidget* widget); private: - static void CallFocusIn(GtkWidget* widget, - GdkEventFocus* event, - NativeControlGtk* button); - DISALLOW_COPY_AND_ASSIGN(NativeControlGtk); }; diff --git a/views/controls/native_control_win.cc b/views/controls/native_control_win.cc index 9f4d2d6..037066c 100644 --- a/views/controls/native_control_win.cc +++ b/views/controls/native_control_win.cc @@ -24,10 +24,9 @@ NativeControlWin::NativeControlWin() { NativeControlWin::~NativeControlWin() { HWND hwnd = native_view(); if (hwnd) { - // Destroy the hwnd if it still exists. Otherwise we won't have shut things - // down correctly, leading to leaking and crashing if another message - // comes in for the hwnd. - Detach(); + // Destroy the hwnd if it still exists. Otherwise we won't shut things down + // correctly, leading to leaking and crashing if another message comes in + // for the hwnd. DestroyWindow(hwnd); } } @@ -74,9 +73,7 @@ void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) { if (!is_visible) { // We destroy the child control HWND when we become invisible because of the // performance cost of maintaining many HWNDs. - HWND hwnd = native_view(); - Detach(); - DestroyWindow(hwnd); + DestroyWindow(native_view()); } else if (!native_view()) { if (GetWidget()) CreateNativeControl(); @@ -117,14 +114,14 @@ void NativeControlWin::NativeControlCreated(HWND native_control) { // Note that we never unset this property. We don't have to. SetProp(native_control, kNativeControlWinKey, this); - // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages. + Attach(native_control); + // native_view() is now valid. + + // Subclass so we get WM_KEYDOWN message. original_wndproc_ = win_util::SetWindowProc(native_control, &NativeControlWin::NativeControlWndProc); - Attach(native_control); - // native_view() is now valid. - // Update the newly created HWND with any resident enabled state. EnableWindow(native_view(), IsEnabled()); @@ -186,16 +183,10 @@ LRESULT NativeControlWin::NativeControlWndProc(HWND window, if (message == WM_KEYDOWN && native_control->OnKeyDown(static_cast<int>(w_param))) { return 0; - } else if (message == WM_SETFOCUS) { - // Let the focus manager know that the focus changed. - FocusManager* focus_manager = native_control->GetFocusManager(); - if (focus_manager) { - focus_manager->SetFocusedView(native_control->focus_view()); - } else { - NOTREACHED(); - } } else if (message == WM_DESTROY) { - win_util::SetWindowProc(window, native_control->original_wndproc_); + WNDPROC old_wndproc = + win_util::SetWindowProc(window, native_control->original_wndproc_); + DCHECK(old_wndproc == &NativeControlWin::NativeControlWndProc); } return CallWindowProc(native_control->original_wndproc_, window, message, diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc index 29175ec..14a6578 100644 --- a/views/focus/focus_manager_unittest.cc +++ b/views/focus/focus_manager_unittest.cc @@ -165,6 +165,46 @@ class FocusManagerTest : public testing::Test, public WindowDelegate { virtual void InitContentView() { } + gfx::NativeView CreateChildNativeView(gfx::NativeView parent) { +#if defined(OS_WIN) + const wchar_t* kChildClassName = L"FocusTestChildClass"; + WNDCLASS wnd_class = { 0 }; + if (!::GetClassInfo(::GetModuleHandle(NULL), kChildClassName, &wnd_class)) { + // Let's register our dummy class. + wnd_class.lpfnWndProc = ::DefWindowProc; + wnd_class.hInstance = ::GetModuleHandle(NULL); + wnd_class.lpszClassName = kChildClassName; + ATOM atom = RegisterClass(&wnd_class); + } + return ::CreateWindow(kChildClassName, NULL, WS_CHILD, 0, 0, 0, 0, parent, + NULL, NULL, NULL); +#else + GtkWidget* widget = gtk_link_button_new("stupid button"); + if (parent) + gtk_container_add(GTK_CONTAINER(parent), widget); + return widget; +#endif + } + + gfx::NativeView CreateContainerNativeView() { +#if defined(OS_WIN) + const wchar_t* kTopClassName = L"FocusTestTopClass"; + WNDCLASS wnd_class = { 0 }; + if (!::GetClassInfo(::GetModuleHandle(NULL), kTopClassName, &wnd_class)) { + // Let's register our dummy class. + wnd_class.lpfnWndProc = ::DefWindowProc; + wnd_class.hInstance = ::GetModuleHandle(NULL); + wnd_class.lpszClassName = kTopClassName; + ATOM atom = RegisterClass(&wnd_class); + } + // Create a top window HWND + return ::CreateWindow(kTopClassName, NULL, 0, 0, 0, 0, 0, 0, + NULL, NULL, NULL); +#else + return gtk_fixed_new(); +#endif + } + protected: virtual gfx::Rect bounds() { return gfx::Rect(0, 0, 500, 500); @@ -215,7 +255,9 @@ class BorderView : public NativeViewHost { public: explicit BorderView(View* child) : child_(child), widget_(NULL) { DCHECK(child); - SetFocusable(false); + // This is a container and no view should get focused when its associated + // native view gets the focus. + set_focus_view(NULL); } virtual ~BorderView() {} @@ -816,6 +858,66 @@ TEST_F(FocusManagerTest, FocusNativeControls) { } #endif +// A simple view we use to contain a NativeViewHost. +// The only thing it does is not mess with the native focus when focused. +class NoNativeFocusView : public View { + public: + NoNativeFocusView() { + SetFocusable(true); + } + virtual void Focus() { + } +}; + +// Tests that the NativeViewHost class sets the focus View appropriately on the +// FocusManager. +TEST_F(FocusManagerTest, FocusNativeViewHost) { + { + // Test wrapping a simple native view. + gfx::NativeView native_view = + CreateChildNativeView(content_view_->GetWidget()->GetNativeView()); + NativeViewHost* native_view_host = new NativeViewHost(); + content_view_->AddChildView(native_view_host); + native_view_host->Attach(native_view); + FocusNativeView(native_view); + EXPECT_EQ(native_view_host, GetFocusManager()->GetFocusedView()); + GetFocusManager()->ClearFocus(); + } + + { + // Test with nested native views, making sure set_focus_native_view() works. + gfx::NativeView top_native_view = CreateContainerNativeView(); + gfx::NativeView child_native_view = CreateChildNativeView(top_native_view); + NativeViewHost* native_view_host = new NativeViewHost(); + native_view_host->set_focus_native_view(child_native_view); + content_view_->AddChildView(native_view_host); + native_view_host->Attach(top_native_view); + + // Focus the top native view, that shouldn't change the focus. + // (Note this isn't a case that we expect to happen.) + FocusNativeView(top_native_view); + EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); + // Focus the inner HWND, the focused view should change. + FocusNativeView(child_native_view); + EXPECT_EQ(native_view_host, GetFocusManager()->GetFocusedView()); + GetFocusManager()->ClearFocus(); + } + + { + // Now also make sure set_focused_view() works. + gfx::NativeView native_view = + CreateChildNativeView(content_view_->GetWidget()->GetNativeView()); + NativeViewHost* native_view_host = new NativeViewHost(); + NoNativeFocusView* container_view = new NoNativeFocusView(); + container_view->AddChildView(native_view_host); + content_view_->AddChildView(container_view); + native_view_host->set_focus_view(container_view); + native_view_host->Attach(native_view); + FocusNativeView(native_view); + EXPECT_EQ(container_view, GetFocusManager()->GetFocusedView()); + } +} + // Test that when activating/deactivating the top window, the focus is stored/ // restored properly. TEST_F(FocusManagerTest, FocusStoreRestore) { |