Commit 49d02cd2 authored by msw@chromium.org's avatar msw@chromium.org

Re-land: Store and restore view focus in OnWindowFocused.

r271281 reverted the first r271249 for Win XP test failures:

http://build.chromium.org/p/chromium.win/builders/XP%20Tests%20%281%29/builds/31239/steps/interactive_ui_tests/logs/stdio
[ RUN      ] ConstrainedWindowViewTest.ClosesOnEscape
[216:3316:0517/130516:ERROR:gpu_info_collector_win.cc(103)] Can't retrieve a valid WinSAT assessment.
c:\b\build\slave\cr-win-rel\build\src\chrome\browser\ui\views\constrained_window_views_browsertest.cc(206): error: Value of: dialog->GetWidget()
  Actual: 08C1F9C0
Expected: 0
Which is: NULL

This CL makes that test no-op on XP; I'll follow up in Issue 177482.

------------------------------------------------------------
Mimic [Desktop]NativeWidgetAura::OnWindowActivated.
Simplify OnNativeBlur calls and OnNative[Blur|Focus] impls.
(View focus changes update the TextInputClient as needed)
Rewrite and enable related ConstrainedWindowViewTests.

Print GetLastError() in SendInput() error case for tests.
(key presses get 5/ERROR_ACCESS_DENIED on locked desktops?)

BUG=368691, 170331, 177482, 163931
TEST=Automated tests; the focused Views change as expected between the browser, web contents, and web content modal dialogs (print preview, collected cookies, etc.).
TBR=sky@chromium.org

