Merge branch 'webview_window_handling'

Add wxWebView child window handling.

See #23334.
This commit is contained in:
Vadim Zeitlin 2023-03-12 13:58:01 +01:00
commit 1c0e4dbf8e
9 changed files with 528 additions and 85 deletions

View file

@ -37,14 +37,17 @@ __CRT_UUID_DECL(ICoreWebView2ExecuteScriptCompletedHandler, 0x49511172, 0xcc67,
__CRT_UUID_DECL(ICoreWebView2NavigationCompletedEventHandler, 0xd33a35bf, 0x1c49, 0x4f98, 0x93,0xab, 0x00,0x6e,0x05,0x33,0xfe,0x1c);
__CRT_UUID_DECL(ICoreWebView2NavigationStartingEventHandler, 0x9adbe429, 0xf36d, 0x432b, 0x9d,0xdc, 0xf8,0x88,0x1f,0xbd,0x76,0xe3);
__CRT_UUID_DECL(ICoreWebView2NewWindowRequestedEventHandler, 0xd4c185fe, 0xc81c, 0x4989, 0x97,0xaf, 0x2d,0x3f,0xa7,0xab,0x56,0x51);
__CRT_UUID_DECL(ICoreWebView2Settings3, 0xfdb5ab74, 0xaf33, 0x4854, 0x84,0xf0,0x0a,0x63,0x1d,0xeb,0x5e,0xba);
__CRT_UUID_DECL(ICoreWebView2SourceChangedEventHandler, 0x3c067f9f, 0x5388, 0x4772, 0x8b,0x48, 0x79,0xf7,0xef,0x1a,0xb3,0x7c);
__CRT_UUID_DECL(ICoreWebView2WebMessageReceivedEventHandler, 0x57213f19, 0x00e6, 0x49fa, 0x8e,0x07, 0x89,0x8e,0xa0,0x1e,0xcb,0xd2);
__CRT_UUID_DECL(ICoreWebView2WebResourceRequestedEventHandler, 0xab00b74c, 0x15f1, 0x4646, 0x80, 0xe8, 0xe7, 0x63, 0x41, 0xd2, 0x5d, 0x71);
__CRT_UUID_DECL(ICoreWebView2Settings3, 0xfdb5ab74, 0xaf33, 0x4854, 0x84,0xf0,0x0a,0x63,0x1d,0xeb,0x5e,0xba);
__CRT_UUID_DECL(ICoreWebView2WindowCloseRequestedEventHandler, 0x5c19e9e0,0x092f,0x486b, 0xaf,0xfa,0xca,0x82,0x31,0x91,0x30,0x39);
#endif
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxWebViewHandler>, wxStringToWebHandlerMap);
class wxWebViewEdgeParentWindowInfo;
class wxWebViewEdgeImpl
{
public:
@ -53,12 +56,15 @@ public:
bool Create();
wxWebViewEdge* CreateChildWebView(std::shared_ptr<wxWebViewEdgeParentWindowInfo> parentWindowInfo);
wxWebViewEdge* m_ctrl;
wxCOMPtr<ICoreWebView2Environment> m_webViewEnvironment;
wxCOMPtr<ICoreWebView2_2> m_webView;
wxCOMPtr<ICoreWebView2Controller> m_webViewController;
wxCOMPtr<ICoreWebView2EnvironmentOptions> m_webViewEnvironmentOptions;
std::shared_ptr<wxWebViewEdgeParentWindowInfo> m_parentWindowInfo;
bool m_initialized;
bool m_isBusy;
@ -85,6 +91,7 @@ public:
EventRegistrationToken m_containsFullScreenElementChangedToken = { };
EventRegistrationToken m_webMessageReceivedToken = { };
EventRegistrationToken m_webResourceRequestedToken = { };
EventRegistrationToken m_windowCloseRequestedToken = { };
// WebView Event handlers
HRESULT OnNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args);
@ -98,6 +105,7 @@ public:
HRESULT OnWebMessageReceived(ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args);
HRESULT OnWebResourceRequested(ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args);
HRESULT OnAddScriptToExecuteOnDocumentedCreatedCompleted(HRESULT errorCode, LPCWSTR id);
HRESULT OnWindowCloseRequested(ICoreWebView2* sender, IUnknown* args);
HRESULT OnEnvironmentCreated(HRESULT result, ICoreWebView2Environment* environment);
HRESULT OnWebViewCreated(HRESULT result, ICoreWebView2Controller* webViewController);

View file

@ -120,6 +120,8 @@ private:
void OnTopLevelParentIconized(wxIconizeEvent& event);
wxDECLARE_DYNAMIC_CLASS(wxWebViewEdge);
friend class wxWebViewEdgeImpl;
};
class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryEdge : public wxWebViewFactory

View file

