diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h index 534aca693..9f14e5d1b 100644 --- a/include/capi/cef_browser_capi.h +++ b/include/capi/cef_browser_capi.h @@ -448,10 +448,13 @@ typedef struct _cef_browser_host_t { int clearSelection); /// - // Open developer tools in its own window. If |inspect_element_at| is non- - // NULL the element at the specified (x,y) location will be inspected. The - // |windowInfo| parameter will be ignored if this browser is wrapped in a - // cef_browser_view_t. + // Open developer tools (DevTools) in its own browser. The DevTools browser + // will remain associated with this browser. If the DevTools browser is + // already open then it will be focused, in which case the |windowInfo|, + // |client| and |settings| parameters will be ignored. If |inspect_element_at| + // is non-NULL then the element at the specified (x,y) location will be + // inspected. The |windowInfo| parameter will be ignored if this browser is + // wrapped in a cef_browser_view_t. /// void (CEF_CALLBACK *show_dev_tools)(struct _cef_browser_host_t* self, const struct _cef_window_info_t* windowInfo, @@ -460,11 +463,16 @@ typedef struct _cef_browser_host_t { const cef_point_t* inspect_element_at); /// - // Explicitly close the developer tools window if one exists for this browser - // instance. + // Explicitly close the associated DevTools browser, if any. /// void (CEF_CALLBACK *close_dev_tools)(struct _cef_browser_host_t* self); + /// + // Returns true (1) if this browser currently has an associated DevTools + // browser. Must be called on the browser process UI thread. + /// + int (CEF_CALLBACK *has_dev_tools)(struct _cef_browser_host_t* self); + /// // Retrieve a snapshot of current navigation entries as values sent to the // specified visitor. If |current_only| is true (1) only the current diff --git a/include/cef_browser.h b/include/cef_browser.h index 4d0ca26ef..3f6e6c088 100644 --- a/include/cef_browser.h +++ b/include/cef_browser.h @@ -490,24 +490,34 @@ class CefBrowserHost : public virtual CefBase { virtual void StopFinding(bool clearSelection) =0; /// - // Open developer tools in its own window. If |inspect_element_at| is non- - // empty the element at the specified (x,y) location will be inspected. The - // |windowInfo| parameter will be ignored if this browser is wrapped in a - // CefBrowserView. + // Open developer tools (DevTools) in its own browser. The DevTools browser + // will remain associated with this browser. If the DevTools browser is + // already open then it will be focused, in which case the |windowInfo|, + // |client| and |settings| parameters will be ignored. If |inspect_element_at| + // is non-empty then the element at the specified (x,y) location will be + // inspected. The |windowInfo| parameter will be ignored if this browser is + // wrapped in a CefBrowserView. /// - /*--cef(optional_param=inspect_element_at)--*/ + /*--cef(optional_param=windowInfo,optional_param=client, + optional_param=settings,optional_param=inspect_element_at)--*/ virtual void ShowDevTools(const CefWindowInfo& windowInfo, CefRefPtr client, const CefBrowserSettings& settings, const CefPoint& inspect_element_at) =0; /// - // Explicitly close the developer tools window if one exists for this browser - // instance. + // Explicitly close the associated DevTools browser, if any. /// /*--cef()--*/ virtual void CloseDevTools() =0; + /// + // Returns true if this browser currently has an associated DevTools browser. + // Must be called on the browser process UI thread. + /// + /*--cef()--*/ + virtual bool HasDevTools() =0; + /// // Retrieve a snapshot of current navigation entries as values sent to the // specified visitor. If |current_only| is true only the current navigation diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index abd54dd49..071f15085 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -836,6 +836,15 @@ void CefBrowserHostImpl::CloseDevTools() { } } +bool CefBrowserHostImpl::HasDevTools() { + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "called on invalid thread"; + return false; + } + + return (devtools_frontend_ != nullptr); +} + void CefBrowserHostImpl::GetNavigationEntries( CefRefPtr visitor, bool current_only) { diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index eb89e1c03..4a9c96e99 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -180,6 +180,7 @@ class CefBrowserHostImpl : public CefBrowserHost, const CefBrowserSettings& settings, const CefPoint& inspect_element_at) override; void CloseDevTools() override; + bool HasDevTools() override; void GetNavigationEntries( CefRefPtr visitor, bool current_only) override; diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index 2c033d886..44ee9ce6e 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -425,19 +425,7 @@ void CEF_CALLBACK browser_host_show_dev_tools(struct _cef_browser_host_t* self, DCHECK(self); if (!self) return; - // Verify param: windowInfo; type: struct_byref_const - DCHECK(windowInfo); - if (!windowInfo) - return; - // Verify param: client; type: refptr_diff - DCHECK(client); - if (!client) - return; - // Verify param: settings; type: struct_byref_const - DCHECK(settings); - if (!settings) - return; - // Unverified params: inspect_element_at + // Unverified params: windowInfo, client, settings, inspect_element_at // Translate param: windowInfo; type: struct_byref_const CefWindowInfo windowInfoObj; @@ -471,6 +459,20 @@ void CEF_CALLBACK browser_host_close_dev_tools( CefBrowserHostCppToC::Get(self)->CloseDevTools(); } +int CEF_CALLBACK browser_host_has_dev_tools(struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefBrowserHostCppToC::Get(self)->HasDevTools(); + + // Return type: bool + return _retval; +} + void CEF_CALLBACK browser_host_get_navigation_entries( struct _cef_browser_host_t* self, cef_navigation_entry_visitor_t* visitor, int current_only) { @@ -962,6 +964,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC() { GetStruct()->stop_finding = browser_host_stop_finding; GetStruct()->show_dev_tools = browser_host_show_dev_tools; GetStruct()->close_dev_tools = browser_host_close_dev_tools; + GetStruct()->has_dev_tools = browser_host_has_dev_tools; GetStruct()->get_navigation_entries = browser_host_get_navigation_entries; GetStruct()->set_mouse_cursor_change_disabled = browser_host_set_mouse_cursor_change_disabled; diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc index c5fd38be4..36c0e57fd 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc @@ -375,11 +375,7 @@ void CefBrowserHostCToCpp::ShowDevTools(const CefWindowInfo& windowInfo, // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING - // Verify param: client; type: refptr_diff - DCHECK(client.get()); - if (!client.get()) - return; - // Unverified params: inspect_element_at + // Unverified params: windowInfo, client, settings, inspect_element_at // Execute _struct->show_dev_tools(_struct, @@ -400,6 +396,20 @@ void CefBrowserHostCToCpp::CloseDevTools() { _struct->close_dev_tools(_struct); } +bool CefBrowserHostCToCpp::HasDevTools() { + cef_browser_host_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, has_dev_tools)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = _struct->has_dev_tools(_struct); + + // Return type: bool + return _retval?true:false; +} + void CefBrowserHostCToCpp::GetNavigationEntries( CefRefPtr visitor, bool current_only) { cef_browser_host_t* _struct = GetStruct(); diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h index 8ee049cb3..cc03c437d 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.h +++ b/libcef_dll/ctocpp/browser_host_ctocpp.h @@ -63,6 +63,7 @@ class CefBrowserHostCToCpp CefRefPtr client, const CefBrowserSettings& settings, const CefPoint& inspect_element_at) OVERRIDE; void CloseDevTools() OVERRIDE; + bool HasDevTools() OVERRIDE; void GetNavigationEntries(CefRefPtr visitor, bool current_only) OVERRIDE; void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE; diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc index 4de9425f9..71b77f9d5 100644 --- a/tests/cefclient/browser/client_handler.cc +++ b/tests/cefclient/browser/client_handler.cc @@ -687,14 +687,33 @@ int ClientHandler::GetBrowserCount() const { void ClientHandler::ShowDevTools(CefRefPtr browser, const CefPoint& inspect_element_at) { + if (!CefCurrentlyOn(TID_UI)) { + // Execute this method on the UI thread. + CefPostTask(TID_UI, base::Bind(&ClientHandler::ShowDevTools, this, browser, + inspect_element_at)); + return; + } + CefWindowInfo windowInfo; CefRefPtr client; CefBrowserSettings settings; - if (CreatePopupWindow(browser, true, CefPopupFeatures(), windowInfo, client, - settings)) { - browser->GetHost()->ShowDevTools(windowInfo, client, settings, - inspect_element_at); + CefRefPtr host = browser->GetHost(); + + // Test if the DevTools browser already exists. + bool has_devtools = host->HasDevTools(); + if (!has_devtools) { + // Create a new RootWindow for the DevTools browser that will be created + // by ShowDevTools(). + has_devtools = CreatePopupWindow(browser, true, CefPopupFeatures(), + windowInfo, client, settings); + } + + if (has_devtools) { + // Create the DevTools browser if it doesn't already exist. + // Otherwise, focus the existing DevTools browser and inspect the element + // at |inspect_element_at| if non-empty. + host->ShowDevTools(windowInfo, client, settings, inspect_element_at); } }