在Linux

时间:2016-07-27 17:45:31

标签: c++ linux gtk wxwidgets chromium-embedded

我从this branch of wxWidgets from GitHub user hokein开始,因为它似乎正在寻找旧版本的CEF。基本上,我尝试使用cef_3.2526.1354来实现wxWebViewChromium(使用CEF作为后端的wxWebView),因为这是我们想要在我们的应用程序中使用的版本。我在使用Hyper-V的虚拟机中使用GNOME运行CentOS 7。

上面链接的存储库中的原始代码(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

当我尝试使用cef_3.2526.1354进行编译和链接时,我收到了与info.SetAsChild(viewport);行相关的错误。我传递了GtkWidget*,它期待cef_window_handle_t, CefRect

到目前为止我尝试了什么

我根据GtkWidget* view_port

创建了这样的CefRect
GtkAllocation gtk_alloc;
gtk_widget_get_allocation(view_port, &gtk_alloc);
CefRect cef_rect (
    (int)gtk_alloc.x,
    (int)gtk_alloc.y,
    (int)gtk_alloc.width,
    (int)gtk_alloc.height
);

CEF库代码中的typedef表明cef_window_handle_tunsigned long,但CEF documentation表示它是GtkWidget* ...我猜是同样的事情,但这导致了一些初步的混乱。起初我以为我需要从底层X11窗口传递X11窗口id(XID),但这会产生运行时错误:

Gdk: gdkdrawable-x11.c:952 drawable is not a pixmap or window

简单地将GtkWidget*转换为unsigned long而不是使用基础X11窗口ID删除了此错误,因此我认为这就是函数所期望的。

我的代码(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, &gtk_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

发生了什么

我能够编译,链接和运行应用程序。我可以看到wxWidgets窗口,我可以像任何普通窗口一样最小化,最大化,调整大小和关闭窗口。窗户里什么都没有 - 它只是一个平坦的灰色空窗。我期待(或希望)看到CEF浏览器。在我用来启动应用程序的终端中,我收到以下消息:

[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.

此网址似乎不再有用。如果我从命令行启动./cefclient --no-sandbox,我会收到相同的错误消息,但CEF客户端按预期工作。如果我从命令行启动./cefclient(没有禁用沙箱),我会收到同样的消息,而不是ERROR它说FATAL并且CEF客户端不起作用(直接崩溃)。

我的问题

我对webview_chromium.cpp文件的修改有什么问题吗?这个文件中的其他地方是否应该查找我可能需要更新的内容以使其与cef_3.2526.1354一起使用?如何对我看到的这个空窗口进行故障排除?

谢谢!

更新

Czarek Tomczak告诉我,这个版本的CEF期待一个X11窗口句柄,所以我修改了我的代码如下。

#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, &gtk_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

但这仍然导致下面的运行时错误,并且输出与之前相同的空白窗口。

Gdk: gdkdrawable-x11.c:952 drawable is not a pixmap or window

任何帮助我指向正确方向的人都会非常感激。我也试过在这里创建一个实际的GtkWindow而不是一个带有视口的滚动窗口。这消除了上述运行时错误,但它打开了第二个窗口,两个窗口都是空白的。我需要在一个窗口内完成所有这些工作。

更新2

在Czarek Tomczak的帮助下,他发布的链接以及this FAQ我已经达到了能够将CEF浏览器嵌入GtkWidget的程度,但我只能做到这一点我将小部件创建为顶级GTK窗口,如下所示:

m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);

m_widget是我尝试创建的wxWebView的主要小部件。这个问题是现在CEF浏览器出现在它自己的GTK窗口中,但我真正需要的是CEF浏览器适合我要添加我的wxWebViewChromium小部件的wxBoxSizer。为了实现这一点,我将Create方法中的一些代码拆分为OnSize方法,这样我就可以在GtkWidget实现后获取GtkWidget的XID,并在发生这种情况后创建CEF浏览器。 OnSize方法已连接到wxEVT_SIZE。我的代码现在如下。

Create方法

的更新部分
// 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 );

OnSize方法

的更新部分
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, &gtk_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
    );
}

当我尝试使m_widget以外的东西而不是顶级GTK小部件时(如上面Create方法的代码的注释部分所示),我收到以下错误在运行时。

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.

如何让这个窗口显示在我的wxBoxSizer中而不是它自己的GTK顶级窗口?

1 个答案:

答案 0 :(得分:1)

CEF期待X11窗口句柄。在以前版本的CEF中需要GtkWidget句柄。该维基页面上的文档似乎已过时。在将X11句柄传递给CEF之前,请确保X11句柄有效(显示窗口)。

我只能建议看看如何在cefclient示例应用程序中创建GTK窗口:

https://bitbucket.org/chromiumembedded/cef/src/98f59f47fd395c170f389eba36f2ef2e06a500a8/tests/cefclient/browser/root_window_gtk.cc?at=master&fileviewer=file-view-default#root_window_gtk.cc-233

另外看一下CreateBrowser() - 它使用GetXWindowForWidget():

https://bitbucket.org/chromiumembedded/cef/src/98f59f47fd395c170f389eba36f2ef2e06a500a8/tests/cefclient/browser/browser_window_std_gtk.cc?at=master&fileviewer=file-view-default#browser_window_std_gtk.cc-91