I started with this branch of wxWidgets from GitHub user hokein since it seems to do what I'm looking for with older versions of CEF. Basically, I'm trying to implement wxWebViewChromium (a wxWebView using CEF as a back-end) using cef_3.2526.1354 since this is the version we want to use in our application. I'm running CentOS 7 with GNOME in a VM using Hyper-V.
Original code from the repository linked above (part of webview_chromium.cpp)
#ifdef __WXGTK__
m_widget = gtk_scrolled_window_new( NULL, NULL );
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( NULL, NULL );
gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
view_port );
info.SetAsChild( view_port );
m_parent->DoAddChild( this );
PostCreation( size );
gtk_widget_show( view_port );
#endif
When I tried to compile and link this with cef_3.2526.1354, I was getting errors related to the info.SetAsChild(viewport);
line. I was passing it a GtkWidget*
and it was expecting cef_window_handle_t, CefRect
.
What I've tried so far
I created the CefRect like this based on the GtkWidget* view_port
:
GtkAllocation gtk_alloc;
gtk_widget_get_allocation(view_port, >k_alloc);
CefRect cef_rect (
(int)gtk_alloc.x,
(int)gtk_alloc.y,
(int)gtk_alloc.width,
(int)gtk_alloc.height
);
The typedef from the CEF library code indicates that cef_window_handle_t
is an unsigned long
, but the CEF documentation says it's a GtkWidget*
... Which I guess are the same thing, but this led to some initial confusion. At first I thought that I needed to pass the X11 window id (XID) from the underlying X11 window, but this produced a runtime error:
Gdk: gdkdrawable-x11.c:952 drawable is not a pixmap or window
Simply casting the GtkWidget*
as an unsigned long
instead of using the underlying X11 window ID removed this error, so I think that this is what the function was expecting.
My code currently (part of webview_chromium.cpp)
#ifdef __WXGTK__
m_widget = gtk_scrolled_window_new( NULL, NULL );
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( NULL, NULL );
gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
view_port );
GtkAllocation gtk_alloc;
gtk_widget_get_allocation(view_port, >k_alloc);
CefRect cef_rect (
(int)gtk_alloc.x,
(int)gtk_alloc.y,
(int)gtk_alloc.width,
(int)gtk_alloc.height
);
info.SetAsChild(
(unsigned long) view_port,
cef_rect
);
m_parent->DoAddChild( this );
PostCreation( size );
// gtk_widget_show(view_port);
gtk_widget_show_all(m_widget);
gtk_widget_show_all(view_port);
#endif
What's happening
I am able to compile, link, and run the application. I can see the wxWidgets window, and I can minimize, maximize, resize, and close the window just like any normal window. There is nothing in the window - it is just a plain, grey, empty window. I am expecting (or hoping) to see the CEF browser. In the terminal that I used to launch the application, I get the following message:
[0727/132200:ERROR:browser_main_loop.cc(203)] Running without SUID sandbox! See https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment for more information on developing with sandbox on.
This URL no longer seems to be of any use. If I launch ./cefclient --no-sandbox
from the command line I get the same error message, but the CEF client works as expected. If I launch ./cefclient
from the command line (without disabling sandbox), I get this same message except instead of ERROR
it says FATAL
and the CEF client does not work (crashes outright).
My questions
Have I done anything wrong with my modifications to the webview_chromium.cpp
file? Is there anywhere else in this file that I should look for things that I might need to update to get this working with cef_3.2526.1354? How can I troubleshoot this empty window that I'm seeing?
Thanks!
UPDATE
Czarek Tomczak informed me that this version of CEF is expecting an X11 window handle, so I have modified my code as follows.
#ifdef __WXGTK__
m_widget = gtk_scrolled_window_new( NULL, NULL );
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( NULL, NULL );
gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
view_port );
gtk_widget_show_all(m_widget);
gtk_widget_show_all(view_port);
GtkAllocation gtk_alloc;
gtk_widget_get_allocation(view_port, >k_alloc);
CefRect cef_rect (
(int)gtk_alloc.x,
(int)gtk_alloc.y,
(int)gtk_alloc.width,
(int)gtk_alloc.height
);
info.SetAsChild(
gdk_x11_drawable_get_xid(gtk_widget_get_window(view_port)),
cef_rect
);
m_parent->DoAddChild( this );
PostCreation( size );
#endif
But this is still leading to the run-time error below, with the same blank window output as before.
Gdk: gdkdrawable-x11.c:952 drawable is not a pixmap or window
Any help pointing me in the right direction would be much appreciated. I have also tried creating an actual GtkWindow here instead of a scrolled window with a viewport inside it. This gets rid of the above run-time error, but it opens a second window, both of which are blank. I need all of this to work within one window.
UPDATE 2
With some help from Czarek Tomczak, the links he posted, and this FAQ I have gotten to a point where I am able to embed the CEF browser into a GtkWidget, but I am only able to make this work if I create the widget as a top-level GTK window like this:
m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Where m_widget
is the main widget of the wxWebView I'm trying to create. The issue with this is that now the CEF browser is coming up in its own GTK window, but what I really need is for the CEF browser to fit into the wxBoxSizer
that I am adding my wxWebViewChromium widget to. To get this working to this point I split out some of the code from the Create method into the OnSize method so that I could get the XID of the GtkWidget after the GtkWidget was realized, and create the CEF browser after this happened. The OnSize method is connected to wxEVT_SIZE
. My code is now as follows.
Updated portion of Create
Method
// Actual creation of CEF browser moved to OnSize function so we
// can guarantee the widgets have been realized
this->Bind(wxEVT_SIZE, &wxWebViewChromium::OnSize, this);
// Works but as a top-level GTK window only
m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
// None of these work
//m_widget = gtk_drawing_area_new();
//m_widget = gtk_vbox_new(false, 0);
g_object_ref( m_widget );
Updated portion of OnSize
Method
if (!cef_browser_created)
{
cef_browser_created = true;
CefBrowserSettings browsersettings;
CefWindowInfo info;
XSetErrorHandler(XErrorHandlerImpl);
XSetIOErrorHandler(XIOErrorHandlerImpl);
gtk_widget_realize(m_widget);
::Window xwindow = GTK_WINDOW_XID(gtk_widget_get_window(m_widget));
DCHECK(xwindow);
GtkAllocation gtk_alloc;
gtk_widget_get_allocation(m_widget, >k_alloc);
CefRect cef_rect (
(int)gtk_alloc.x,
(int)gtk_alloc.y,
(int)gtk_alloc.width,
(int)gtk_alloc.height
);
info.SetAsChild(xwindow, cef_rect);
m_parent->DoAddChild( this );
PostCreation( size );
CefBrowserHost::CreateBrowserSync(
info,
static_cast<CefRefPtr<CefClient> >(m_clientHandler),
create_url.ToStdString(),
browsersettings,
NULL
);
}
When I try to make m_widget
something other than a top-level GTK widget (as shown in the commented-out portions of the code for the Create
method above), I get the following error at run-time.
Gtk: IA__gtk_widget_realize: assertion 'GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
Gdk: gdkdrawable-x11.c:952 drawable is not a pixmap or window
Check failed: xwindow.
How can I make this window appear inside my wxBoxSizer instead of as its own GTK top-level window?