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:
@ -4,8 +4,10 @@
|
||||
|
||||
#include "tests/cefclient/browser/base_client_handler.h"
|
||||
|
||||
#include "include/cef_command_line.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/root_window_manager.h"
|
||||
#include "tests/shared/common/client_switches.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
@ -36,6 +38,11 @@ bool BaseClientHandler::OnProcessMessageReceived(
|
||||
source_process, message);
|
||||
}
|
||||
|
||||
bool BaseClientHandler::OnSetFocus(CefRefPtr<CefBrowser> browser,
|
||||
FocusSource source) {
|
||||
return !ShouldRequestFocus();
|
||||
}
|
||||
|
||||
void BaseClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
@ -76,6 +83,17 @@ void BaseClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
}
|
||||
|
||||
void BaseClientHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!isLoading && initial_navigation_) {
|
||||
initial_navigation_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
@ -168,4 +186,19 @@ BaseClientHandler::HangAction BaseClientHandler::GetHangAction() const {
|
||||
return hang_action_;
|
||||
}
|
||||
|
||||
bool BaseClientHandler::ShouldRequestFocus() {
|
||||
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 false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -14,7 +14,9 @@ namespace client {
|
||||
|
||||
// Abstract base class for client handlers.
|
||||
class BaseClientHandler : public CefClient,
|
||||
public CefFocusHandler,
|
||||
public CefLifeSpanHandler,
|
||||
public CefLoadHandler,
|
||||
public CefRequestHandler,
|
||||
public CefResourceRequestHandler {
|
||||
public:
|
||||
@ -28,17 +30,28 @@ class BaseClientHandler : public CefClient,
|
||||
static CefRefPtr<BaseClientHandler> GetForClient(CefRefPtr<CefClient> client);
|
||||
|
||||
// CefClient methods
|
||||
CefRefPtr<CefFocusHandler> GetFocusHandler() override { return this; }
|
||||
CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
|
||||
CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
|
||||
CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
|
||||
bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) override;
|
||||
|
||||
// CefFocusHandler methods
|
||||
bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override;
|
||||
|
||||
// CefLifeSpanHandler methods
|
||||
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
|
||||
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
|
||||
|
||||
// CefLoadHandler methods
|
||||
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
|
||||
// CefRequestHandler methods
|
||||
bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
@ -95,6 +108,8 @@ class BaseClientHandler : public CefClient,
|
||||
void SetHangAction(HangAction action);
|
||||
HangAction GetHangAction() const;
|
||||
|
||||
bool ShouldRequestFocus();
|
||||
|
||||
// Used to determine the object type for each concrete implementation.
|
||||
virtual const void* GetTypeKey() const = 0;
|
||||
|
||||
@ -129,6 +144,9 @@ class BaseClientHandler : public CefClient,
|
||||
|
||||
HangAction hang_action_ = HangAction::kDefault;
|
||||
|
||||
// True for the initial navigation after browser creation.
|
||||
bool initial_navigation_ = true;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BaseClientHandler);
|
||||
};
|
||||
|
||||
|
@ -888,13 +888,12 @@ 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;
|
||||
}
|
||||
if (BaseClientHandler::OnSetFocus(browser, source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (delegate_ && delegate_->OnSetFocus(source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1009,9 +1008,8 @@ void ClientHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool canGoForward) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!isLoading && initial_navigation_) {
|
||||
initial_navigation_ = false;
|
||||
}
|
||||
BaseClientHandler::OnLoadingStateChange(browser, isLoading, canGoBack,
|
||||
canGoForward);
|
||||
|
||||
NotifyLoadingState(isLoading, canGoBack, canGoForward);
|
||||
}
|
||||
|
@ -32,9 +32,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
public CefDisplayHandler,
|
||||
public CefDownloadHandler,
|
||||
public CefDragHandler,
|
||||
public CefFocusHandler,
|
||||
public CefKeyboardHandler,
|
||||
public CefLoadHandler,
|
||||
public CefPermissionHandler {
|
||||
public:
|
||||
// Implement this interface to receive notification of ClientHandler
|
||||
@ -82,6 +80,9 @@ class ClientHandler : public BaseClientHandler,
|
||||
virtual void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) = 0;
|
||||
|
||||
// Called on the UI thread to optionally handle the browser gaining focus.
|
||||
virtual bool OnSetFocus(cef_focus_source_t source) { return false; }
|
||||
|
||||
// Set focus to the next/previous control.
|
||||
virtual void OnTakeFocus(bool next) {}
|
||||
|
||||
@ -111,9 +112,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
|
||||
CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; }
|
||||
CefRefPtr<CefDragHandler> GetDragHandler() override { return this; }
|
||||
CefRefPtr<CefFocusHandler> GetFocusHandler() override { return this; }
|
||||
CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() override { return this; }
|
||||
CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
|
||||
CefRefPtr<CefPermissionHandler> GetPermissionHandler() override {
|
||||
return this;
|
||||
}
|
||||
@ -423,9 +422,6 @@ class ClientHandler : public BaseClientHandler,
|
||||
// True if an editable field currently has focus.
|
||||
bool focus_on_editable_field_ = false;
|
||||
|
||||
// True for the initial navigation after browser creation.
|
||||
bool initial_navigation_ = true;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ClientHandler);
|
||||
};
|
||||
|
||||
|
@ -451,6 +451,14 @@ void RootWindowViews::OnSetDraggableRegions(
|
||||
}
|
||||
}
|
||||
|
||||
bool RootWindowViews::OnSetFocus(cef_focus_source_t source) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (window_) {
|
||||
return window_->OnSetFocus(source);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RootWindowViews::OnTakeFocus(bool next) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
// Execute this method on the UI thread.
|
||||
|
@ -85,6 +85,7 @@ class RootWindowViews : public RootWindow,
|
||||
bool canGoForward) override;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) override;
|
||||
bool OnSetFocus(cef_focus_source_t source) override;
|
||||
void OnTakeFocus(bool next) override;
|
||||
void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) override;
|
||||
|
||||
|
@ -15,8 +15,8 @@ namespace {
|
||||
void AddPopOutAccelerator(CefRefPtr<CefWindow> window) {
|
||||
// Add an accelerator to toggle the BrowserView popout. OnAccelerator will be
|
||||
// called when the accelerator is triggered.
|
||||
window->SetAccelerator(ID_POPOUT_OVERLAY, 'O', /*shift_pressed=*/false,
|
||||
/*ctrl_pressed=*/false, /*alt_pressed=*/true,
|
||||
window->SetAccelerator(ID_POPOUT_OVERLAY, 'O', /*shift_pressed=*/true,
|
||||
/*ctrl_pressed=*/true, /*alt_pressed=*/false,
|
||||
/*high_priority=*/true);
|
||||
}
|
||||
|
||||
@ -201,10 +201,15 @@ void ViewsOverlayBrowser::PopOutBrowserView() {
|
||||
void ViewsOverlayBrowser::PopInBrowserView() {
|
||||
CHECK(!browser_view_);
|
||||
|
||||
CefRefPtr<CefView> last_focused_view = window_->GetFocusedView();
|
||||
|
||||
// Resume ownership of the BrowserView and close the popout Window.
|
||||
CHECK(popout_window_);
|
||||
browser_view_ =
|
||||
PopoutWindowDelegate::GetForWindow(popout_window_)->DetachBrowserView();
|
||||
|
||||
const bool should_focus_browser =
|
||||
popout_window_->IsActive() && browser_view_->HasFocus();
|
||||
popout_window_->RemoveChildView(browser_view_);
|
||||
popout_window_->Close();
|
||||
popout_window_ = nullptr;
|
||||
@ -219,6 +224,14 @@ void ViewsOverlayBrowser::PopInBrowserView() {
|
||||
|
||||
// Make sure the overlay is positioned correctly.
|
||||
UpdateBounds(last_insets_);
|
||||
|
||||
if (should_focus_browser) {
|
||||
// Keep the BrowserView focused.
|
||||
browser_view_->RequestFocus();
|
||||
} else if (last_focused_view) {
|
||||
// Keep focus unchanged in the main Window.
|
||||
last_focused_view->RequestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewsOverlayBrowser::UpdateBounds(CefInsets insets) {
|
||||
@ -270,6 +283,14 @@ void ViewsOverlayBrowser::PopOutWindowDestroyed() {
|
||||
popout_window_ = nullptr;
|
||||
}
|
||||
|
||||
bool ViewsOverlayBrowser::RequestFocus() {
|
||||
if (browser_view_) {
|
||||
browser_view_->RequestFocus();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CefSize ViewsOverlayBrowser::GetMinimumSize(CefRefPtr<CefView> view) {
|
||||
return CefSize(200, 200);
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ class ViewsOverlayBrowser : public CefBrowserViewDelegate {
|
||||
|
||||
void PopOutWindowDestroyed();
|
||||
|
||||
bool RequestFocus();
|
||||
|
||||
private:
|
||||
// CefViewDelegate methods:
|
||||
CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "include/cef_i18n_util.h"
|
||||
#include "include/views/cef_box_layout.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "tests/cefclient/browser/base_client_handler.h"
|
||||
#include "tests/cefclient/browser/default_client_handler.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
@ -201,10 +202,7 @@ void ViewsWindow::Show() {
|
||||
window_->Show();
|
||||
}
|
||||
}
|
||||
if (browser_view_ && !window_->IsMinimized()) {
|
||||
// Give keyboard focus to the BrowserView.
|
||||
browser_view_->RequestFocus();
|
||||
}
|
||||
MaybeRequestBrowserFocus();
|
||||
}
|
||||
|
||||
void ViewsWindow::Hide() {
|
||||
@ -378,6 +376,18 @@ void ViewsWindow::SetDraggableRegions(
|
||||
window_->SetDraggableRegions(window_regions);
|
||||
}
|
||||
|
||||
bool ViewsWindow::OnSetFocus(cef_focus_source_t source) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// No special handling of focus requests originating from the system.
|
||||
if (source == FOCUS_SOURCE_SYSTEM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RequestBrowserFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewsWindow::TakeFocus(bool next) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
@ -1396,4 +1406,31 @@ void ViewsWindow::NudgeWindow() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void ViewsWindow::MaybeRequestBrowserFocus() {
|
||||
if (browser_view_) {
|
||||
// BaseClientHandler has some state that we need to query.
|
||||
if (auto handler =
|
||||
BaseClientHandler::GetForBrowser(browser_view_->GetBrowser());
|
||||
handler->ShouldRequestFocus()) {
|
||||
RequestBrowserFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViewsWindow::RequestBrowserFocus() {
|
||||
if (window_->IsMinimized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Maybe give keyboard focus to the overlay BrowserView.
|
||||
if (overlay_browser_ && overlay_browser_->RequestFocus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give keyboard focus to the main BrowserView.
|
||||
if (browser_view_) {
|
||||
browser_view_->RequestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -120,6 +120,7 @@ class ViewsWindow : public CefBrowserViewDelegate,
|
||||
void SetAlwaysOnTop(bool on_top);
|
||||
void SetLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
|
||||
void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
|
||||
bool OnSetFocus(cef_focus_source_t source);
|
||||
void TakeFocus(bool next);
|
||||
void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model);
|
||||
|
||||
@ -253,6 +254,9 @@ class ViewsWindow : public CefBrowserViewDelegate,
|
||||
|
||||
void NudgeWindow();
|
||||
|
||||
void MaybeRequestBrowserFocus();
|
||||
void RequestBrowserFocus();
|
||||
|
||||
const WindowType type_;
|
||||
Delegate* const delegate_; // Not owned by this object.
|
||||
const bool use_alloy_style_;
|
||||
|
@ -33,12 +33,6 @@ class SimpleWindowDelegate : public CefWindowDelegate {
|
||||
if (initial_show_state_ != CEF_SHOW_STATE_HIDDEN) {
|
||||
window->Show();
|
||||
}
|
||||
|
||||
if (initial_show_state_ != CEF_SHOW_STATE_MINIMIZED &&
|
||||
initial_show_state_ != CEF_SHOW_STATE_HIDDEN) {
|
||||
// Give keyboard focus to the browser view.
|
||||
browser_view_->RequestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
|
||||
|
Reference in New Issue
Block a user