Windows: Use WS_EX_NOACTIVATE to control initial window activation (issue #1856)

This commit is contained in:
Marshall Greenblatt 2019-02-07 16:36:31 -05:00
parent 84a5749f9f
commit b8eaec0db2
10 changed files with 107 additions and 7 deletions

View File

@ -207,8 +207,27 @@ bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
gfx::Rect(0, 0, point.x(), point.y()));
window_widget_ = delegate_view->GetWidget();
const HWND widget_hwnd = HWNDForWidget(window_widget_);
DCHECK(widget_hwnd);
const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
if (window_info_.ex_style & WS_EX_NOACTIVATE) {
// Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
// so that HWNDMessageHandler::Show() called via Widget::Show() does not
// activate the window.
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
widget_ex_styles | WS_EX_NOACTIVATE);
}
window_widget_->Show();
if (window_info_.ex_style & WS_EX_NOACTIVATE) {
// Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside the
// browser correctly activate and focus the window.
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
}
return true;
}

View File

@ -41,6 +41,9 @@ void BrowserWindowOsrWin::GetPopupConfig(CefWindowHandle temp_handle,
windowInfo.external_begin_frame_enabled =
osr_window_->settings().external_begin_frame_enabled;
// Don't activate the hidden browser on creation.
windowInfo.ex_style |= WS_EX_NOACTIVATE;
client = client_handler_;
}

View File

@ -26,6 +26,11 @@ void BrowserWindowStdWin::CreateBrowser(
RECT wnd_rect = {rect.x, rect.y, rect.x + rect.width, rect.y + rect.height};
window_info.SetAsChild(parent_handle, wnd_rect);
if (GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Don't activate the browser window on creation.
window_info.ex_style |= WS_EX_NOACTIVATE;
}
CefBrowserHost::CreateBrowser(window_info, client_handler_,
client_handler_->startup_url(), settings,
request_context);
@ -39,6 +44,10 @@ void BrowserWindowStdWin::GetPopupConfig(CefWindowHandle temp_handle,
// The window will be properly sized after the browser is created.
windowInfo.SetAsChild(temp_handle, RECT());
// Don't activate the hidden browser window on creation.
windowInfo.ex_style |= WS_EX_NOACTIVATE;
client = client_handler_;
}
@ -53,8 +62,11 @@ void BrowserWindowStdWin::ShowPopup(ClientWindowHandle parent_handle,
if (hwnd) {
SetParent(hwnd, parent_handle);
SetWindowPos(hwnd, NULL, x, y, static_cast<int>(width),
static_cast<int>(height), SWP_NOZORDER);
ShowWindow(hwnd, SW_SHOW);
static_cast<int>(height), SWP_NOZORDER | SWP_NOACTIVATE);
const bool no_activate =
GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE;
ShowWindow(hwnd, no_activate ? SW_SHOWNOACTIVATE : SW_SHOW);
}
}

View File

@ -249,7 +249,8 @@ ClientHandler::ClientHandler(Delegate* delegate,
browser_count_(0),
console_log_file_(MainContext::Get()->GetConsoleLogPath()),
first_console_message_(true),
focus_on_editable_field_(false) {
focus_on_editable_field_(false),
initial_navigation_(true) {
DCHECK(!console_log_file_.empty());
#if defined(OS_LINUX)
@ -497,6 +498,22 @@ void ClientHandler::OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) {
NotifyTakeFocus(next);
}
bool ClientHandler::OnSetFocus(CefRefPtr<CefBrowser> browser,
FocusSource source) {
CEF_REQUIRE_UI_THREAD();
if (initial_navigation_) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(switches::kNoActivate)) {
// Don't give focus to the browser on creation.
return true;
}
}
return false;
}
bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event,
@ -606,6 +623,10 @@ void ClientHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool canGoForward) {
CEF_REQUIRE_UI_THREAD();
if (!isLoading && initial_navigation_) {
initial_navigation_ = false;
}
NotifyLoadingState(isLoading, canGoBack, canGoForward);
}

View File

@ -169,6 +169,7 @@ class ClientHandler : public CefClient,
// CefFocusHandler methods
void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) OVERRIDE;
bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) OVERRIDE;
// CefKeyboardHandler methods
bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
@ -370,6 +371,9 @@ class ClientHandler : public CefClient,
// True if an editable field currently has focus.
bool focus_on_editable_field_;
// True for the initial navigation after browser creation.
bool initial_navigation_;
// Set of Handlers registered with the message router.
MessageHandlerSet message_handler_set_;

View File

@ -76,6 +76,11 @@ void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
CefWindowInfo window_info;
window_info.SetAsWindowless(hwnd_);
if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Don't activate the browser window on creation.
window_info.ex_style |= WS_EX_NOACTIVATE;
}
window_info.shared_texture_enabled = settings_.shared_texture_enabled;
window_info.external_begin_frame_enabled =
settings_.external_begin_frame_enabled;
@ -220,10 +225,16 @@ void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
RegisterOsrClass(hInst, background_brush);
DWORD ex_style = 0;
if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Don't activate the browser window on creation.
ex_style |= WS_EX_NOACTIVATE;
}
// Create the native window with a border so it's easier to visually identify
// OSR windows.
hwnd_ = ::CreateWindow(
kWndClass, 0,
hwnd_ = ::CreateWindowEx(
ex_style, kWndClass, 0,
WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
parent_hwnd, 0, hInst, 0);

View File

@ -150,6 +150,7 @@ class RootWindow
ShowNormal,
ShowMinimized,
ShowMaximized,
ShowNoActivate,
};
// Show the window.

View File

@ -226,6 +226,9 @@ void RootWindowWin::Show(ShowMode mode) {
case ShowMaximized:
nCmdShow = SW_SHOWMAXIMIZED;
break;
case ShowNoActivate:
nCmdShow = SW_SHOWNOACTIVATE;
break;
default:
break;
}
@ -334,8 +337,16 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
find_message_id_ = RegisterWindowMessage(FINDMSGSTRING);
CHECK(find_message_id_);
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
const bool no_activate = command_line->HasSwitch(switches::kNoActivate);
const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
const DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0;
DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0;
if (no_activate) {
// Don't activate the browser window on creation.
dwExStyle |= WS_EX_NOACTIVATE;
}
int x, y, width, height;
if (::IsRectEmpty(&start_rect_)) {
@ -373,7 +384,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
if (!initially_hidden) {
// Show this window.
Show(ShowNormal);
Show(no_activate ? ShowNoActivate : ShowNormal);
}
}
@ -1069,6 +1080,22 @@ void RootWindowWin::OnSetLoadingState(bool isLoading,
EnableWindow(stop_hwnd_, isLoading);
EnableWindow(edit_hwnd_, TRUE);
}
if (!isLoading && GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Done with the initial navigation. Remove the WS_EX_NOACTIVATE style so
// that future mouse clicks inside the browser correctly activate and focus
// the window. For the top-level window removing this style causes Windows
// to display the task bar button.
SetWindowLongPtr(hwnd_, GWL_EXSTYLE,
GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
if (browser_window_) {
HWND browser_hwnd = browser_window_->GetWindowHandle();
SetWindowLongPtr(
browser_hwnd, GWL_EXSTYLE,
GetWindowLongPtr(browser_hwnd, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
}
}
}
namespace {

View File

@ -43,6 +43,7 @@ const char kWidevineCdmPath[] = "widevine-cdm-path";
const char kSslClientCertificate[] = "ssl-client-certificate";
const char kCRLSetsPath[] = "crl-sets-path";
const char kLoadExtension[] = "load-extension";
const char kNoActivate[] = "no-activate";
} // namespace switches
} // namespace client

View File

@ -37,6 +37,7 @@ extern const char kWidevineCdmPath[];
extern const char kSslClientCertificate[];
extern const char kCRLSetsPath[];
extern const char kLoadExtension[];
extern const char kNoActivate[];
} // namespace switches
} // namespace client