Expand description
WPE WebKit integration for the LTK toolkit.
Exposes WebView, a wrapper around a WebKitWebView driven on
the WPEPlatform path with the headless display backend. The
view’s pixels are imported as an EGLImage per frame and
re-targeted onto a GL texture inside LTK’s GLES context, so the
page composites inline with the rest of the LTK widget tree — no
hole-punching, no separate Wayland surface for WebKit.
§Quick start
use ltk::{ App, CursorShape, Element, Keysym };
use ltk_webkit::WebView;
#[ derive( Clone ) ]
enum Msg { Tick }
struct DemoApp { webview: WebView }
impl App for DemoApp
{
type Message = Msg;
fn view( &self ) -> Element<Msg>
{
ltk::column().push( self.webview.element::<Msg>() ).into()
}
fn update( &mut self, _: Msg ) {}
fn poll_external( &mut self ) -> Vec<Msg>
{
self.webview.tick();
vec![ Msg::Tick ]
}
fn poll_interval( &self ) -> Option<std::time::Duration>
{
Some( std::time::Duration::from_millis( 16 ) )
}
fn invalidate_after( &self, _: &Msg ) -> ltk::InvalidationScope
{
if self.webview.take_redraw_request() { ltk::InvalidationScope::All }
else { ltk::InvalidationScope::Only( Vec::new() ) }
}
// Forward LTK input to WebKit.
fn on_pointer_move( &mut self, x: f32, y: f32 )
{
self.webview.pointer_move( x as f64, y as f64 );
}
fn on_pointer_button( &mut self, x: f32, y: f32, pressed: bool )
{
if pressed { self.webview.pointer_press( x as f64, y as f64 ); }
else { self.webview.pointer_release( x as f64, y as f64 ); }
}
fn on_pointer_axis( &mut self, x: f32, y: f32, dx: f32, dy: f32 )
{
let scale = -1.0_f32 / 3.0;
self.webview.scroll( x as f64, y as f64, ( dx * scale ) as f64, ( dy * scale ) as f64 );
}
fn on_raw_key( &mut self, ks: Keysym, kc: u32, pressed: bool, ctrl: bool, shift: bool )
{
self.webview.send_key( ks.raw(), kc, pressed, ctrl, shift );
}
fn cursor_override( &self ) -> Option<CursorShape>
{
Some( self.webview.cursor_shape() )
}
fn window_config( &self ) -> Option<( &str, &str )>
{
Some( ( "ltk-webkit demo", "net.liberux.ltk-webkit.demo" ) )
}
}
let webview = WebView::new( 800.0, 600.0, "https://example.com" )?;
ltk::run( DemoApp { webview } );§What is wired up
Forwarded into WebKit via the methods on WebView:
| LTK callback | WebView method | WPE event |
|---|---|---|
App::on_pointer_move | WebView::pointer_move | POINTER_MOVE |
App::on_pointer_button( pressed ) | WebView::pointer_press / WebView::pointer_release | POINTER_DOWN/POINTER_UP |
App::on_pointer_axis | WebView::scroll | SCROLL |
App::on_raw_key | WebView::send_key | KEYBOARD_KEY_DOWN/UP |
App::on_touch_down / move / up | WebView::touch_down / WebView::touch_move / WebView::touch_up | TOUCH_DOWN/TOUCH_MOVE/TOUCH_UP |
| layout rect change (per frame) | (auto via WebView::element) | WPEToplevel::resize |
On a touchscreen the host must also return true from ltk’s
App::claims_raw_touch — otherwise the primary finger is consumed
by ltk’s widget gesture machine and never reaches these callbacks.
WebKit’s own gesture recognition then turns the raw stream into
taps, kinetic scrolls and pinch-zoom.
Forwarded out of WebKit (read by LTK):
| What | Method |
|---|---|
| New rendered frame ready | WebView::take_redraw_request |
| Cursor shape WebKit wants | WebView::cursor_shape |
§Threading
Single-threaded usage only. WPE’s GMainLoop, the Wayland event
loop and LTK’s render loop must all run on the same thread (the
main thread, in practice). WebView exposes Send + Sync
because the [ltk::ExternalSource::Texture] closure requires it,
but the FFI pointers it holds are not actually safe to use across
threads — calling WebView::tick or rendering off the main thread
is undefined behaviour.
§Caveats
- Press counts (single / double / triple click) come from
wpe_view_compute_press_count, which uses a position + time window heuristic; quirky touchpads may need calibration. - Cursor changes incur a WebKit-IPC round trip; the host’s
invalidate_aftershould returnAllwheneverWebView::take_redraw_requestistrueto avoid stale-frame lag. - Cursor names WebKit emits but LTK doesn’t enumerate
(
col-resize,row-resize,zoom-in,none, …) fall back toDefault. Dropof an internalInnerdoes not destroy the bound EGLImage — minor leak, acceptable for the spike.
Structs§
- A WebKit-rendered view that can be embedded into an LTK widget tree via
WebView::element.