- Code: Select all
// main.cpp
#include <cassert> // for function-like macro assert
#include <future> // for class template future
#include <gdk/gdkx.h> // for function-like macro GDK_WINDOW_XID
#include <gtk/gtk.h>
#include <include/cef_app.h> // for function CefExecuteProcess
#include <include/cef_client.h>
#include <include/internal/cef_linux.h> // for class CefMainArgs
#include <memory> // for class template unique_ptr
#include <thread> // for class thread
#if defined(_NDEBUG)
#define ASSERT(expr) expr
#else
#define ASSERT(expr) assert(expr)
#endif
GdkVisual *get_default_visual(void);
void my_cef_ui_thread(std::future<Window>&& futCtnWin)
{
// Create the first browser window.
CefWindowInfo winfo;
winfo.SetAsChild(futCtnWin.get(), CefRect());
CefBrowserSettings bsettings;
CefBrowserHost::CreateBrowser(winfo, nullptr, "https://www.google.com/", bsettings, nullptr, nullptr);
// Enter CEF message loop.
GMainContext *ctx = ::g_main_context_new();
::g_main_context_push_thread_default(ctx);
GMainLoop *loop = ::g_main_loop_new(ctx, false);
::g_main_loop_run(loop);
::g_main_loop_unref(loop);
::g_main_context_unref(ctx);
// Clean up CEF.
::CefShutdown();
}
int main(int argc, char *argv[])
{
// Create the worker thread or not, depending on the role of this process.
CefMainArgs args(argc, argv);
int iExitStatusCode = ::CefExecuteProcess(args, nullptr, nullptr);
if (iExitStatusCode != -1) return iExitStatusCode;
// Initialize CEF.
CefSettings settings;
settings.multi_threaded_message_loop = true;
ASSERT(::CefInitialize(args, settings, nullptr, nullptr) == true);
std::promise<Window> pmiCtnWin;
auto&& thdCEF = std::unique_ptr<std::thread>(new std::thread(my_cef_ui_thread, pmiCtnWin.get_future()));;
// Create the top-level window.
::gtk_init(NULL, NULL);
GtkWidget *frm = ::gtk_window_new(GTK_WINDOW_TOPLEVEL);
::gtk_widget_set_visual(frm, get_default_visual());
::gtk_widget_realize(frm);
pmiCtnWin.set_value(GDK_WINDOW_XID(::gtk_widget_get_window(frm)));
::gtk_widget_show(frm);
// Enter GTK event loop.
// ::gtk_main();
// Clean up and exit normally.
thdCEF->join();
return 0;
}
Below is an auxiliary function get_default_visual which is needed for running CEF on GTK+ 3. It is used in the above translation unit to change the X Visual before creating the underlying X window of the container widget for CEF browser window. It is necessary because the X Visual provided by GTK+ 3 isn't compatible with CEF.
- Code: Select all
// get_default_visual.cpp
#include <gdk/gdk.h>
#include <gdk/gdkx.h> // for function-like macros GDK_SCREEN_XDISPLAY, GDK_SCREEN_XNUMBER and function gdk_x11_visual_get_xvisual
#include <gtk/gtk.h> // for function-like macro GTK_CHECK_VERSION
#if GTK_CHECK_VERSION(3, 15, 2)
GdkVisual *get_default_visual(void)
{
// Get the default X visual.
GdkScreen *scr = ::gdk_screen_get_default(); // the default physical screen
Visual *xvDefault = DefaultVisual(
GDK_SCREEN_XDISPLAY(GDK_X11_SCREEN(scr)), // the connection to the X server.
GDK_SCREEN_XNUMBER(GDK_X11_SCREEN(scr)) // the index number of the default physical screen
);
// Get the list of all available GdkVisual objects.
GList *list = ::gdk_screen_list_visuals(scr); // The type of the data in each list item is GdkVisual.
// Find out which GdkVisual wraps the default X visual.
GdkVisual *gvCurrent = NULL;
for (GList *item = list; item; item = item->next) {
gvCurrent = GDK_VISUAL(item->data);
Visual *xvCurrent = ::gdk_x11_visual_get_xvisual(GDK_X11_VISUAL(gvCurrent));
if (xvCurrent->visualid == xvDefault->visualid) break;
}
::g_list_free(list);
// Return the default X visual we just found.
return gvCurrent;
}
#endif
The program can be compiled with these commands.
- Code: Select all
$ dirCEF="/somewhere/cef_binary_xxx_linux64"
$ g++ -Wall -I${dirCEF} $(pkg-config --cflags gtk+-3.0,glib-2.0) -c main.cpp
$ g++ -Wall -I${dirCEF} $(pkg-config --cflags gtk+-3.0,glib-2.0) -c get_default_visual.cpp
$ g++ main.o get_default_visual.o -Wl,-rpath=${dirCEF}/Debug ${dirCEF}/libcef_dll/libcef_dll_wrapper.a \
> -L${dirCEF}/Debug -lcef -lboost_thread -pthread $(pkg-config --libs gtk+-3.0) -o a.out
It can be built and open web page successfully on Debian 10 based distro, e.g. MX 19.2. However, if uncomment the line that calls gtk_main, it crashes immediately. It looks like some CEF messages were wrongly flowing into the message loop managed by gtk_main. Is there any way to tell CEF to send all its messages only to a specific thread? Please help. Thanks.