Expand description
A web view for the LTK toolkit.
Exposes WebView, a page rendered off screen and drawn as a texture inside LTK’s GLES context, so it composites inline with the rest of the LTK widget tree: no hole-punching, no separate surface. The API is the same on every platform; the engine behind it is WPE WebKit on Linux, a WebKitWebView on the headless WPEPlatform display whose DMA-BUF frames are imported as EGLImages, and CEF on Windows.
§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 ltk reports the primary finger through the pointer
callbacks, so taps reach the page as clicks. For WebKit’s own touch
handling the host returns true from ltk’s App::claims_raw_touch,
and WebKit’s gesture recognition then turns the raw stream into
taps, kinetic scrolls and pinch-zoom. A host that shows the view next
to regular widgets returns WebView::contains from
App::claims_raw_touch_at instead, so its own chrome stays touchable.
Forwarded out of WebKit (read by LTK):
| What | Method |
|---|---|
| New rendered frame ready | WebView::take_redraw_request |
| Cursor shape WebKit wants | WebView::cursor_shape |
| Link under the pointer | WebView::hovered_link |
§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::Frame] 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 page’s request for files, which must be answered: dropped unanswered, it is cancelled.
- A main-frame navigation about to start.
- What a secondary press landed on; the position is in the host’s coordinates.
- What
crate::WebView::print_previewrenders. - One sheet of a
Preview, margins included, in RGBA. - How
crate::WebView::print_to_pdflays the page out. Lengths are in PDF points, 1/72 of an inch. The browser adds no header or footer, so the PDF carries neither the address nor the date; its title is the document’s. - Premultiplied RGBA,
width * 4bytes a row. - A WebKit-rendered view that can be embedded into an LTK widget tree via
WebView::element.
Enums§
- How much the engine keeps in memory to make browsing faster.
- Why a page’s web process went away. The view survives it and can load again.
Functions§
- The codecs that some video device of this machine decodes in hardware. Cameras and other devices answer with no input formats and add nothing.
- Drain the download events produced since the previous call, including a
Progressevent for every live download that advanced. - Resolve
hostahead of a load that is likely to follow, such as the address being typed. - For the views created from now on; an existing view keeps the policy it was built with.
- Pages are told that the blocked codecs cannot be played, which sites such as YouTube answer by streaming another one. An empty list lifts the block. A later call replaces what an earlier one injected; pages already loaded keep what they have until their next load.
- Creates the web context, so
set_memory_limithas to come first. - Replace the content filter with
rules_json. WebKit compiles it in the background, intostore_dir, so loads that start right away may still go unfiltered; pages already loaded keep what they have until their next load. - Keep website data and cookies in
dataand caches incache. Unset, WebKit names its directories after the program, so every WPE application without a name of its own shares them. Call it before anything else in this crate; a later call is ignored. - Directory new downloads are saved to. Defaults to
$XDG_DOWNLOAD_DIR, then the download directory ofuser-dirs.dirs, then~/Downloads. - Turn the feature named
identifier(aswebkit_feature_get_identifiergives it) on or off in the views created from now on. An identifier this WebKit does not know is reported once on stderr, with the ones that resemble it. - Memory a web process, or the network process, may use before WebKit starts giving it back: caches from a third of the limit, all it can from half. Unset, WebKit derives the limit from the machine, up to 3 GiB. Call it before anything else in this crate; zero is ignored.
- The keyboard modifiers the user holds, for pages that read them on a click, a motion or the wheel, as Shift+click extends a selection and Ctrl+click adds to it. The host calls this whenever they change.
Accept-Languageandnavigator.languages, most preferred first; WebKit’s default follows the process locale.- Whether a page may set cookies for a site other than the one in the address bar.
- WebKit’s Intelligent Tracking Prevention. Off by default, as in WebKit.
- Call
wakefrom another thread whenever the main context has events, so the host’s run loop can callcrate::WebView::tickthen rather than on a timer. After a call towakethe watch rests until the next tick, so a host that does not tick is woken once. Call it once, from the thread that ticks.