Skip to content

LostSyscall/cefwebview

Repository files navigation

CefWebView

A reusable CEF (Chromium Embedded Framework) WebView control for Win32/MFC and Linux/GTK3 applications.

Features

  • Embed Chromium browser in Win32 window, MFC dialog/view, or Linux GTK3 window
  • JavaScript-to-C++ bidirectional communication via CefMessageRouter
  • Local frontend build loading (file:// protocol) with auto-resize and Unicode path support
  • Supports both dedicated CEF message loop and integrated host loop
  • Software rendering fallback for GPU-less environments
  • PIMPL pattern hides CEF internals from public API
  • Platform-abstracted types (CefWebViewHandle, CefWebViewRect) for cross-platform API

Requirements

Windows

  • Windows 10+
  • Visual Studio 2019 (MSVC 14.29, x64)
  • CMake 3.21+
  • CEF 144+ binary distribution (included in third_party/cef/)

Linux

  • Linux (x64, GTK3 desktop environment)
  • GCC 9+ or Clang 10+
  • CMake 3.21+
  • GTK3 development libraries (libgtk-3-dev)
  • CEF 144+ binary distribution (linux64 standard build)

Building

Note: CEF binary distribution is not included in the repository (~800MB). Download manually from cef-builds.spotify.com and extract to third_party/cef/, or let CMake handle it via cmake/DownloadCef.cmake. Copy CMakeUserPresets.json.example to CMakeUserPresets.json and set VCPKG_ROOT to your local vcpkg installation before building.

Windows

cmake --preset debug
cmake --build build --config Debug

The Win32 demo executable is at build/demos/win32_demo/Debug/CefWebViewWin32Demo.exe. CEF runtime files and frontend assets are copied to the output directory automatically.

Linux

mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)

The Linux demo executable is at build/demos/linux_demo/CefWebViewLinuxDemo.

Docker (Linux cross-build from Windows)

docker build -t cefwebview-linux -f docker/Dockerfile .
docker run --rm -v $(pwd)/build-linux:/build cefwebview-linux

Quick Start (Win32)

#include "cefwebview/CefManager.h"
#include "cefwebview/CefWebView.h"

int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int nCmdShow) {
    // 1. Handle CEF sub-processes (must be first call in WinMain)
    int exitCode = CefManager::Instance().HandleSubProcess(0, nullptr);
    if (exitCode >= 0) return exitCode;

    // 2. Initialize CEF with a callback for browser creation
    CefManager::InitParams params;
    params.loopMode = CefManager::DEDICATED_LOOP;
    params.noSandbox = true;
    params.onContextInitialized = [nCmdShow]() {
        // Create your window here, then create CefWebView
        CefWebView* webView = new CefWebView();
        webView->Create(static_cast<CefWebViewHandle>(hWnd), rect, L"about:blank");
        webView->LoadDirectory(exeDir + L"frontend_dist");
    };

    if (!CefManager::Instance().Initialize(params)) return -1;

    // 3. Run message loop
    CefManager::Instance().RunMessageLoop();

    // 4. Shutdown
    CefManager::Instance().Shutdown();
    return 0;
}

Quick Start (Linux/GTK3)

#include "cefwebview/CefManager.h"
#include "cefwebview/CefWebView.h"
#include <gtk/gtk.h>

int main(int argc, char* argv[]) {
    // 1. Handle CEF sub-processes
    int exitCode = CefManager::Instance().HandleSubProcess(argc, argv);
    if (exitCode >= 0) return exitCode;

    gtk_init(&argc, &argv);

    // 2. Initialize CEF with INTEGRATED_LOOP for GTK main loop
    CefManager::InitParams params;
    params.loopMode = CefManager::INTEGRATED_LOOP;
    params.noSandbox = true;
    params.onContextInitialized = [&]() {
        GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        // ... create CefWebView ...
        webView->Create(static_cast<CefWebViewHandle>(window), rect, L"about:blank");
    };

    if (!CefManager::Instance().Initialize(params)) return -1;

    // 3. GTK main loop with CEF work integration
    while (gtk_events_pending()) {
        gtk_main_iteration();
        CefManager::Instance().DoMessageLoopWork();
    }

    CefManager::Instance().Shutdown();
    return 0;
}

API Reference

CefManager (Singleton)

Method Description
Instance() Get the singleton instance
HandleSubProcess(argc, argv) Call first in main(); returns exit code for sub-processes
Initialize(params) Initialize CEF; returns false on failure
Shutdown() Clean up CEF resources
RunMessageLoop() Run CEF-owned message loop (DEDICATED_LOOP)
QuitMessageLoop() Exit the CEF message loop
DoMessageLoopWork() Pump CEF work in host-owned loop (INTEGRATED_LOOP)
GetLoopMode() Get the current message loop mode

InitParams fields: loopMode, cachePath, userAgent, noSandbox, multiThreadedMessageLoop, remoteDebuggingPort, onContextInitialized

CefWebView (Cross-platform Control)

Method Description
Create(parent, rect, url) Create browser as child of parent (HWND on Win32, GtkWidget* on Linux)
Destroy() Close and destroy the browser
Navigate(url) Navigate to a URL
LoadLocalFile(path) Load a local file via file:/// protocol (Unicode paths supported)
LoadDirectory(dir) Load dir/index.html as a frontend build
GoBack() / GoForward() / Reload() / StopLoad() Navigation controls
SetBounds(rect) Resize browser to fill client area (0,0 origin)
SetFocus() Focus the browser window
ExecuteJavaScript(script) Run JS in the main frame
RegisterJsHandler(name, callback) Register a C++ handler for JS messages
IsCreated() / IsLoading() / GetTitle() / GetUrl() State queries
GetHandle() Get native browser handle (HWND or GtkWidget*)
SetOnTitleChange(cb) / ... Event callback setters