@ -27,12 +27,18 @@
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxWebViewHandler>, wxStringToWebHandlerMap);
class wxWebViewWindowInfoWebKit;
class WXDLLIMPEXP_WEBVIEW wxWebViewWebKit : public wxWebView
{
public:
wxDECLARE_DYNAMIC_CLASS(wxWebViewWebKit);
wxWebViewWebKit() { Init(); }
wxWebViewWebKit(wxWebViewWindowInfoWebKit* parentWindowInfo = nullptr)
{
m_parentWindowInfo = parentWindowInfo;
Init();
}
wxWebViewWebKit(wxWindow *parent,
wxWindowID winID = wxID_ANY,
const wxString& strURL = wxASCII_STR(wxWebViewDefaultURLStr),
@ -118,6 +124,7 @@ private:
OSXWebViewPtr m_webView;
wxStringToWebHandlerMap m_handlers;
wxString m_customUserAgent;
wxWebViewWindowInfoWebKit* m_parentWindowInfo = nullptr;
WX_NSObject m_navigationDelegate;
WX_NSObject m_UIDelegate;

View file

@ -323,6 +323,27 @@ private:
wxDECLARE_ABSTRACT_CLASS(wxWebView);
};
class WXDLLIMPEXP_WEBVIEW wxWebViewWindowInfo
{
public:
virtual ~wxWebViewWindowInfo() = default;
virtual wxPoint GetPosition() const = 0;
virtual wxSize GetSize() const = 0;
virtual bool ShouldDisplayMenuBar() const = 0;
virtual bool ShouldDisplayStatusBar() const = 0;
virtual bool ShouldDisplayToolBar() const = 0;
virtual bool ShouldDisplayScrollBars() const = 0;
virtual wxWebView* CreateChildWebView() = 0;
};
class WXDLLIMPEXP_WEBVIEW wxWebViewEvent : public wxNotifyEvent
{
public:
@ -343,6 +364,7 @@ public:
wxWebViewNavigationActionFlags GetNavigationAction() const { return m_actionFlags; }
const wxString& GetMessageHandler() const { return m_messageHandler; }
wxWebViewWindowInfo* GetTargetWindowInfo() const { return (wxWebViewWindowInfo*)m_clientData; }
virtual wxEvent* Clone() const override { return new wxWebViewEvent(*this); }
private:
@ -359,6 +381,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NAVIGATED, wxWebVie
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_LOADED, wxWebViewEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_ERROR, wxWebViewEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, wxWebViewEvent);
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);

View file