Review URL: https://codereview.chromium.org/285403003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271312 0039d316-1c4b-4281-b951-d872f2087c98
parent f4a752ee
...@@ -2,105 +2,39 @@ ...@@ -2,105 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/memory/weak_ptr.h" #include "base/memory/scoped_ptr.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/constrained_window_views.h" #include "chrome/browser/ui/views/tab_modal_confirm_dialog_views.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_host.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "ipc/ipc_message.h" #include "content/public/test/browser_test_utils.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_manager.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/widget/widget.h"
#include "ui/views/test/test_widget_observer.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/web_dialogs/test/test_web_dialog_delegate.h"
#if defined(USE_AURA) && defined(USE_X11)
#include <X11/Xlib.h>
#include "ui/events/test/events_test_utils_x11.h"
#endif
using web_modal::WebContentsModalDialogManager; #if defined(OS_WIN)
using web_modal::WebContentsModalDialogManagerDelegate; #include "base/win/windows_version.h"
#endif
namespace { namespace {
class TestConstrainedDialogContentsView class TestDialog : public views::DialogDelegateView {
: public views::View,
public base::SupportsWeakPtr<TestConstrainedDialogContentsView> {
public:
TestConstrainedDialogContentsView()
: text_field_(new views::Textfield) {
SetLayoutManager(new views::FillLayout);
AddChildView(text_field_);
}
views::View* GetInitiallyFocusedView() {
return text_field_;
}
private:
views::Textfield* text_field_;
DISALLOW_COPY_AND_ASSIGN(TestConstrainedDialogContentsView);
};
class TestConstrainedDialog : public views::DialogDelegate {
public: public:
TestConstrainedDialog() TestDialog() { SetFocusable(true); }
: contents_((new TestConstrainedDialogContentsView())->AsWeakPtr()), virtual ~TestDialog() {}
done_(false) {
}
virtual ~TestConstrainedDialog() {}
virtual views::View* GetInitiallyFocusedView() OVERRIDE {
return contents_ ? contents_->GetInitiallyFocusedView() : NULL;
}
virtual views::View* GetContentsView() OVERRIDE {
return contents_.get();
}
virtual views::Widget* GetWidget() OVERRIDE {
return contents_ ? contents_->GetWidget() : NULL;
}
virtual const views::Widget* GetWidget() const OVERRIDE {
return contents_ ? contents_->GetWidget() : NULL;
}
virtual void DeleteDelegate() OVERRIDE {
// Don't delete the delegate yet. We need to keep it around for inspection
// later.
EXPECT_TRUE(done_);
}
virtual bool Accept() OVERRIDE {
done_ = true;
return true;
}
virtual bool Cancel() OVERRIDE { virtual views::View* GetInitiallyFocusedView() OVERRIDE { return this; }
done_ = true; // Don't delete the delegate yet. Keep it around for inspection later.
return true; virtual void DeleteDelegate() OVERRIDE {}
}
virtual ui::ModalType GetModalType() const OVERRIDE { virtual ui::ModalType GetModalType() const OVERRIDE {
#if defined(USE_ASH) #if defined(USE_ASH)
...@@ -110,363 +44,174 @@ class TestConstrainedDialog : public views::DialogDelegate { ...@@ -110,363 +44,174 @@ class TestConstrainedDialog : public views::DialogDelegate {
#endif #endif
} }
bool done() {
return done_;
}
private: private:
// contents_ will be freed when the View goes away. DISALLOW_COPY_AND_ASSIGN(TestDialog);
base::WeakPtr<TestConstrainedDialogContentsView> contents_;
bool done_;
DISALLOW_COPY_AND_ASSIGN(TestConstrainedDialog);
}; };
} // namespace // A helper function to create and show a web contents modal dialog.
scoped_ptr<TestDialog> ShowModalDialog(content::WebContents* web_contents) {
scoped_ptr<TestDialog> dialog(new TestDialog());
views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
dialog.get(), web_contents->GetNativeView());
web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->
ShowModalDialog(window->GetNativeView());
return dialog.Pass();
}
class ConstrainedWindowViewTest : public InProcessBrowserTest { } // namespace
public:
ConstrainedWindowViewTest() {
}
};
#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) typedef InProcessBrowserTest ConstrainedWindowViewTest;
// TODO(erg): linux_aura bringup: http://crbug.com/163931
#define MAYBE_FocusTest DISABLED_FocusTest
#else
#define MAYBE_FocusTest FocusTest
#endif
// Tests the following: // Tests the intial focus of tab-modal dialogs, the restoration of focus to the
// // browser when they close, and that queued dialogs don't register themselves as
// *) Initially focused view in a constrained dialog receives focus reliably. // accelerator targets until they are displayed.
// IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) {
// *) Constrained windows that are queued don't register themselves as
// accelerator targets until they are displayed.
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_FocusTest) {
content::WebContents* web_contents = content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents != NULL); EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
WebContentsModalDialogManager* web_contents_modal_dialog_manager = scoped_ptr<TestDialog> dialog1 = ShowModalDialog(web_contents);
WebContentsModalDialogManager::FromWebContents(web_contents);
ASSERT_TRUE(web_contents_modal_dialog_manager != NULL); // |dialog1| should be active and focused.
WebContentsModalDialogManagerDelegate* modal_delegate = EXPECT_TRUE(dialog1->GetWidget()->IsVisible());
web_contents_modal_dialog_manager->delegate(); views::FocusManager* focus_manager = dialog1->GetWidget()->GetFocusManager();
ASSERT_TRUE(modal_delegate != NULL); EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView());
// Create a constrained dialog. It will attach itself to web_contents. // Create a second dialog. This will also be modal to |web_contents|, but will
scoped_ptr<TestConstrainedDialog> test_dialog1(new TestConstrainedDialog); // remain hidden since the |dialog1| is still showing.
views::Widget* window1 = views::Widget::CreateWindowAsFramelessChild( scoped_ptr<TestDialog> dialog2 = ShowModalDialog(web_contents);
test_dialog1.get(), EXPECT_FALSE(dialog2->GetWidget()->IsVisible());
modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); EXPECT_TRUE(dialog1->GetWidget()->IsVisible());
web_contents_modal_dialog_manager->ShowModalDialog(window1->GetNativeView()); EXPECT_EQ(focus_manager, dialog2->GetWidget()->GetFocusManager());
EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
views::FocusManager* focus_manager = window1->GetFocusManager(); EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView());
ASSERT_TRUE(focus_manager);
// Pressing return should close |dialog1|.
// test_dialog1's text field should be focused.
EXPECT_EQ(test_dialog1->GetInitiallyFocusedView(),
focus_manager->GetFocusedView());
// Now create a second constrained dialog. This will also be attached to
// web_contents, but will remain hidden since the test_dialog1 is still
// showing.
scoped_ptr<TestConstrainedDialog> test_dialog2(new TestConstrainedDialog);
views::Widget* window2 = views::Widget::CreateWindowAsFramelessChild(
test_dialog2.get(),
modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
web_contents_modal_dialog_manager->ShowModalDialog(window2->GetNativeView());
// Should be the same focus_manager.
ASSERT_EQ(focus_manager, window2->GetFocusManager());
// test_dialog1's text field should still be the view that has focus.
EXPECT_EQ(test_dialog1->GetInitiallyFocusedView(),
focus_manager->GetFocusedView());
ASSERT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
// Now send a VKEY_RETURN to the browser. This should result in closing
// test_dialog1.
EXPECT_TRUE(focus_manager->ProcessAccelerator( EXPECT_TRUE(focus_manager->ProcessAccelerator(
ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE))); ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_EQ(NULL, dialog1->GetWidget());
EXPECT_TRUE(test_dialog1->done()); // |dialog2| should be visible and focused.
EXPECT_FALSE(test_dialog2->done()); EXPECT_TRUE(dialog2->GetWidget()->IsVisible());
EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive()); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView());
// test_dialog2 will be shown. Focus should be on test_dialog2's text field.
EXPECT_EQ(test_dialog2->GetInitiallyFocusedView(),
focus_manager->GetFocusedView());
int tab_with_constrained_window = // Creating a new tab should take focus away from the other tab's dialog.
browser()->tab_strip_model()->active_index(); const int tab_with_dialog = browser()->tab_strip_model()->active_index();
// Create a new tab.
chrome::NewTab(browser()); chrome::NewTab(browser());
EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
EXPECT_NE(dialog2->GetContentsView(), focus_manager->GetFocusedView());
// The constrained dialog should no longer be selected. // Activating the previous tab should bring focus to the dialog.
EXPECT_NE(test_dialog2->GetInitiallyFocusedView(), browser()->tab_strip_model()->ActivateTabAt(tab_with_dialog, false);
focus_manager->GetFocusedView()); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView());
browser()->tab_strip_model()->ActivateTabAt(tab_with_constrained_window,
false);
// Activating the previous tab should bring focus to the constrained window.
EXPECT_EQ(test_dialog2->GetInitiallyFocusedView(),
focus_manager->GetFocusedView());
// Send another VKEY_RETURN, closing test_dialog2 // Pressing enter again should close |dialog2|.
EXPECT_TRUE(focus_manager->ProcessAccelerator( EXPECT_TRUE(focus_manager->ProcessAccelerator(
ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE))); ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_TRUE(test_dialog2->done()); EXPECT_EQ(NULL, dialog2->GetWidget());
EXPECT_FALSE(web_contents_modal_dialog_manager->IsDialogActive()); EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
} }
#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) // Tests that the tab-modal window is closed properly when its tab is closed.
// TODO(erg): linux_aura bringup: http://crbug.com/163931 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabCloseTest) {
#define MAYBE_TabCloseTest DISABLED_TabCloseTest scoped_ptr<TestDialog> dialog = ShowModalDialog(
#else browser()->tab_strip_model()->GetActiveWebContents());
#define MAYBE_TabCloseTest TabCloseTest EXPECT_TRUE(dialog->GetWidget()->IsVisible());
#endif chrome::CloseTab(browser());
// Tests that the constrained window is closed properly when its tab is
// closed.
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabCloseTest) {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents != NULL);
WebContentsModalDialogManager* web_contents_modal_dialog_manager =
WebContentsModalDialogManager::FromWebContents(web_contents);
ASSERT_TRUE(web_contents_modal_dialog_manager != NULL);
WebContentsModalDialogManagerDelegate* modal_delegate =
web_contents_modal_dialog_manager->delegate();
ASSERT_TRUE(modal_delegate != NULL);
// Create a constrained dialog. It will attach itself to web_contents.
scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
test_dialog.get(),
modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
bool closed =
browser()->tab_strip_model()->CloseWebContentsAt(
browser()->tab_strip_model()->active_index(),
TabStripModel::CLOSE_NONE);
EXPECT_TRUE(closed);
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_TRUE(test_dialog->done()); EXPECT_EQ(NULL, dialog->GetWidget());
} }
#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) // Tests that the tab-modal window is hidden when an other tab is selected and
// TODO(erg): linux_aura bringup: http://crbug.com/163931
#define MAYBE_TabSwitchTest DISABLED_TabSwitchTest
#else
#define MAYBE_TabSwitchTest TabSwitchTest
#endif
// Tests that the constrained window is hidden when an other tab is selected and
// shown when its tab is selected again. // shown when its tab is selected again.
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabSwitchTest) { IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabSwitchTest) {
content::WebContents* web_contents = scoped_ptr<TestDialog> dialog = ShowModalDialog(
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents());
ASSERT_TRUE(web_contents != NULL); EXPECT_TRUE(dialog->GetWidget()->IsVisible());
// Create a constrained dialog. It will attach itself to web_contents. // Open a new tab. The tab-modal window should hide itself.
scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog); chrome::NewTab(browser());
WebContentsModalDialogManager* web_contents_modal_dialog_manager = EXPECT_FALSE(dialog->GetWidget()->IsVisible());
WebContentsModalDialogManager::FromWebContents(web_contents);
WebContentsModalDialogManagerDelegate* modal_delegate = // Close the new tab. The tab-modal window should show itself again.
web_contents_modal_dialog_manager->delegate(); chrome::CloseTab(browser());
ASSERT_TRUE(modal_delegate != NULL); EXPECT_TRUE(dialog->GetWidget()->IsVisible());
views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
test_dialog.get(),
modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
EXPECT_TRUE(window->IsVisible());
// Open a new tab. The constrained window should hide itself.
browser()->tab_strip_model()->AppendWebContents(
content::WebContents::Create(
content::WebContents::CreateParams(browser()->profile())),
true);
EXPECT_FALSE(window->IsVisible());
// Close the new tab. The constrained window should show itself again.
bool closed =
browser()->tab_strip_model()->CloseWebContentsAt(
browser()->tab_strip_model()->active_index(),
TabStripModel::CLOSE_NONE);
EXPECT_TRUE(closed);
EXPECT_TRUE(window->IsVisible());
// Close the original tab. // Close the original tab.
browser()->tab_strip_model()->CloseWebContentsAt( chrome::CloseTab(browser());
browser()->tab_strip_model()->active_index(),
TabStripModel::CLOSE_NONE);
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_TRUE(test_dialog->done()); EXPECT_EQ(NULL, dialog->GetWidget());
} }
// Tests that the constrained window behaves properly when moving its tab // Tests that tab-modal dialogs follow tabs dragged between browser windows.
// between browser windows.
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabMoveTest) { IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabMoveTest) {
// Open a second browser. content::WebContents* web_contents =
Browser* browser2 = CreateBrowser(browser()->profile()); browser()->tab_strip_model()->GetActiveWebContents();
scoped_ptr<TestDialog> dialog = ShowModalDialog(web_contents);
EXPECT_TRUE(dialog->GetWidget()->IsVisible());
// Create a second WebContents in the second browser, so that moving the // Move the tab to a second browser window; but first create another tab.
// WebContents does not trigger the browser to close immediately. This mimics // That prevents the first browser window from closing when its tab is moved.
// the behavior when a user drags tabs between browsers. chrome::NewTab(browser());
content::WebContents* web_contents = content::WebContents::Create( browser()->tab_strip_model()->DetachWebContentsAt(
content::WebContents::CreateParams(browser()->profile())); browser()->tab_strip_model()->GetIndexOfWebContents(web_contents));
Browser* browser2 = CreateBrowser(browser()->profile());
browser2->tab_strip_model()->AppendWebContents(web_contents, true); browser2->tab_strip_model()->AppendWebContents(web_contents, true);
ASSERT_EQ(web_contents, browser2->tab_strip_model()->GetActiveWebContents()); EXPECT_TRUE(dialog->GetWidget()->IsVisible());
// Create a constrained dialog. It will attach itself to web_contents.
scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
WebContentsModalDialogManager* web_contents_modal_dialog_manager =
WebContentsModalDialogManager::FromWebContents(web_contents);
WebContentsModalDialogManagerDelegate* modal_delegate =
web_contents_modal_dialog_manager->delegate();
ASSERT_TRUE(modal_delegate != NULL);
views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
test_dialog.get(),
modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
EXPECT_TRUE(window->IsVisible());
// Detach the web contents from the second browser's tab strip.
browser2->tab_strip_model()->DetachWebContentsAt(
browser2->tab_strip_model()->GetIndexOfWebContents(web_contents));
// Append the web contents to the first browser. // Close the first browser.
browser()->tab_strip_model()->AppendWebContents(web_contents, true); chrome::CloseWindow(browser());
EXPECT_TRUE(window->IsVisible());
// Close the second browser.
browser2->tab_strip_model()->CloseAllTabs();
content::RunAllPendingInMessageLoop();
EXPECT_TRUE(window->IsVisible());
// Close the dialog's tab.
bool closed =
browser()->tab_strip_model()->CloseWebContentsAt(
browser()->tab_strip_model()->GetIndexOfWebContents(web_contents),
TabStripModel::CLOSE_NONE);
EXPECT_TRUE(closed);
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_TRUE(test_dialog->done()); EXPECT_TRUE(dialog->GetWidget()->IsVisible());
}
#if defined(OS_WIN) || (defined(USE_AURA) && defined(USE_X11))
// Forwards the key event which has |key_code| to the renderer.
void ForwardKeyEvent(content::RenderViewHost* host, ui::KeyboardCode key_code) {
#if defined(OS_WIN)
MSG native_key_event = { NULL, WM_KEYDOWN, key_code, 0 };
#elif defined(USE_X11)
ui::ScopedXI2Event x_event;
x_event.InitKeyEvent(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
XEvent* native_key_event = x_event;
#endif
#if defined(USE_AURA) // Close the dialog's browser window.
ui::KeyEvent key(native_key_event, false); chrome::CloseTab(browser2);
ui::KeyEvent* native_ui_key_event = &key; content::RunAllPendingInMessageLoop();
#elif defined(OS_WIN) EXPECT_EQ(NULL, dialog->GetWidget());
MSG native_ui_key_event = native_key_event;
#endif
host->ForwardKeyboardEvent(
content::NativeWebKeyboardEvent(native_ui_key_event));
} }
// Tests that backspace is not processed before it's sent to the web contents. // Tests that the web contents navigates when backspace is pressed.
// Flaky on Win Aura and Linux ChromiumOS. See http://crbug.com/170331 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, NavigationOnBackspace) {
#if defined(USE_AURA)
#define MAYBE_BackspaceSentToWebContent DISABLED_BackspaceSentToWebContent
#else
#define MAYBE_BackspaceSentToWebContent BackspaceSentToWebContent
#endif
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest,
MAYBE_BackspaceSentToWebContent) {
content::WebContents* web_contents = content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents != NULL); content::WaitForLoadStop(web_contents);
const GURL original_url = web_contents->GetURL();
GURL new_tab_url(chrome::kChromeUINewTabURL); EXPECT_NE(GURL(chrome::kChromeUIVersionURL), original_url);
ui_test_utils::NavigateToURL(browser(), new_tab_url); ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL));
GURL about_url(chrome::kChromeUIAboutURL); content::WaitForLoadStop(web_contents);
ui_test_utils::NavigateToURL(browser(), about_url); EXPECT_EQ(GURL(chrome::kChromeUIVersionURL), web_contents->GetURL());
ConstrainedWebDialogDelegate* cwdd = CreateConstrainedWebDialog( scoped_ptr<TestDialog> dialog = ShowModalDialog(web_contents);
browser()->profile(), EXPECT_TRUE(dialog->GetWidget()->IsVisible());
new ui::test::TestWebDialogDelegate(about_url), EXPECT_EQ(dialog->GetContentsView(),
NULL, dialog->GetWidget()->GetFocusManager()->GetFocusedView());
web_contents);
// Pressing backspace should navigate back and close the dialog.
content::WindowedNotificationObserver back_observer( EXPECT_TRUE(chrome::CanGoBack(browser()));
content::NOTIFICATION_LOAD_STOP, EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_BACK,
content::Source<content::NavigationController>( false, false, false, false));
&web_contents->GetController()));
content::RenderViewHost* render_view_host =
cwdd->GetWebContents()->GetRenderViewHost();
ForwardKeyEvent(render_view_host, ui::VKEY_BACK);
// Backspace is not processed as accelerator before it's sent to web contents.
EXPECT_FALSE(web_contents->GetController().GetPendingEntry());
EXPECT_EQ(about_url.spec(), web_contents->GetURL().spec());
// Backspace is processed as accelerator after it's sent to web contents.
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_TRUE(web_contents->GetController().GetPendingEntry()); content::WaitForLoadStop(web_contents);
EXPECT_EQ(NULL, dialog->GetWidget());
// Wait for the navigation to commit, since the URL will not be visible EXPECT_EQ(original_url, web_contents->GetURL());
// until then.
back_observer.Wait();
EXPECT_TRUE(chrome::IsNTPURL(web_contents->GetURL(), browser()->profile()));
} }
// Fails flakily (once per 10-20 runs) on Win Aura only. http://crbug.com/177482 // Tests that the dialog closes when the escape key is pressed.
// Also fails on CrOS. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, ClosesOnEscape) {
// Also fails on linux_aura (http://crbug.com/163931) #if defined(OS_WIN)
#if defined(TOOLKIT_VIEWS) // TODO(msw): The widget is not made NULL on XP. http://crbug.com/177482
#define MAYBE_EscapeCloseConstrainedWindow DISABLED_EscapeCloseConstrainedWindow if (base::win::GetVersion() < base::win::VERSION_VISTA)
#else return;
#define MAYBE_EscapeCloseConstrainedWindow EscapeCloseConstrainedWindow
#endif #endif
// Tests that escape closes the constrained window. scoped_ptr<TestDialog> dialog = ShowModalDialog(
IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, browser()->tab_strip_model()->GetActiveWebContents());
MAYBE_EscapeCloseConstrainedWindow) { EXPECT_TRUE(dialog->GetWidget()->IsVisible());
content::WebContents* web_contents = EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE,
browser()->tab_strip_model()->GetActiveWebContents(); false, false, false, false));
ASSERT_TRUE(web_contents != NULL);
GURL new_tab_url(chrome::kChromeUINewTabURL);
ui_test_utils::NavigateToURL(browser(), new_tab_url);
ConstrainedWebDialogDelegate* cwdd = CreateConstrainedWebDialog(
browser()->profile(),
new ui::test::TestWebDialogDelegate(new_tab_url),
NULL,
web_contents);
views::Widget* widget =
views::Widget::GetWidgetForNativeView(cwdd->GetNativeDialog());
views::test::TestWidgetObserver observer(widget);
content::RenderViewHost* render_view_host =
cwdd->GetWebContents()->GetRenderViewHost();
ForwardKeyEvent(render_view_host, ui::VKEY_ESCAPE);
// Escape is not processed as accelerator before it's sent to web contents.
EXPECT_FALSE(observer.widget_closed());
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
EXPECT_EQ(NULL, dialog->GetWidget());
// Escape is processed as accelerator after it's sent to web contents.
EXPECT_TRUE(observer.widget_closed());
} }
#endif // defined(OS_WIN) || (defined(USE_AURA) && defined(USE_X11))
...@@ -43,7 +43,7 @@ HRESULT ForegroundHelper::ForegroundHotKey(HWND window) { ...@@ -43,7 +43,7 @@ HRESULT ForegroundHelper::ForegroundHotKey(HWND window) {
hotkey.type = INPUT_KEYBOARD; hotkey.type = INPUT_KEYBOARD;
hotkey.ki.wVk = VK_F22; hotkey.ki.wVk = VK_F22;
if (1 != SendInput(1, &hotkey, sizeof(hotkey))) { if (1 != SendInput(1, &hotkey, sizeof(hotkey))) {
LOG(WARNING) << "Failed to send input"; LOG(WARNING) << "Failed to send input; GetLastError(): " << GetLastError();
return E_FAIL; return E_FAIL;
} }
......
...@@ -258,6 +258,7 @@ DesktopNativeWidgetAura::DesktopNativeWidgetAura( ...@@ -258,6 +258,7 @@ DesktopNativeWidgetAura::DesktopNativeWidgetAura(
native_widget_delegate_(delegate), native_widget_delegate_(delegate),
last_drop_operation_(ui::DragDropTypes::DRAG_NONE), last_drop_operation_(ui::DragDropTypes::DRAG_NONE),
restore_focus_on_activate_(false), restore_focus_on_activate_(false),
restore_focus_on_window_focus_(false),
cursor_(gfx::kNullCursor), cursor_(gfx::kNullCursor),
widget_type_(Widget::InitParams::TYPE_WINDOW) { widget_type_(Widget::InitParams::TYPE_WINDOW) {
aura::client::SetFocusChangeObserver(content_window_, this); aura::client::SetFocusChangeObserver(content_window_, this);
...@@ -1082,15 +1083,23 @@ void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus, ...@@ -1082,15 +1083,23 @@ void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
native_widget_delegate_->OnNativeFocus(lost_focus); native_widget_delegate_->OnNativeFocus(lost_focus);
// If focus is moving from a descendant Window to |content_window_| then // If focus is moving from a descendant Window to |content_window_| then
// native activation hasn't changed. We still need to inform the InputMethod // native activation hasn't changed. Still, the InputMethod and FocusManager
// we've been focused though. // must be informed of the Window focus change.
InputMethod* input_method = GetWidget()->GetInputMethod(); InputMethod* input_method = GetWidget()->GetInputMethod();
if (input_method) if (input_method)
input_method->OnFocus(); input_method->OnFocus();
if (restore_focus_on_window_focus_) {
restore_focus_on_window_focus_ = false;
GetWidget()->GetFocusManager()->RestoreFocusedView();
}
} else if (content_window_ == lost_focus) { } else if (content_window_ == lost_focus) {
desktop_window_tree_host_->OnNativeWidgetBlur(); desktop_window_tree_host_->OnNativeWidgetBlur();
native_widget_delegate_->OnNativeBlur( native_widget_delegate_->OnNativeBlur(gained_focus);
aura::client::GetFocusClient(content_window_)->GetFocusedWindow());
DCHECK(!restore_focus_on_window_focus_);
restore_focus_on_window_focus_ = true;
GetWidget()->GetFocusManager()->StoreFocusedView(false);
} }
} }
......
...@@ -294,6 +294,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura ...@@ -294,6 +294,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
window_modality_controller_; window_modality_controller_;
bool restore_focus_on_activate_; bool restore_focus_on_activate_;
bool restore_focus_on_window_focus_;
gfx::NativeCursor cursor_; gfx::NativeCursor cursor_;
// We must manually reference count the number of users of |cursor_manager_| // We must manually reference count the number of users of |cursor_manager_|
......
...@@ -895,6 +895,7 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus, ...@@ -895,6 +895,7 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
if (GetWidget()->GetInputMethod()) // Null in tests. if (GetWidget()->GetInputMethod()) // Null in tests.
GetWidget()->GetInputMethod()->OnFocus(); GetWidget()->GetInputMethod()->OnFocus();
delegate_->OnNativeFocus(lost_focus); delegate_->OnNativeFocus(lost_focus);
GetWidget()->GetFocusManager()->RestoreFocusedView();
} else if (window_ == lost_focus) { } else if (window_ == lost_focus) {
// GetInputMethod() recreates the input method if it's previously been // GetInputMethod() recreates the input method if it's previously been
// destroyed. If we get called during destruction, the input method will be // destroyed. If we get called during destruction, the input method will be
...@@ -910,9 +911,8 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus, ...@@ -910,9 +911,8 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
DCHECK_EQ(ownership_, Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET); DCHECK_EQ(ownership_, Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
} }
aura::client::FocusClient* client = aura::client::GetFocusClient(window_); delegate_->OnNativeBlur(gained_focus);
if (client) // NULL during destruction of aura::Window. GetWidget()->GetFocusManager()->StoreFocusedView(true);
delegate_->OnNativeBlur(client->GetFocusedWindow());
} }
} }
......
...@@ -1045,19 +1045,11 @@ void Widget::OnNativeWidgetActivationChanged(bool active) { ...@@ -1045,19 +1045,11 @@ void Widget::OnNativeWidgetActivationChanged(bool active) {
} }
void Widget::OnNativeFocus(gfx::NativeView old_focused_view) { void Widget::OnNativeFocus(gfx::NativeView old_focused_view) {
// Ensure the focused view's TextInputClient is used for text input.
views::FocusManager* focus_manager = GetFocusManager();
focus_manager->FocusTextInputClient(focus_manager->GetFocusedView());
WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(old_focused_view, WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(old_focused_view,
GetNativeView()); GetNativeView());
} }
void Widget::OnNativeBlur(gfx::NativeView new_focused_view) { void Widget::OnNativeBlur(gfx::NativeView new_focused_view) {
// Ensure the focused view's TextInputClient is not used for text input.
views::FocusManager* focus_manager = GetFocusManager();
focus_manager->BlurTextInputClient(focus_manager->GetFocusedView());
WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(GetNativeView(), WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(GetNativeView(),
new_focused_view); new_focused_view);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment