diff --git a/include/cef.h b/include/cef.h index 877ec2f5b..9b90d37a0 100644 --- a/include/cef.h +++ b/include/cef.h @@ -525,11 +525,18 @@ public: virtual RetVal HandleTakeFocus(CefRefPtr browser, bool reverse) =0; - // Event called for adding values to a frame's JavaScript 'window' object. The + // Event called for adding values to a frame's JavaScript 'window' object. The // return value is currently ignored. virtual RetVal HandleJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object) =0; + + // Called when the browser component is requesting focus. |isWidget| will be + // true if the focus is requested for a child widget of the browser window. + // Return RV_CONTINUE to allow the focus to be set or RV_HANDLED to cancel + // setting the focus. + virtual RetVal HandleSetFocus(CefRefPtr browser, + bool isWidget) =0; }; diff --git a/include/cef_capi.h b/include/cef_capi.h index 71381210d..1c7aaa57d 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -432,11 +432,19 @@ typedef struct _cef_handler_t enum cef_retval_t (CEF_CALLBACK *handle_take_focus)( struct _cef_handler_t* handler, cef_browser_t* browser, int reverse); - // Event called for adding values to a frame's JavaScript 'window' object. The + // Event called for adding values to a frame's JavaScript 'window' object. The // return value is currently ignored. enum cef_retval_t (CEF_CALLBACK *handle_jsbinding)( struct _cef_handler_t* handler, cef_browser_t* browser, cef_frame_t* frame, struct _cef_v8value_t* object); + + // Called when the browser component is requesting focus. |isWidget| will be + // true (1) if the focus is requested for a child widget of the browser + // window. Return RV_CONTINUE to allow the focus to be set or RV_HANDLED to + // cancel setting the focus. + enum cef_retval_t (CEF_CALLBACK *handle_set_focus)( + struct _cef_handler_t* handler, cef_browser_t* browser, int isWidget); + } cef_handler_t; diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index b31bab9a7..9e573f156 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -548,13 +548,19 @@ bool CefBrowserImpl::UIT_Navigate(const BrowserNavigationEntry& entry, // In case LoadRequest failed before DidCreateDataSource was called. delegate_->set_pending_extra_data(NULL); - // Restore focus to the main frame prior to loading new request. - // This makes sure that we don't have a focused iframe. Otherwise, that - // iframe would keep focus when the SetFocus called immediately after - // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 - // for more details). - GetWebView()->SetFocusedFrame(frame); - UIT_SetFocus(GetWebViewHost(), true); + if (handler_.get() && handler_->HandleSetFocus(this, false) == RV_CONTINUE) { + // Restore focus to the main frame prior to loading new request. + // This makes sure that we don't have a focused iframe. Otherwise, that + // iframe would keep focus when the SetFocus called immediately after + // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 + // for more details). + // TODO(cef): The above comment may be wrong, or the below call to + // SetFocusedFrame() may be unnecessary or in the wrong place. See this + // thread for additional details: + // http://groups.google.com/group/chromium-dev/browse_thread/thread/42bcd31b59e3a168 + GetWebView()->SetFocusedFrame(frame); + UIT_SetFocus(GetWebViewHost(), true); + } return true; } diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc index 892892a8b..d69bac522 100644 --- a/libcef/browser_webview_delegate.cc +++ b/libcef/browser_webview_delegate.cc @@ -548,8 +548,11 @@ void BrowserWebViewDelegate::DidScrollRect(WebWidget* webwidget, int dx, int dy, } void BrowserWebViewDelegate::Focus(WebWidget* webwidget) { - if (WebWidgetHost* host = GetHostForWidget(webwidget)) - browser_->UIT_SetFocus(host, true); + if (WebWidgetHost* host = GetHostForWidget(webwidget)) { + CefRefPtr handler = browser_->GetHandler(); + if (handler.get() && handler->HandleSetFocus(browser_, true) == RV_CONTINUE) + browser_->UIT_SetFocus(host, true); + } } void BrowserWebViewDelegate::Blur(WebWidget* webwidget) { diff --git a/libcef_dll/cpptoc/handler_cpptoc.cc b/libcef_dll/cpptoc/handler_cpptoc.cc index 9e3ff1349..5af421a07 100644 --- a/libcef_dll/cpptoc/handler_cpptoc.cc +++ b/libcef_dll/cpptoc/handler_cpptoc.cc @@ -423,8 +423,8 @@ enum cef_retval_t CEF_CALLBACK handler_handle_take_focus( return CefHandlerCppToC::Get(handler)->HandleTakeFocus( CefBrowserCToCpp::Wrap(browser), (reverse ? true : false)); } - -enum cef_retval_t CEF_CALLBACK handler_handle_jsbinding( + +enum cef_retval_t CEF_CALLBACK handler_handle_jsbinding( struct _cef_handler_t* handler, cef_browser_t* browser, cef_frame_t* frame, struct _cef_v8value_t* object) { @@ -440,6 +440,18 @@ enum cef_retval_t CEF_CALLBACK handler_handle_jsbinding( CefV8ValueCToCpp::Wrap(object)); } +enum cef_retval_t CEF_CALLBACK handler_handle_set_focus( + struct _cef_handler_t* handler, cef_browser_t* browser, int isWidget) +{ + DCHECK(handler); + DCHECK(browser); + if(!handler || !browser) + return RV_CONTINUE; + + return CefHandlerCppToC::Get(handler)->HandleSetFocus( + CefBrowserCToCpp::Wrap(browser), isWidget); +} + CefHandlerCppToC::CefHandlerCppToC(CefHandler* cls) : CefCppToC(cls) @@ -466,6 +478,7 @@ CefHandlerCppToC::CefHandlerCppToC(CefHandler* cls) handler_handle_before_window_close; struct_.struct_.handle_take_focus = handler_handle_take_focus; struct_.struct_.handle_jsbinding = handler_handle_jsbinding; + struct_.struct_.handle_set_focus = handler_handle_set_focus; } #ifdef _DEBUG diff --git a/libcef_dll/ctocpp/handler_ctocpp.cc b/libcef_dll/ctocpp/handler_ctocpp.cc index f5c595a10..11e7513a3 100644 --- a/libcef_dll/ctocpp/handler_ctocpp.cc +++ b/libcef_dll/ctocpp/handler_ctocpp.cc @@ -317,7 +317,7 @@ CefHandler::RetVal CefHandlerCToCpp::HandleTakeFocus( reverse); } -CefHandler::RetVal CefHandlerCToCpp::HandleJSBinding( +CefHandler::RetVal CefHandlerCToCpp::HandleJSBinding( CefRefPtr browser, CefRefPtr frame, CefRefPtr object) { @@ -328,6 +328,16 @@ CefHandler::RetVal CefHandlerCToCpp::HandleJSBinding( CefFrameCppToC::Wrap(frame), CefV8ValueCppToC::Wrap(object)); } +CefHandler::RetVal CefHandlerCToCpp::HandleSetFocus( + CefRefPtr browser, bool isWidget) +{ + if(CEF_MEMBER_MISSING(struct_, handle_set_focus)) + return RV_CONTINUE; + + return struct_->handle_set_focus(struct_, CefBrowserCppToC::Wrap(browser), + isWidget); +} + #ifdef _DEBUG long CefCToCpp::DebugObjCt = 0; #endif diff --git a/libcef_dll/ctocpp/handler_ctocpp.h b/libcef_dll/ctocpp/handler_ctocpp.h index 857c03d10..234138a94 100644 --- a/libcef_dll/ctocpp/handler_ctocpp.h +++ b/libcef_dll/ctocpp/handler_ctocpp.h @@ -87,9 +87,11 @@ public: virtual RetVal HandleBeforeWindowClose(CefRefPtr browser); virtual RetVal HandleTakeFocus(CefRefPtr browser, bool reverse); - virtual RetVal HandleJSBinding(CefRefPtr browser, + virtual RetVal HandleJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object); + virtual RetVal HandleSetFocus(CefRefPtr browser, + bool isWidget); }; diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp index bb7e12b59..ef3cef88b 100644 --- a/tests/cefclient/cefclient.cpp +++ b/tests/cefclient/cefclient.cpp @@ -720,6 +720,16 @@ public: return RV_HANDLED; } + // Called when the browser component is requesting focus. |isWidget| will be + // true if the focus is requested for a child widget of the browser window. + // Return RV_CONTINUE to allow the focus to be set or RV_HANDLED to cancel + // setting the focus. + virtual RetVal HandleSetFocus(CefRefPtr browser, + bool isWidget) + { + return RV_CONTINUE; + } + // Retrieve the current navigation state flags void GetNavState(bool &isLoading, bool &canGoBack, bool &canGoForward) {