@ -161,6 +161,91 @@ enum wxWebViewIE_EmulationLevel
wxWEBVIEWIE_EMU_IE11_FORCE = 11001
};
/**
A class describing the window information for a new child window.
This class is available via wxWebViewEvent::GetTargetWindowInfo()
while handling @c wxEVT_WEBVIEW_NEWWINDOW.
If the new window should be created use CreateChildWebView() while
processing the event. This will ensure that the new web view is
accessible from JavaScript within the originating wxWebView.
@since 3.3.0
*/
class WXDLLIMPEXP_WEBVIEW wxWebViewWindowInfo
{
public:
/**
Returns the position of the new window if specified by
a @c window.open() call.
*/
virtual wxPoint GetPosition() const = 0;
/**
Returns the size of the new window if specified by
a @c window.open() call.
*/
virtual wxSize GetSize() const = 0;
/**
Returns @true if the target window is expected to display
a menu bar as specified by a @c window.open() call.
*/
virtual bool ShouldDisplayMenuBar() const = 0;
/**
Returns @true if the target window is expected to display
a status bar as specified by a @c window.open() call.
*/
virtual bool ShouldDisplayStatusBar() const = 0;
/**
Returns @true if the target window is expected to display
a tool bar as specified by a @c window.open() call.
*/
virtual bool ShouldDisplayToolBar() const = 0;
/**
Returns @true if the target window is expected to display
scroll bars as specified by a @c window.open() call.
*/
virtual bool ShouldDisplayScrollBars() const = 0;
/**
Create a new child web view for the target window.
This @b must be created in the event handler for @c wxEVT_WEBVIEW_NEWWINDOW
and wxWebView::Create() @b must be called directly.
The requested URL will be loaded automatically in the new child web view.
Sample C++ code handling the event:
@code
// Bind handler
m_webView->Bind(wxEVT_WEBVIEW_NEWWINDOW, [](wxWebViewEvent& evt) {
// Get target window info
wxWebViewWindowInfo* info = evt.GetTargetWindowInfo();
// Create a top level window for the child web view
wxWindow* win = new wxWindow(this, wxID_ANY, info->GetPosition(), info->GetSize());
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
// Create the child web view
wxWebView* childWebView = info->CreateChildWebView();
// Place the child web view into the window
childWebView->Create(win, wxID_ANY);
sizer->Add(childWebView, 1, wxEXPAND);
});
@endcode
Sample JavaScript opening a new window:
@code
window.open("http://www.wxwidgets.org", "newWindow", "width=400,height=400");
@endcode
*/
virtual wxWebView* CreateChildWebView() = 0;
};
/**
@class wxWebViewHandlerRequest
@ -532,7 +617,7 @@ public:
/**
@class wxWebView
This control may be used to render web (HTML / CSS / javascript) documents.
This control may be used to render web (HTML / CSS / JavaScript) documents.
It is designed to allow the creation of multiple backends for each port,
although currently just one is available. It differs from wxHtmlWindow in
that each backend is actually a full rendering engine, Internet Explorer or Edge on MSW and
@ -707,7 +792,12 @@ public:
@event{EVT_WEBVIEW_NEWWINDOW(id, func)}
Process a @c wxEVT_WEBVIEW_NEWWINDOW event, generated when a new
window is created. You must handle this event if you want anything to
happen, for example to load the page in a new window or tab.
happen, for example to load the page in a new window or tab. For usage
details see wxWebViewWindowInfo::CreateChildWebView().
@event{wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED(id, func)}
Process a @c wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED event, generated when
a window is requested to be closed.
only available in wxWidgets 3.3.0 or later.
@event{EVT_WEBVIEW_TITLE_CHANGED(id, func)}
Process a @c wxEVT_WEBVIEW_TITLE_CHANGED event, generated when
the page title changes. Use GetString to get the title.
@ -1120,13 +1210,13 @@ public:
});
@endcode
Sample javascript sending a script message:
Sample JavaScript sending a script message:
@code
// Send sample message body
window.wx_msg.postMessage('This is a message body');
@endcode
@param name Name of the message handler that can be used from javascript
@param name Name of the message handler that can be used from JavaScript
@return @true if the handler could be added, @false if it could not be added.
@see RemoveScriptMessageHandler()
@ -1153,7 +1243,7 @@ public:
/**
Injects the specified script into the webpage's content.
@param javascript The javascript code to add.
@param javascript The JavaScript code to add.
@param injectionTime Specifies when the script will be executed.
@return Returns true if the script was added successfully.
@ -1599,7 +1689,12 @@ public:
@event{EVT_WEBVIEW_NEWWINDOW(id, func)}
Process a @c wxEVT_WEBVIEW_NEWWINDOW event, generated when a new
window is created. You must handle this event if you want anything to
happen, for example to load the page in a new window or tab.
happen, for example to load the page in a new window or tab. For usage
details see wxWebViewWindowInfo::CreateChildWebView().
@event{wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED(id, func)}
Process a @c wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED event, generated when
a window is requested to be closed.
only available in wxWidgets 3.3.0 or later.
@event{EVT_WEBVIEW_TITLE_CHANGED(id, func)}
Process a @c wxEVT_WEBVIEW_TITLE_CHANGED event, generated when
the page title changes. Use GetString to get the title.
@ -1661,6 +1756,17 @@ public:
*/
const wxString& GetMessageHandler() const;
/**
Get information about the target window. Only valid for events of type
@c wxEVT_WEBVIEW_NEWWINDOW
@note This is only available with the macOS and the Edge backend.
@see wxWebViewWindowInfo
@since 3.3.0
*/
wxWebViewWindowInfo* GetTargetWindowInfo() const;
/**
Returns true the script execution failed. Only valid for events of type
@c wxEVT_WEBVIEW_SCRIPT_RESULT

View file

@ -98,7 +98,7 @@ private:
class WebFrame : public wxFrame
{
public:
WebFrame(const wxString& url);
WebFrame(const wxString& url, bool isMain = true, wxWebViewWindowInfo* newWindowInfo = nullptr);
virtual ~WebFrame();
void UpdateState();
@ -118,6 +118,7 @@ public:
void OnFullScreenChanged(wxWebViewEvent& evt);
void OnScriptMessage(wxWebViewEvent& evt);
void OnScriptResult(wxWebViewEvent& evt);
void OnWindowCloseRequested(wxWebViewEvent& evt);
void OnSetPage(wxCommandEvent& evt);
void OnViewSourceRequest(wxCommandEvent& evt);
void OnViewTextRequest(wxCommandEvent& evt);
@ -176,6 +177,7 @@ public:
private:
wxTextCtrl* m_url;
wxWebView* m_browser;
bool m_isMainFrame;
wxToolBar* m_toolbar;
wxToolBarToolBase* m_toolbar_back;
@ -332,9 +334,11 @@ bool WebApp::OnInit()
return true;
}
WebFrame::WebFrame(const wxString& url) :
WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWindowInfo) :
wxFrame(nullptr, wxID_ANY, "wxWebView Sample")
{
m_isMainFrame = isMain;
// set the frame icon
SetIcon(wxICON(sample));
SetTitle("wxWebView Sample");
@ -349,7 +353,7 @@ WebFrame::WebFrame(const wxString& url) :
m_toolbar_forward = m_toolbar->AddTool(wxID_ANY, _("Forward"), wxArtProvider::GetBitmapBundle(wxART_GO_FORWARD, wxART_TOOLBAR));
m_toolbar_stop = m_toolbar->AddTool(wxID_ANY, _("Stop"), wxArtProvider::GetBitmapBundle(wxART_STOP, wxART_TOOLBAR));
m_toolbar_reload = m_toolbar->AddTool(wxID_ANY, _("Reload"), wxArtProvider::GetBitmapBundle(wxART_REFRESH, wxART_TOOLBAR));
m_url = new wxTextCtrl(m_toolbar, wxID_ANY, "", wxDefaultPosition, FromDIP(wxSize(400, -1)), wxTE_PROCESS_ENTER );
m_url = new wxTextCtrl(m_toolbar, wxID_ANY, "", wxDefaultPosition, FromDIP(wxSize(400, -1)), wxTE_PROCESS_ENTER);
m_toolbar->AddControl(m_url, _("URL"));
m_toolbar_tools = m_toolbar->AddTool(wxID_ANY, _("Menu"), wxArtProvider::GetBitmapBundle(wxART_WX_LOGO, wxART_TOOLBAR));
@ -400,7 +404,8 @@ WebFrame::WebFrame(const wxString& url) :
topsizer->Add(m_info, wxSizerFlags().Expand());
// Create a log window
new wxLogWindow(this, _("Logging"), true, false);
if (m_isMainFrame)
new wxLogWindow(this, _("Logging"), true, false);
#if wxUSE_WEBVIEW_EDGE
// Check if a fixed version of edge is present in
@ -415,30 +420,50 @@ WebFrame::WebFrame(const wxString& url) :
}
#endif
// Create the webview
m_browser = wxWebView::New();
m_browser = (newWindowInfo) ? newWindowInfo->CreateChildWebView() : wxWebView::New();
#ifdef __WXMAC__
// With WKWebView handlers need to be registered before creation
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
if (m_isMainFrame)
{
// With WKWebView handlers need to be registered before creation
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
}
#endif
m_browser->Create(this, wxID_ANY, url, wxDefaultPosition, wxDefaultSize);
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
// Log backend information
wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(),
wxWebView::GetBackendVersionInfo().ToString());
wxLogMessage("User Agent: %s", m_browser->GetUserAgent());
if (newWindowInfo)
{
if (newWindowInfo->GetSize().IsFullySpecified())
SetSize(FromDIP(newWindowInfo->GetSize()));
if (newWindowInfo->GetPosition().IsFullySpecified())
Move(FromDIP(newWindowInfo->GetPosition()));
if (!newWindowInfo->ShouldDisplayToolBar())
m_toolbar->Hide();
if (!newWindowInfo->ShouldDisplayMenuBar())
SetMenuBar(nullptr);
}
if (m_isMainFrame)
{
// Log backend information
wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(),
wxWebView::GetBackendVersionInfo().ToString());
wxLogMessage("User Agent: %s", m_browser->GetUserAgent());
#ifndef __WXMAC__
//We register the wxfs:// protocol for testing purposes
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
//And the memory: file system
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
//We register the wxfs:// protocol for testing purposes
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
//And the memory: file system
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
#endif
if (!m_browser->AddScriptMessageHandler("wx"))
wxLogError("Could not add script message handler");
if (!m_browser->AddScriptMessageHandler("wx"))
wxLogError("Could not add script message handler");
}
else
wxLogMessage("Created new window");
SetSizer(topsizer);
@ -581,6 +606,7 @@ WebFrame::WebFrame(const wxString& url) :
Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &WebFrame::OnFullScreenChanged, this, m_browser->GetId());
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebFrame::OnScriptMessage, this, m_browser->GetId());
Bind(wxEVT_WEBVIEW_SCRIPT_RESULT, &WebFrame::OnScriptResult, this, m_browser->GetId());
Bind(wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, &WebFrame::OnWindowCloseRequested, this, m_browser->GetId());
// Connect the menu events
Bind(wxEVT_MENU, &WebFrame::OnSetPage, this, setPage->GetId());
@ -947,11 +973,20 @@ void WebFrame::OnNewWindow(wxWebViewEvent& evt)
}
wxLogMessage("%s", "New window; url='" + evt.GetURL() + "'" + flag);
wxWebViewWindowInfo* info = evt.GetTargetWindowInfo();
if (info)
{
wxLogMessage(" New window info: Position=%d,%d Size=%d,%d",
info->GetPosition().x, info->GetPosition().y,
info->GetSize().GetWidth(), info->GetSize().GetHeight());
}
//If we handle new window events then just load them in this window as we
//are a single window browser
if(m_tools_handle_new_window->IsChecked())
m_browser->LoadURL(evt.GetURL());
//If we handle new window events then create a new frame
if (m_tools_handle_new_window->IsChecked())
{
WebFrame* newFrame = new WebFrame(evt.GetURL(), false, info);
newFrame->Show();
}
UpdateState();
}
@ -981,6 +1016,13 @@ void WebFrame::OnScriptResult(wxWebViewEvent& evt)
wxLogMessage("Async script result received; value = %s", evt.GetString());
}
void WebFrame::OnWindowCloseRequested(wxWebViewEvent& WXUNUSED(evt))
{
wxLogMessage("Window close requested");
if (!m_isMainFrame)
Close();
}
void WebFrame::OnSetPage(wxCommandEvent& WXUNUSED(evt))
{
m_browser->SetPage

View file

@ -49,6 +49,7 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_NAVIGATED, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_LOADED, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_ERROR, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent );
wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);

View file

@ -252,6 +252,114 @@ public:
wxCOMPtr<ICoreWebView2WebResourceRequestedEventArgs> m_args;
};
// wxWebViewNewWindowInfoEdge
class wxWebViewNewWindowInfoEdge : public wxWebViewWindowInfo
{
public:
wxWebViewNewWindowInfoEdge(wxWebViewEdgeImpl* impl, ICoreWebView2NewWindowRequestedEventArgs* args):
m_impl(impl),
m_args(args)
{
m_args->get_WindowFeatures(&m_windowFeatures);
}
virtual wxPoint GetPosition() const override
{
wxPoint result(-1, -1);
BOOL hasPosition;
if (SUCCEEDED(m_windowFeatures->get_HasPosition(&hasPosition)) && hasPosition)
{
UINT32 x, y;
if (SUCCEEDED(m_windowFeatures->get_Left(&x)) &&
SUCCEEDED(m_windowFeatures->get_Top(&y)))
result = wxPoint(x, y);
}
return result;
}
virtual wxSize GetSize() const override
{
wxSize result(-1, -1);
BOOL hasSize;
if (SUCCEEDED(m_windowFeatures->get_HasSize(&hasSize)) && hasSize)
{
UINT32 width, height;
if (SUCCEEDED(m_windowFeatures->get_Width(&width)) &&
SUCCEEDED(m_windowFeatures->get_Height(&height)))
result = wxSize(width, height);
}
return result;
}
virtual bool ShouldDisplayMenuBar() const override
{
BOOL result;
if (SUCCEEDED(m_windowFeatures->get_ShouldDisplayMenuBar(&result)))
return result;
else
return true;
}
virtual bool ShouldDisplayStatusBar() const override
{
BOOL result;
if (SUCCEEDED(m_windowFeatures->get_ShouldDisplayStatus(&result)))
return result;
else
return true;
}
virtual bool ShouldDisplayToolBar() const override
{
BOOL result;
if (SUCCEEDED(m_windowFeatures->get_ShouldDisplayToolbar(&result)))
return result;
else
return true;
}
virtual bool ShouldDisplayScrollBars() const override
{
BOOL result;
if (SUCCEEDED(m_windowFeatures->get_ShouldDisplayScrollBars(&result)))
return result;
else
return true;
}
virtual wxWebView* CreateChildWebView() override
{
return m_impl->CreateChildWebView(
std::make_shared<wxWebViewEdgeParentWindowInfo>(m_impl, m_args));
}
private:
wxWebViewEdgeImpl* m_impl;
wxCOMPtr<ICoreWebView2NewWindowRequestedEventArgs> m_args;
wxCOMPtr<ICoreWebView2WindowFeatures> m_windowFeatures;
};
class wxWebViewEdgeParentWindowInfo
{
public:
wxWebViewEdgeParentWindowInfo(wxWebViewEdgeImpl* impl,
ICoreWebView2NewWindowRequestedEventArgs* args):
m_impl(impl),
m_args(args)
{
HRESULT hr = m_args->GetDeferral(&m_deferral);
if (FAILED(hr))
wxLogApiError("GetDeferral", hr);
}
virtual ~wxWebViewEdgeParentWindowInfo() = default;
wxWebViewEdgeImpl* m_impl;
wxCOMPtr<ICoreWebView2NewWindowRequestedEventArgs> m_args;
wxCOMPtr<ICoreWebView2Deferral> m_deferral;
};
#define wxWEBVIEW_EDGE_EVENT_HANDLER_METHOD \
m_inEventCallback = true; \
wxON_BLOCK_EXIT_SET(m_inEventCallback, false);
@ -280,6 +388,7 @@ wxWebViewEdgeImpl::~wxWebViewEdgeImpl()
m_webView->remove_ContainsFullScreenElementChanged(m_containsFullScreenElementChangedToken);
m_webView->remove_WebMessageReceived(m_webMessageReceivedToken);
m_webView->remove_WebResourceRequested(m_webResourceRequestedToken);
m_webView->remove_WindowCloseRequested(m_windowCloseRequestedToken);
}
}
@ -298,19 +407,34 @@ bool wxWebViewEdgeImpl::Create()
wxString userDataPath = wxStandardPaths::Get().GetUserLocalDataDir();
HRESULT hr = wxCreateCoreWebView2EnvironmentWithOptions(
ms_browserExecutableDir.wc_str(),
userDataPath.wc_str(),
m_webViewEnvironmentOptions,
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(this,
&wxWebViewEdgeImpl::OnEnvironmentCreated).Get());
if (FAILED(hr))
if (m_parentWindowInfo)
{
wxLogApiError("CreateWebView2EnvironmentWithOptions", hr);
return false;
OnEnvironmentCreated(S_OK, m_parentWindowInfo->m_impl->m_webViewEnvironment);
return true;
}
else
return true;
{
HRESULT hr = wxCreateCoreWebView2EnvironmentWithOptions(
ms_browserExecutableDir.wc_str(),
userDataPath.wc_str(),
m_webViewEnvironmentOptions,
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(this,
&wxWebViewEdgeImpl::OnEnvironmentCreated).Get());
if (FAILED(hr))
{
wxLogApiError("CreateWebView2EnvironmentWithOptions", hr);
return false;
}
else
return true;
}
}
wxWebViewEdge* wxWebViewEdgeImpl::CreateChildWebView(std::shared_ptr<wxWebViewEdgeParentWindowInfo> parentWindowInfo)
{
wxWebViewEdge* childWebView = new wxWebViewEdge();
childWebView->m_impl->m_parentWindowInfo = parentWindowInfo;
return childWebView;
}
HRESULT wxWebViewEdgeImpl::OnEnvironmentCreated(
@ -493,6 +617,7 @@ HRESULT wxWebViewEdgeImpl::OnNavigationCompleted(ICoreWebView2* WXUNUSED(sender)
HRESULT wxWebViewEdgeImpl::OnNewWindowRequested(ICoreWebView2* WXUNUSED(sender), ICoreWebView2NewWindowRequestedEventArgs* args)
{
wxWEBVIEW_EDGE_EVENT_HANDLER_METHOD
wxCoTaskMemPtr<wchar_t> uri;
wxString evtURL;
if (SUCCEEDED(args->get_Uri(&uri)))
@ -503,12 +628,21 @@ HRESULT wxWebViewEdgeImpl::OnNewWindowRequested(ICoreWebView2* WXUNUSED(sender),
if (SUCCEEDED(args->get_IsUserInitiated(&isUserInitiated)) && isUserInitiated)
navFlags = wxWEBVIEW_NAV_ACTION_USER;
wxWebViewEvent evt(wxEVT_WEBVIEW_NEWWINDOW, m_ctrl->GetId(), evtURL, wxString(), navFlags);
m_ctrl->GetEventHandler()->AddPendingEvent(evt);
wxWebViewNewWindowInfoEdge windowInfo(this, args);
wxWebViewEvent evt(wxEVT_WEBVIEW_NEWWINDOW, m_ctrl->GetId(), evtURL, wxString(), navFlags, "");
evt.SetClientData(&windowInfo);
m_ctrl->HandleWindowEvent(evt);
args->put_Handled(true);
return S_OK;
}
HRESULT wxWebViewEdgeImpl::OnWindowCloseRequested(ICoreWebView2* WXUNUSED(sender), IUnknown* WXUNUSED(args))
{
wxWebViewEvent evt(wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, m_ctrl->GetId(), m_ctrl->GetCurrentURL(), "");
m_ctrl->GetEventHandler()->AddPendingEvent(evt);
return S_OK;
}
HRESULT wxWebViewEdgeImpl::OnDocumentTitleChanged(ICoreWebView2* WXUNUSED(sender), IUnknown* WXUNUSED(args))
{
wxWebViewEvent event(wxEVT_WEBVIEW_TITLE_CHANGED,
@ -675,6 +809,10 @@ HRESULT wxWebViewEdgeImpl::OnWebViewCreated(HRESULT result, ICoreWebView2Control
Callback<ICoreWebView2WebResourceRequestedEventHandler>(
this, &wxWebViewEdgeImpl::OnWebResourceRequested).Get(),
&m_webResourceRequestedToken);
m_webView->add_WindowCloseRequested(
Callback<ICoreWebView2WindowCloseRequestedEventHandler>(
this, &wxWebViewEdgeImpl::OnWindowCloseRequested).Get(),
&m_windowCloseRequestedToken);
// Register handlers
for (wxStringToWebHandlerMap::iterator it = m_handlers.begin(); it != m_handlers.end(); it++)
@ -722,6 +860,17 @@ HRESULT wxWebViewEdgeImpl::OnWebViewCreated(HRESULT result, ICoreWebView2Control
m_pendingUserScripts.clear();
}
if (m_parentWindowInfo)
{
if (FAILED(m_parentWindowInfo->m_args->put_NewWindow(baseWebView)))
wxLogApiError("WebView2::WebViewCreated (put_NewWindow)", hr);
if (FAILED(m_parentWindowInfo->m_deferral->Complete()))
wxLogApiError("WebView2::WebViewCreated (Complete)", hr);
m_parentWindowInfo.reset();
return S_OK;
}
if (!m_pendingURL.empty())
{
m_ctrl->LoadURL(m_pendingURL);

View file

@ -110,6 +110,86 @@ wxVersionInfo wxWebViewFactoryWebKit::GetVersionInfo()
return wxVersionInfo("WKWebView", verMaj, verMin, verMicro);
}
//-----------------------------------------------------------------------------
// wxWebViewWindowInfoWebKit
//-----------------------------------------------------------------------------
class wxWebViewWindowInfoWebKit: public wxWebViewWindowInfo
{
public:
wxWebViewWindowInfoWebKit(WKWebViewConfiguration* configuration,
WKNavigationAction* navigationAction,
WKWindowFeatures* windowFeatures):
m_configuration(configuration),
m_navigationAction(navigationAction),
m_windowFeatures(windowFeatures)
{
}
virtual wxPoint GetPosition() const override
{
wxPoint pos(-1, -1);
if (m_windowFeatures.y)
pos.y = m_windowFeatures.y.intValue;
if (m_windowFeatures.x)
pos.x = m_windowFeatures.x.intValue;
return pos;
}
virtual wxSize GetSize() const override
{
wxSize size(-1, -1);
if (m_windowFeatures.height)
size.y = m_windowFeatures.height.intValue;
if (m_windowFeatures.width)
size.x = m_windowFeatures.width.intValue;
return size;
}
virtual bool ShouldDisplayMenuBar() const override
{
if (m_windowFeatures.menuBarVisibility)
return m_windowFeatures.menuBarVisibility.boolValue;
else
return true;
}
virtual bool ShouldDisplayStatusBar() const override
{
if (m_windowFeatures.statusBarVisibility)
return m_windowFeatures.statusBarVisibility.boolValue;
else
return true;
}
virtual bool ShouldDisplayToolBar() const override
{
if (m_windowFeatures.toolbarsVisibility)
return m_windowFeatures.toolbarsVisibility.boolValue;
else
return true;
}
virtual bool ShouldDisplayScrollBars() const override
{
return true;
}
virtual wxWebView* CreateChildWebView() override
{
m_childWebView = new wxWebViewWebKit(this);
return m_childWebView;
}
wxWebView* m_childWebView = nullptr;
WKWebViewConfiguration* m_configuration;
WKNavigationAction* m_navigationAction;
WKWindowFeatures* m_windowFeatures;
};
// ----------------------------------------------------------------------------
// creation/destruction
// ----------------------------------------------------------------------------
@ -130,9 +210,10 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
wxControl::Create(parent, winID, pos, size, style, wxDefaultValidator, name);
NSRect r = wxOSXGetFrameForControl( this, pos , size ) ;
WKWebViewConfiguration* webViewConfig = (WKWebViewConfiguration*) m_webViewConfiguration;
WKWebViewConfiguration* webViewConfig = (m_parentWindowInfo) ?
m_parentWindowInfo->m_configuration : (WKWebViewConfiguration*) m_webViewConfiguration;
if (!m_handlers.empty())
if (!m_handlers.empty() && !m_parentWindowInfo)
{
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
if ( WX_IS_MACOS_AVAILABLE(10, 13) )
@ -154,9 +235,12 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
MacPostControlCreate(pos, size);
// WKWebView configuration is only used during creation
[m_webViewConfiguration release];
m_webViewConfiguration = nil;
if (!m_parentWindowInfo)
{
// WKWebView configuration is only used during creation
[m_webViewConfiguration release];
m_webViewConfiguration = nil;
}
if (!m_customUserAgent.empty())
SetUserAgent(m_customUserAgent);
@ -178,45 +262,51 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
[m_webView setUIDelegate:uiDelegate];
// Implement javascript fullscreen interface with user script and message handler
AddUserScript("\
document.__wxToggleFullscreen = function (elem) { \
if (!document.__wxStylesAdded) { \
function createClass(name,rules) { \
var style= document.createElement('style'); style.type = 'text/css'; \
document.getElementsByTagName('head')[0].appendChild(style); \
style.sheet.addRule(name, rules); \
if (!m_parentWindowInfo)
{
// Implement javascript fullscreen interface with user script and message handler
AddUserScript("\
document.__wxToggleFullscreen = function (elem) { \
if (!document.__wxStylesAdded) { \
function createClass(name,rules) { \
var style= document.createElement('style'); style.type = 'text/css'; \
document.getElementsByTagName('head')[0].appendChild(style); \
style.sheet.addRule(name, rules); \
} \
createClass(\"body.wxfullscreen\", \"padding: 0; margin: 0; height: 100%;\"); \
createClass(\".wxfullscreen\", \"position: fixed; overflow: hidden; z-index: 1000; left: 0; top: 0; bottom: 0; right: 0;\"); \
createClass(\".wxfullscreenelem\", \"width: 100% !important; height: 100% !important; padding-top: 0 !important;\"); \
document.__wxStylesAdded = true; \
} \
createClass(\"body.wxfullscreen\", \"padding: 0; margin: 0; height: 100%;\"); \
createClass(\".wxfullscreen\", \"position: fixed; overflow: hidden; z-index: 1000; left: 0; top: 0; bottom: 0; right: 0;\"); \
createClass(\".wxfullscreenelem\", \"width: 100% !important; height: 100% !important; padding-top: 0 !important;\"); \
document.__wxStylesAdded = true; \
} \
if (elem) { \
elem.classList.add(\"wxfullscreen\"); \
elem.classList.add(\"wxfullscreenelem\"); \
document.body.classList.add(\"wxfullscreen\"); \
} else if (document.webkitFullscreenElement) { \
document.webkitFullscreenElement.classList.remove(\"wxfullscreen\"); \
document.webkitFullscreenElement.classList.remove(\"wxfullscreenelem\"); \
document.body.classList.remove(\"wxfullscreen\"); \
} \
document.webkitFullscreenElement = elem; \
window.webkit.messageHandlers.__wxfullscreen.postMessage((elem) ? 1: 0); \
document.dispatchEvent(new Event('webkitfullscreenchange')); \
if (document.onwebkitfullscreenchange) document.onwebkitfullscreenchange(); \
}; \
Element.prototype.webkitRequestFullscreen = function() {document.__wxToggleFullscreen(this);}; \
document.webkitExitFullscreen = function() {document.__wxToggleFullscreen(undefined);}; \
document.onwebkitfullscreenchange = null; \
document.webkitFullscreenEnabled = true; \
");
[m_webView.configuration.userContentController addScriptMessageHandler:
[[WebViewScriptMessageHandler alloc] initWithWxWindow:this] name:@"__wxfullscreen"];
if (elem) { \
elem.classList.add(\"wxfullscreen\"); \
elem.classList.add(\"wxfullscreenelem\"); \
document.body.classList.add(\"wxfullscreen\"); \
} else if (document.webkitFullscreenElement) { \
document.webkitFullscreenElement.classList.remove(\"wxfullscreen\"); \
document.webkitFullscreenElement.classList.remove(\"wxfullscreenelem\"); \
document.body.classList.remove(\"wxfullscreen\"); \
} \
document.webkitFullscreenElement = elem; \
window.webkit.messageHandlers.__wxfullscreen.postMessage((elem) ? 1: 0); \
document.dispatchEvent(new Event('webkitfullscreenchange')); \
if (document.onwebkitfullscreenchange) document.onwebkitfullscreenchange(); \
}; \
Element.prototype.webkitRequestFullscreen = function() {document.__wxToggleFullscreen(this);}; \
document.webkitExitFullscreen = function() {document.__wxToggleFullscreen(undefined);}; \
document.onwebkitfullscreenchange = null; \
document.webkitFullscreenEnabled = true; \
");
[m_webView.configuration.userContentController addScriptMessageHandler:
[[WebViewScriptMessageHandler alloc] initWithWxWindow:this] name:@"__wxfullscreen"];
}
m_UIDelegate = uiDelegate;
LoadURL(strURL);
if (m_parentWindowInfo)
[m_webView loadRequest:m_parentWindowInfo->m_navigationAction.request];
else
LoadURL(strURL);
return true;
}
@ -1013,15 +1103,30 @@ WX_API_AVAILABLE_MACOS(10, 13)
wxWEBVIEW_NAV_ACTION_USER :
wxWEBVIEW_NAV_ACTION_OTHER;
wxWebViewWindowInfoWebKit windowInfo(configuration, navigationAction, windowFeatures);
wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
webKitWindow->GetId(),
wxCFStringRef::AsString( navigationAction.request.URL.absoluteString ),
"", navFlags);
event.SetClientData(&windowInfo);
if (webKitWindow && webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent(event);
return nil;
if (windowInfo.m_childWebView)
return (WKWebView*) windowInfo.m_childWebView->GetNativeBackend();
else
return nil;
}
- (void)webViewDidClose:(WKWebView *)webView
{
wxWebViewEvent event(wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED,
webKitWindow->GetId(), "", "");
if (webKitWindow && webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent(event);
}
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message