diff --git a/include/wx/webview_chromium.h b/include/wx/webview_chromium.h index 14840691f5..c72ff41b4a 100644 --- a/include/wx/webview_chromium.h +++ b/include/wx/webview_chromium.h @@ -118,10 +118,18 @@ public: //Virtual Filesystem Support virtual void RegisterHandler(wxSharedPtr handler) override; +#ifdef __WXGTK__ + virtual void GTKHandleRealized() override; +#endif + protected: virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override; private: + // Actually create the browser: this can only be done once the window is + // created in wxGTK. + bool DoCreateBrowser(const wxString& url); + //History related variables, we currently use our own implementation wxVector > m_historyList; int m_historyPosition; @@ -142,6 +150,10 @@ private: friend class ClientHandler; ClientHandler* m_clientHandler; +#ifdef __WXGTK__ + wxString m_url; +#endif + friend class wxWebViewChromiumModule; static bool ms_cefInitialized; diff --git a/interface/wx/webview_chromium.h b/interface/wx/webview_chromium.h index d1ac554215..b036a1479b 100644 --- a/interface/wx/webview_chromium.h +++ b/interface/wx/webview_chromium.h @@ -64,6 +64,23 @@ Only Microsoft Visual C++ 2015 or newer can be used to build wxWebViewChromium. + __Linux with GTK__ + + wxWebviewChromium currently only supports X11 and not Wayland, i.e. you + need to either ensure that `GDK_BACKEND` environment variable is set to + "x11" before running your program using it or call + + @code + gdk_set_allowed_backends("x11") + @endcode + + in your application code. + + Moreover, the actual browser is only created once the window is shown, and + can't be used until then. You can bind an event handler for wxEVT_CREATE to + know when it is usable. + + __Mac OS X Platform__ OS X 10.9 or above is required. diff --git a/samples/webview/webview.cpp b/samples/webview/webview.cpp index 0832a8445e..2cfb7f4e14 100644 --- a/samples/webview/webview.cpp +++ b/samples/webview/webview.cpp @@ -460,14 +460,17 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowFeatures* wi m_browser->RegisterHandler(wxSharedPtr(new AdvancedWebViewHandler())); } #endif - m_browser->Create(this, wxID_ANY, url, wxDefaultPosition, + if ( !m_browser->Create(this, wxID_ANY, url, wxDefaultPosition, #if defined(wxWEBVIEW_SAMPLE_CHROMIUM) && defined(__WXOSX__) // OSX implementation currently cannot handle the default size wxSize(800, 600) #else wxDefaultSize #endif - ); + ) ) + { + wxLogFatalError("Failed to create wxWebView"); + } topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); @@ -476,7 +479,14 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowFeatures* wi // Log backend information wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(), wxWebView::GetBackendVersionInfo().ToString()); - wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); + + // Chromium backend can't be used immediately after creation, so wait + // until the browser is created before calling GetUserAgent(). + m_browser->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent& event) { + wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); + + event.Skip(); + }); #ifndef __WXMAC__ //We register the wxfs:// protocol for testing purposes diff --git a/src/common/webview_chromium.cpp b/src/common/webview_chromium.cpp index 8ef0981c9b..4d1e37ffe9 100644 --- a/src/common/webview_chromium.cpp +++ b/src/common/webview_chromium.cpp @@ -305,20 +305,18 @@ bool wxWebViewChromium::Create(wxWindow* parent, const wxString& name) { #ifdef __WXGTK__ - style |= wxHSCROLL | wxVSCROLL; - if ( !PreCreation( parent, pos, size ) || - !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ) ) - { - wxFAIL_MSG( wxT("wxWebViewChromium creation failed") ); + // Currently CEF works only with X11. + if ( wxGetDisplayInfo().type != wxDisplayX11 ) return false; - } -#else + + style |= wxHSCROLL | wxVSCROLL; +#endif + if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) ) { return false; } -#endif if ( !InitCEF() ) return false; @@ -331,46 +329,51 @@ bool wxWebViewChromium::Create(wxWindow* parent, m_historyPosition = -1; m_zoomLevel = wxWEBVIEW_ZOOM_MEDIUM; - CefBrowserSettings browsersettings; - CefWindowInfo info; - m_clientHandler = new ClientHandler{*this}; m_clientHandler->AddRef(); - // Initialize window info to the defaults for a child window #ifdef __WXGTK__ - m_widget = gtk_scrolled_window_new( nullptr, nullptr ); - g_object_ref( m_widget ); - GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW( m_widget ); - // Hide the scroll bar. - gtk_scrolled_window_set_policy( scrolled_window, GTK_POLICY_NEVER, GTK_POLICY_NEVER); - GtkWidget* view_port = gtk_viewport_new( nullptr, nullptr ); + #ifdef __WXGTK3__ - gtk_container_add( GTK_CONTAINER(m_widget), view_port ); -#else - gtk_scrolled_window_add_with_viewport( scrolled_window, view_port ); -#endif - // TODO: figure out correct parameters for Linux SetAsChild() call - ::Window xid = GDK_WINDOW_XID(gtk_widget_get_window(view_port)); - wxASSERT(xid != 0); - info.SetAsChild(xid, CefRect(0, 0, size.GetX(), size.GetY())); - m_parent->DoAddChild( this ); - PostCreation( size ); + // CEF window creation fails with Match error unless we use the default X11 + // visual, which is not the case by default since GTK 3.15, see dae447728d + // (X11: Pick better system and rgba visuals for GL, 2014-10-29). + // + // We do this unconditionally instead of checking for GTK version because + // it shouldn't hurt even with earlier version and nobody uses them anyhow. + GdkScreen* screen = gdk_screen_get_default(); + GdkX11Screen* x11_screen = GDK_X11_SCREEN(screen); + Visual* default_xvisual = DefaultVisual(GDK_SCREEN_XDISPLAY(x11_screen), + GDK_SCREEN_XNUMBER(x11_screen)); + GdkVisual* default_visual = nullptr; - gtk_widget_show( view_port ); -#else - const wxSize sz = GetClientSize(); - info.SetAsChild(GetHandle(), {0, 0, sz.x, sz.y}); -#endif + for ( GList* visuals = gdk_screen_list_visuals(screen); + visuals; + visuals = visuals->next) + { + GdkVisual* visual = GDK_X11_VISUAL (visuals->data); + Visual* xvisual = gdk_x11_visual_get_xvisual(GDK_X11_VISUAL (visuals->data)); - CefBrowserHost::CreateBrowser( - info, - CefRefPtr{m_clientHandler}, - url.ToStdString(), - browsersettings, - nullptr, // No extra info - nullptr // Use global request context - ); + if ( xvisual->visualid == default_xvisual->visualid ) + { + default_visual = visual; + break; + } + } + + if ( default_visual ) + gtk_widget_set_visual(m_widget, default_visual); +#endif // wxGTK3 + + // Under wxGTK we need to wait until the window becomes realized in order + // to get the X11 window handle, so postpone calling DoCreateBrowser() + // until GTKHandleRealized(). + m_url = url; +#else + // Under the other platforms we can call it immediately. + if ( !DoCreateBrowser(url) ) + return false; +#endif this->Bind(wxEVT_SIZE, &wxWebViewChromium::OnSize, this); @@ -379,6 +382,51 @@ bool wxWebViewChromium::Create(wxWindow* parent, return true; } +#ifdef __WXGTK__ + +void wxWebViewChromium::GTKHandleRealized() +{ + // Unfortunately there is nothing we can do here if it fails, so just + // ignore the return value. + DoCreateBrowser(m_url); +} + +#endif // __WXGTK__ + +bool wxWebViewChromium::DoCreateBrowser(const wxString& url) +{ + CefBrowserSettings browsersettings; + + // Initialize window info to the defaults for a child window + CefWindowInfo info; + + // In wxGTK the handle returned by GetHandle() is the GtkWidget, but we + // need the underlying X11 window here. +#ifdef __WXGTK__ + const auto handle = GDK_WINDOW_XID(GTKGetDrawingWindow()); +#else + const auto handle = GetHandle(); +#endif + + const wxSize sz = GetClientSize(); + info.SetAsChild(handle, {0, 0, sz.x, sz.y}); + + if ( !CefBrowserHost::CreateBrowser( + info, + CefRefPtr{m_clientHandler}, + url.ToStdString(), + browsersettings, + nullptr, // No extra info + nullptr // Use global request context + ) ) + { + wxLogTrace(TRACE_CEF, "CefBrowserHost::CreateBrowser() failed"); + return false; + } + + return true; +} + wxWebViewChromium::~wxWebViewChromium() { if (m_clientHandler) @@ -461,23 +509,34 @@ void wxWebViewChromium::ShutdownCEF() void wxWebViewChromium::OnSize(wxSizeEvent& event) { -#ifdef __WXMSW__ - wxSize size = GetClientSize(); - if ( m_clientHandler && m_clientHandler->GetBrowser() && m_clientHandler->GetBrowser()->GetHost() ) - { - HWND handle = m_clientHandler->GetBrowser()->GetHost()->GetWindowHandle(); - - if ( handle ) - { - HDWP hdwp = BeginDeferWindowPos(1); - hdwp = DeferWindowPos(hdwp, handle, nullptr, 0, 0, - size.GetWidth(), size.GetHeight(), SWP_NOZORDER); - EndDeferWindowPos(hdwp); - } - } -#endif - event.Skip(); + + CefRefPtr host; + if ( m_clientHandler ) + { + if ( auto browser = m_clientHandler->GetBrowser() ) + host = browser->GetHost(); + } + + if ( !host ) + return; + + auto handle = host->GetWindowHandle(); + if ( !handle ) + return; + + wxSize size = GetClientSize(); + +#ifdef __WXMSW__ + HDWP hdwp = BeginDeferWindowPos(1); + hdwp = DeferWindowPos(hdwp, handle, nullptr, 0, 0, + size.GetWidth(), size.GetHeight(), SWP_NOZORDER); + EndDeferWindowPos(hdwp); +#elif defined(__WXGTK__) + size *= GetDPIScaleFactor(); + + ::XResizeWindow(wxGetX11Display(), handle, size.x, size.y); +#endif } void wxWebViewChromium::SetPageSource(const wxString& pageSource)