From e9dc74cb6d88b7f384b65ce5e84c93113d814791 Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Wed, 7 Apr 2021 22:21:04 +0200 Subject: [PATCH] Add wxWebView::RunScriptAsync() --- include/wx/msw/webview_edge.h | 2 +- include/wx/webview.h | 9 +++++- src/common/webview.cpp | 46 ++++++++++++++++++++++++++++++ src/msw/webview_edge.cpp | 53 +++++++++++++---------------------- 4 files changed, 74 insertions(+), 36 deletions(-) diff --git a/include/wx/msw/webview_edge.h b/include/wx/msw/webview_edge.h index e04748f463..d84b74d927 100644 --- a/include/wx/msw/webview_edge.h +++ b/include/wx/msw/webview_edge.h @@ -88,7 +88,7 @@ public: virtual bool SetUserAgent(const wxString& userAgent) wxOVERRIDE; - virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const wxOVERRIDE; + virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const wxOVERRIDE; virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE; virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE; virtual bool AddUserScript(const wxString& javascript, diff --git a/include/wx/webview.h b/include/wx/webview.h index 43a3bf39c1..d557d8483c 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -191,7 +191,8 @@ public: virtual wxString GetUserAgent() const; // Script - virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const = 0; + virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const; + virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const; virtual bool AddScriptMessageHandler(const wxString& name) { wxUnusedVar(name); return false; } virtual bool RemoveScriptMessageHandler(const wxString& name) @@ -267,6 +268,9 @@ protected: bool QueryCommandEnabled(const wxString& command) const; void ExecCommand(const wxString& command); + void SendScriptResult(void* clientData, bool success, + const wxString& output) const; + // Count the number of calls to RunScript() in order to prevent // the_same variable from being used twice in more than one call. mutable int m_runScriptCount; @@ -276,6 +280,8 @@ private: static wxStringWebViewFactoryMap::iterator FindFactory(const wxString &backend); bool m_showMenu; + mutable int m_syncScriptResult; + mutable wxString m_syncScriptOutput; wxString m_findText; static wxStringWebViewFactoryMap m_factoryMap; @@ -319,6 +325,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NEWWINDOW, wxWebVie wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent); +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent); typedef void (wxEvtHandler::*wxWebViewEventFunction) (wxWebViewEvent&); diff --git a/src/common/webview.cpp b/src/common/webview.cpp index dacd00653a..1b6945c934 100644 --- a/src/common/webview.cpp +++ b/src/common/webview.cpp @@ -50,6 +50,7 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent); wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent); +wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent); wxStringWebViewFactoryMap wxWebView::m_factoryMap; @@ -224,6 +225,51 @@ wxString wxWebView::GetUserAgent() const return userAgent; } +bool wxWebView::RunScript(const wxString& javascript, wxString* output) const +{ + m_syncScriptResult = -1; + m_syncScriptOutput.Clear(); + RunScriptAsync(javascript, (void*)this); + + // Wait for script exection + while (m_syncScriptResult == -1) + wxYield(); + + if (m_syncScriptResult && output) + *output = m_syncScriptOutput; + return m_syncScriptResult == 1; +} + +void wxWebView::RunScriptAsync(const wxString& WXUNUSED(javascript), + void* WXUNUSED(clientData)) const +{ + wxLogError(_("RunScriptAsync not supported")); +} + +void wxWebView::SendScriptResult(void* clientData, bool success, + const wxString& output) const +{ + // If currently running sync RunScript() don't send an event, but use + // the scripts result directly + if (m_syncScriptResult == -1) + { + if (!success) + wxLogWarning(_("Error running JavaScript: %s"), output); + m_syncScriptOutput = output; + m_syncScriptResult = success; + } + else + { + wxWebViewEvent evt(wxEVT_WEBVIEW_SCRIPT_RESULT, GetId(), "", "", + wxWEBVIEW_NAV_ACTION_NONE); + evt.SetEventObject(const_cast(this)); + evt.SetClientData(clientData); + evt.SetInt(success); + evt.SetString(output); + HandleWindowEvent(evt); + } +} + // static wxWebView* wxWebView::New(const wxString& backend) { diff --git a/src/msw/webview_edge.cpp b/src/msw/webview_edge.cpp index 9dce63b27b..c26c5f35df 100644 --- a/src/msw/webview_edge.cpp +++ b/src/msw/webview_edge.cpp @@ -831,61 +831,46 @@ void wxWebViewEdge::MSWSetBrowserExecutableDir(const wxString & path) wxWebViewEdgeImpl::ms_browserExecutableDir = path; } -bool wxWebViewEdge::RunScript(const wxString& javascript, wxString* output) const +void wxWebViewEdge::RunScriptAsync(const wxString& javascript, void* clientData) const { if (!m_impl->m_webView) - return false; + { + SendScriptResult(clientData, false, ""); + return; // TODO: postpone execution + } wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING); - int scriptResult = -1; - wxString scriptOutput; - // Start script execution HRESULT executionResult = m_impl->m_webView->ExecuteScript(wrapJS.GetWrappedCode().wc_str(), Callback( - [&scriptResult, &executionResult, &scriptOutput](HRESULT error, PCWSTR result) -> HRESULT + [this, clientData](HRESULT error, PCWSTR result) -> HRESULT { // Handle script execution callback if (error == S_OK) { - scriptOutput.assign(result); - scriptResult = 1; + wxString scriptDecodedResult; + // Try to decode JSON string or return original + // result if it's not a valid JSON string + if (!wxJSON::DecodeString(result, &scriptDecodedResult)) + scriptDecodedResult = result; + + wxString scriptExtractedOutput; + bool success = wxJSScriptWrapper::ExtractOutput(scriptDecodedResult, &scriptExtractedOutput); + SendScriptResult(clientData, success, scriptExtractedOutput); } else { - executionResult = error; - scriptResult = 0; + SendScriptResult(clientData, false, wxString::Format("%s (0x%08lx)", + wxSysErrorMsgStr(error), error)); } return S_OK; }).Get()); - - // Wait for script exection - while (scriptResult == -1) - wxYield(); - if (FAILED(executionResult)) { - if (output) - output->Printf("%s (0x%08lx)", wxSysErrorMsgStr(executionResult), executionResult); - return false; + SendScriptResult(clientData, false, wxString::Format("%s (0x%08lx)", + wxSysErrorMsgStr(executionResult), executionResult)); } - - wxString scriptDecodedResult; - // Try to decode JSON string or return original - // result if it's not a valid JSON string - if (!wxJSON::DecodeString(scriptOutput, &scriptDecodedResult)) - scriptDecodedResult = scriptOutput; - - wxString scriptExtractedOutput; - bool success = wxJSScriptWrapper::ExtractOutput(scriptDecodedResult, &scriptExtractedOutput); - if (!success) - wxLogWarning(_("Error running JavaScript: %s"), scriptExtractedOutput); - - if (output) - *output = scriptDecodedResult; - - return success; } bool wxWebViewEdge::AddScriptMessageHandler(const wxString& name)