Platform Types

Type Win32 Linux
CefWebViewHandle HWND void* (GtkWidget*)
CefWebViewRect RECT {int left, top, right, bottom}

JS-C++ Interop

JavaScript side (auto-injected on page load):

const result = await window.cefwebview.sendMessage('native.action', { key: 'value' });

C++ side (uses JsHandlerCallback with JsResponseCallback):

webView->RegisterJsHandler("native.action",
    [](const std::string& args, CefWebView::JsResponseCallback respond) {
        // args is the serialized arguments from JS
        respond(true, "response from C++");
    });

Architecture

The library uses a PIMPL pattern — CefWebView and CefManager public headers only declare the API and a struct Impl*. The full implementation (CEF types, ClientHandler, JsInteropHandler) is in platform-specific internal headers (CefWebView_p.h), which are only accessible when building the library itself. Users of the library do not need CEF headers in their include path.

Platform-specific code is separated by directory:

  • src/win32/ — Windows HWND-based implementation
  • src/linux/ — Linux GTK3-based implementation
  • src/core/ — Platform-independent CEF integration (CefManager, ClientHandler, JsInterop)

Important Notes

  • Browser creation must happen in onContextInitialized callback — this fires during CefInitialize(), so the callback must be set before calling Initialize().
  • Do not use --disable-features=NetworkService — this causes a segfault in CEF 144+.
  • GPU process crashes are non-fatal — CEF auto-recovers with software rendering.
  • Call HandleSubProcess() first in main(); CEF sub-processes must exit immediately.
  • Stack size must be at least 8MB for x64 builds (/STACK:0x800000 on Windows).
  • Unicode paths in LoadLocalFile are properly percent-encoded (UTF-8 bytes then %XX).
  • Linux uses INTEGRATED_LOOP — GTK3 owns the main loop; call DoMessageLoopWork() within the GTK event loop.

Troubleshooting

Problem Solution
Exit code 139 (segfault) Remove --disable-features=NetworkService from command line switches
GPU process crash (exit 143) Non-fatal; CEF auto-recovers with software rendering
Browser not appearing Ensure Create() is called inside onContextInitialized callback
Empty window / wrong size Use SetBounds(rect) with client-area rect (0,0 based), not window rect
CEF sub-process hangs Call HandleSubProcess() at the very start of main()
Build error: undefined CefWebView::Impl Only occurs when building the library — consumers use the public header
Linux: libcef.so not found Ensure CEF linux64 distribution is in third_party/cef/
Linux: GTK3 not found Install libgtk-3-dev package

Build Options

CMake Option Default Description
CEFWEBVIEW_BUILD_SHARED OFF Build as shared DLL
CEFWEBVIEW_BUILD_MFC OFF Include MFC support (Windows only)
CEFWEBVIEW_BUILD_DEMOS ON Build demo applications
CEFWEBVIEW_BUILD_TESTS OFF Build tests
CEFWEBVIEW_USE_VCPKG_CEF OFF Use CEF from vcpkg (unofficial::cef) instead of local distribution

vcpkg Integration

CefWebView can be consumed via vcpkg overlay ports. This is useful when integrating CefWebView into another project without manually managing the CEF binary distribution.

Setup

  1. Clone this repository:

    git clone https://github.com/zhangkh/cefproj.git
  2. Configure your project to use the overlay ports:

    In CMakePresets.json:

    {
      "configurePresets": [{
        "name": "default",
        "cacheVariables": {
          "VCPKG_OVERLAY_PORTS": "${sourceDir}/../cefproj/ports"
        }
      }]
    }

    Or via vcpkg CLI:

    vcpkg install cefwebview:x64-windows --overlay-ports=cefproj/ports
    vcpkg install cefwebview:x64-linux --overlay-ports=cefproj/ports
  3. Use in your CMake project:

    find_package(CefWebView REQUIRED)
    target_link_libraries(myapp PRIVATE CefWebView::CefWebView)

How it works

The vcpkg integration uses two overlay ports:

  • cef-binary: Downloads the CEF binary distribution from Spotify CDN, builds libcef_dll_wrapper from source, and installs headers/DLLs/libs. Provides find_package(unofficial-cef) with unofficial::cef::libcef and unofficial::cef::libcef_dll_wrapper targets.

  • cefwebview: Builds CefWebView from source with CEFWEBVIEW_USE_VCPKG_CEF=ON, which uses the CEF installed by cef-binary. Provides find_package(CefWebView) with CefWebView::CefWebView target.

Important notes for vcpkg consumers

  • CEF runtime libraries (libcef.dll/libcef.so, etc.) and resources are installed by the cef-binary port. Your application must copy them to the executable directory at runtime or deployment.
  • The CEFWEBVIEW_USE_VCPKG_CEF option is automatically set when building through vcpkg — do not set it manually in standalone builds.

Project Structure

cefproj/
  include/cefwebview/    Public API headers (PIMPL, no CEF exposure)
  src/core/              CefManager, ClientHandler, CefAppImpl, JsInterop
  src/win32/             CefWebView implementation + CefWebView_p.h (internal)
  src/linux/             CefWebView GTK3 implementation + CefWebView_p.h (internal)
  src/mfc/               CefMfcView MFC control
  ports/cef-binary/      vcpkg overlay port for CEF binary distribution
  ports/cefwebview/      vcpkg overlay port for CefWebView
  demos/win32_demo/      Win32 demo with sample frontend
  demos/linux_demo/      Linux/GTK3 demo with sample frontend
  demos/interop_demo/    JS-C++ interop demo (Win32 + Linux)
  demos/mfc_demo/        MFC demo
  third_party/cef/       CEF binary distribution

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors