An open API service indexing awesome lists of open source software.

https://github.com/bnema/purego-cef

Go bindings for the Chromium Embedded Framework C API, using purego instead of cgo.
https://github.com/bnema/purego-cef

bindings cef chrome-embedded-framework go golang purego

Last synced: about 1 month ago
JSON representation

Go bindings for the Chromium Embedded Framework C API, using purego instead of cgo.

Awesome Lists containing this project

README

          

# purego-cef

Go bindings for the [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef/) C API, using [purego](https://github.com/bnema/purego) instead of cgo.

Linux only. `CGO_ENABLED=0`.

> [!NOTE]
> purego-cef is usable today, but it is still pre-1.0.
> Expect API changes while the handwritten `cef` layer settles.

## Status

purego-cef exposes the CEF C API through generated bindings and adds a smaller
handwritten `cef` layer for the common paths.

What to expect today:
- generated low-level bindings across the CEF C API
- a smaller ergonomic `cef` layer for init, clients, and common handlers
- shipped mocks for testing
- ongoing API cleanup before 1.0

## Architecture

The binding layer is **generated** from CEF C headers (~114 files). The generator parses all headers and produces:

- **Inbound port interfaces** for every CEF handler and type
- **Outbound port interfaces** grouping CEF free functions and object methods by domain
- **A composite CAPI interface** embedding all outbound ports
- **Typed constructors** for handlers and wrappers for CEF objects with automatic refcount management
- **C struct layouts** and purego symbol registration
- **Doc comments** extracted from CEF C headers

The public `cef` package then adds a small handwritten layer for the places
where the raw C API is too awkward to expose directly.

A hand-written core domain handles UTF-16 string conversion, reference counting, CEF lifecycle orchestration, and the Bridge adapter implementing the CAPI interface.

Mocks for all interfaces are generated by [Mockery v3](https://vektra.github.io/mockery/) and shipped in `cef/mocks/`.

## API shape

For most code, prefer the ergonomic handwritten layer when it exists:

- `cef.Settings` instead of `cef.RawSettings`
- `cef.NewClient(...)` with `cef.Client`
- `cef.NewLifeSpanHandler(...)` with `cef.LifeSpanHandler`
- `cef.NewAudioHandler(...)` with the decoded `cef.AudioHandler` interface
- `cef.ExecuteSubprocess()` when you want subprocess status and errors without
implicit `os.Exit` or `stderr` writes; `cef.MaybeExitSubprocess()` remains the
short helper for main packages
- `cef.ExecuteSubprocessWithApp(app)` when helper subprocess startup also needs
a custom `cef.App`
- `cef.LifeSpanHandler` popup callbacks receive a callback-scoped
`*cef.RawClientWriteSlot` when CEF exposes a writable popup client out-param;
check for nil before calling `Set` or `Clear`

Treat `Raw*` types as advanced escape hatches.

## Usage

For main packages, `cef.MaybeExitSubprocess()` is the short path. If you need
explicit subprocess status and error handling, use `cef.ExecuteSubprocess()` or
`cef.ExecuteSubprocessWithApp(app)`.

```go
package main

import (
"runtime"

"github.com/bnema/purego-cef/cef"
)

func main() {
runtime.LockOSThread()
cef.MaybeExitSubprocess()

if err := cef.Init(cef.DefaultSettings()); err != nil {
panic(err)
}
defer cef.Shutdown()

client := cef.NewClient(myClient{})
_ = client

// Your render loop here
for {
cef.DoMessageLoopWork()
}
}

// Implement the user-facing client interface — only the methods you need.
type myClient struct{}

func (c myClient) GetLifeSpanHandler() cef.LifeSpanHandler { return nil }
func (c myClient) GetRenderHandler() cef.RenderHandler { return myRenderer{} }
// ... other handler getters return nil
```

## Requirements

- Go 1.26+
- CEF 145 runtime in `$CEF_DIR` or `~/.local/share/cef`

## Building

```
CGO_ENABLED=0 go build ./...
CGO_ENABLED=0 go test ./...
```

Integration tests need the CEF runtime:

```
CEF_DIR=$HOME/.local/share/cef go test -tags=cef_integration ./integration
```

## Regenerating bindings

```
go generate ./...
```

Or manually:

```
go run ./cmd/cefgen \
--headers-dir ~/.local/share/cef/include \
--capi-dir internal/capi \
--port-in-dir internal/ports/in \
--port-out-dir internal/ports/out \
--public-dir cef
mockery
```

## Project layout

```
cef/ public API (generated) + mocks
bridge.go hand-written: handler constructors, string helpers
init.go hand-written: Init(), Shutdown(), orchestration
internal/
ports/in/ inbound port interfaces (generated)
ports/out/ outbound port interfaces (generated) + composite CAPI (hand-written) + mocks
core/ domain logic: engine, string marshaling, refcount (hand-written)
capi/ purego bindings + bridge (generated + hand-written)
loader/ dlopen libcef.so + version validation (hand-written)
cmd/cefgen/ binding generator (parser, model, emitter, templates)
integration/ integration tests (require CEF runtime)
```

## License

MIT