mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
views: Fix Chrome style browser RequestFocus behavior (fixes #3819)
Fix implementation of CefBrowserView::RequestFocus for Chrome style browsers. Match Alloy style behavior of requesting browser focus (calling OnSetFocus) after initial navigation. Add CefView::HasFocus and CefWindow::GetFocusedView that can be used in combination with CefWindow::IsActive to determine global keyboard focus. Update sample applications for the new behavior. In cefclient: - Browser receives initial focus via ViewsWindow::RequestBrowserFocus. - When running with `--show-overlay-browser` (see #3790): - Give initial focus to the overlay browser. - Change the overlay popout shortcut to CTRL+SHIFT+O to avoid assigning focus to the menu in the main window. - Switching from overlay in the main window to popout browser window will give focus to the popout browser. - Switching from popout browser to overlay will leave current focus unchanged (e.g. in the overlay browser, or somewhere else). User gesture to activate the main window may be required on Mac/Linux. - When running with `--no-active` don't give initial focus to either browser. In cefsimple: - Browser receives initial focus via default handling.
This commit is contained in:
@ -28,7 +28,8 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
|
||||
auto browser = CreateBrowser(params, std::nullopt);
|
||||
|
||||
GURL url = url_util::MakeGURL(params.url, /*fixup=*/true);
|
||||
if (url.is_empty()) {
|
||||
const bool url_is_empty = url.is_empty();
|
||||
if (url_is_empty) {
|
||||
// Chrome will navigate to kChromeUINewTabURL by default. We want to keep
|
||||
// the current CEF behavior of not navigating at all. Use a special URL that
|
||||
// will be recognized in HandleNonNavigationAboutURL.
|
||||
@ -50,6 +51,11 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
|
||||
ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
|
||||
CHECK(browser_host);
|
||||
|
||||
if (!url_is_empty) {
|
||||
// Match Alloy-style behavior of requesting focus after initial navigation.
|
||||
browser_host->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
|
||||
}
|
||||
|
||||
return browser_host;
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,12 @@ CefBrowserPlatformDelegateChromeViews::GetBrowserView() const {
|
||||
return browser_view_.get();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateChromeViews::SetFocus(bool setFocus) {
|
||||
if (setFocus && browser_view_) {
|
||||
browser_view_->RequestFocusSync();
|
||||
}
|
||||
}
|
||||
|
||||
bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class CefBrowserPlatformDelegateChromeViews
|
||||
views::Widget* GetWindowWidget() const override;
|
||||
CefRefPtr<CefBrowserView> GetBrowserView() const override;
|
||||
void SetBrowserView(CefRefPtr<CefBrowserView> browser_view) override;
|
||||
void SetFocus(bool setFocus) override;
|
||||
bool IsViewsHosted() const override;
|
||||
|
||||
CefBrowserViewImpl* browser_view() const { return browser_view_.get(); }
|
||||
|
@ -154,15 +154,8 @@ void CefBrowserPlatformDelegateViews::SendTouchEvent(
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateViews::SetFocus(bool setFocus) {
|
||||
// Will activate the Widget and result in a call to WebContents::Focus().
|
||||
if (setFocus && browser_view_->root_view()) {
|
||||
if (auto widget = GetWindowWidget()) {
|
||||
// Don't activate a minimized Widget, or it will be shown.
|
||||
if (widget->IsMinimized()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
browser_view_->root_view()->RequestFocus();
|
||||
if (setFocus && browser_view_) {
|
||||
browser_view_->RequestFocusSync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,20 @@ void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostBase* browser) {
|
||||
DCHECK(!cef_widget_);
|
||||
}
|
||||
|
||||
void CefBrowserViewImpl::RequestFocusSync() {
|
||||
// With Chrome style the root_view() type (ChromeBrowserView) does not accept
|
||||
// focus, so always give focus to the WebView directly.
|
||||
if (web_view()) {
|
||||
if (auto widget = web_view()->GetWidget(); widget->IsMinimized()) {
|
||||
// Don't activate a minimized Widget, or it will be shown.
|
||||
return;
|
||||
}
|
||||
|
||||
// Activate the Widget and indirectly call WebContents::Focus().
|
||||
web_view()->RequestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool CefBrowserViewImpl::HandleKeyboardEvent(
|
||||
const input::NativeWebKeyboardEvent& event) {
|
||||
if (!root_view()) {
|
||||
@ -256,9 +270,8 @@ cef_runtime_style_t CefBrowserViewImpl::GetRuntimeStyle() {
|
||||
void CefBrowserViewImpl::RequestFocus() {
|
||||
CEF_REQUIRE_VALID_RETURN_VOID();
|
||||
// Always execute asynchronously to work around issue #3040.
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefBrowserViewImpl::RequestFocusInternal,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserViewImpl::RequestFocusSync,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void CefBrowserViewImpl::SetBackgroundColor(cef_color_t color) {
|
||||
@ -481,10 +494,6 @@ bool CefBrowserViewImpl::HandleAccelerator(
|
||||
return false;
|
||||
}
|
||||
|
||||
void CefBrowserViewImpl::RequestFocusInternal() {
|
||||
ParentClass::RequestFocus();
|
||||
}
|
||||
|
||||
void CefBrowserViewImpl::DisassociateFromWidget() {
|
||||
if (!cef_widget_) {
|
||||
return;
|
||||
|
@ -62,6 +62,7 @@ class CefBrowserViewImpl
|
||||
void BrowserCreated(CefBrowserHostBase* browser,
|
||||
base::RepeatingClosure on_bounds_changed);
|
||||
void BrowserDestroyed(CefBrowserHostBase* browser);
|
||||
void RequestFocusSync();
|
||||
|
||||
// Called to handle accelerators when the event is unhandled by the web
|
||||
// content and the browser client.
|
||||
@ -91,6 +92,7 @@ class CefBrowserViewImpl
|
||||
|
||||
// Return the WebView representation of this object.
|
||||
views::WebView* web_view() const;
|
||||
views::View* content_view() const override { return web_view(); }
|
||||
|
||||
// Return the CEF specialization of BrowserView.
|
||||
ChromeBrowserView* chrome_browser_view() const;
|
||||
@ -133,8 +135,6 @@ class CefBrowserViewImpl
|
||||
bool HandleAccelerator(const input::NativeWebKeyboardEvent& event,
|
||||
views::FocusManager* focus_manager);
|
||||
|
||||
void RequestFocusInternal();
|
||||
|
||||
void DisassociateFromWidget();
|
||||
|
||||
// True if the browser is Alloy style, otherwise Chrome style.
|
||||
|
@ -401,6 +401,7 @@ CEF_VIEW_IMPL_T class CefViewImpl : public CefViewAdapter, public CefViewClass {
|
||||
void SetFocusable(bool focusable) override;
|
||||
bool IsFocusable() override;
|
||||
bool IsAccessibilityFocusable() override;
|
||||
bool HasFocus() override;
|
||||
void RequestFocus() override;
|
||||
void SetBackgroundColor(cef_color_t color) override;
|
||||
cef_color_t GetBackgroundColor() override;
|
||||
@ -656,23 +657,29 @@ CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsEnabled() {
|
||||
|
||||
CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetFocusable(bool focusable) {
|
||||
CEF_REQUIRE_VALID_RETURN_VOID();
|
||||
root_view()->SetFocusBehavior(focusable ? views::View::FocusBehavior::ALWAYS
|
||||
: views::View::FocusBehavior::NEVER);
|
||||
content_view()->SetFocusBehavior(focusable
|
||||
? views::View::FocusBehavior::ALWAYS
|
||||
: views::View::FocusBehavior::NEVER);
|
||||
}
|
||||
|
||||
CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsFocusable() {
|
||||
CEF_REQUIRE_VALID_RETURN(false);
|
||||
return root_view()->IsFocusable();
|
||||
return content_view()->IsFocusable();
|
||||
}
|
||||
|
||||
CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsAccessibilityFocusable() {
|
||||
CEF_REQUIRE_VALID_RETURN(false);
|
||||
return root_view()->GetViewAccessibility().IsAccessibilityFocusable();
|
||||
return content_view()->GetViewAccessibility().IsAccessibilityFocusable();
|
||||
}
|
||||
|
||||
CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::HasFocus() {
|
||||
CEF_REQUIRE_VALID_RETURN(false);
|
||||
return content_view()->HasFocus();
|
||||
}
|
||||
|
||||
CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::RequestFocus() {
|
||||
CEF_REQUIRE_VALID_RETURN_VOID();
|
||||
root_view()->RequestFocus();
|
||||
content_view()->RequestFocus();
|
||||
}
|
||||
|
||||
CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetBackgroundColor(cef_color_t color) {
|
||||
|
@ -298,6 +298,16 @@ bool CefWindowImpl::IsFullscreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
CefRefPtr<CefView> CefWindowImpl::GetFocusedView() {
|
||||
CEF_REQUIRE_VALID_RETURN(nullptr);
|
||||
if (widget_ && widget_->GetFocusManager()) {
|
||||
if (auto* focused_view = widget_->GetFocusManager()->GetFocusedView()) {
|
||||
return view_util::GetFor(focused_view, /*find_known_parent=*/true);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CefWindowImpl::SetTitle(const CefString& title) {
|
||||
CEF_REQUIRE_VALID_RETURN_VOID();
|
||||
if (root_view()) {
|
||||
|
@ -58,6 +58,7 @@ class CefWindowImpl
|
||||
bool IsMaximized() override;
|
||||
bool IsMinimized() override;
|
||||
bool IsFullscreen() override;
|
||||
CefRefPtr<CefView> GetFocusedView() override;
|
||||
void SetTitle(const CefString& title) override;
|
||||
CefString GetTitle() override;
|
||||
void SetWindowIcon(CefRefPtr<CefImage> image) override;
|
||||
|
Reference in New Issue
Block a user