ltk_webkit/wpe/
context.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

//! The web context every [`crate::WebView`] is created in, and the memory limit of WebKit's processes.

use std::ffi::c_char;
use std::ptr;
use std::sync::OnceLock;
use std::sync::atomic::{ AtomicU32, Ordering };

use gobject_sys::g_object_new;
use wpe_webkit_sys::*;

use crate::types::CacheModel;

static MEMORY_LIMIT_MIB: AtomicU32       = AtomicU32::new( 0 );
static CONTEXT:          OnceLock<usize> = OnceLock::new();

/// 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.
pub fn set_memory_limit( mib: u32 )
{
	if mib == 0 { return; }
	MEMORY_LIMIT_MIB.store( mib, Ordering::Relaxed );
	// SAFETY: WebKit copies the settings, which are freed here.
	unsafe
	{
		let settings = memory_pressure_settings( mib );
		webkit_network_session_set_memory_pressure_settings( settings );
		webkit_memory_pressure_settings_free( settings );
	}
}

/// Creates the web context, so [`set_memory_limit`] has to come first.
pub fn set_cache_model( model: CacheModel )
{
	let model = match model
	{
		CacheModel::DocumentViewer  => WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER,
		CacheModel::DocumentBrowser => WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER,
		CacheModel::WebBrowser      => WEBKIT_CACHE_MODEL_WEB_BROWSER,
	};
	// SAFETY: the context lives for the process.
	unsafe { webkit_web_context_set_cache_model( web_context(), model ); }
}

/// Owned by the caller, to be freed with `webkit_memory_pressure_settings_free`.
fn memory_pressure_settings( mib: u32 ) -> *mut WebKitMemoryPressureSettings
{
	// SAFETY: a fresh allocation with no other reference to it.
	unsafe
	{
		let settings = webkit_memory_pressure_settings_new();
		webkit_memory_pressure_settings_set_memory_limit( settings, mib );
		settings
	}
}

/// Lives for the process. WebKit's default context unless a memory limit was set, which only a context's construction accepts.
pub( crate ) fn web_context() -> *mut WebKitWebContext
{
	let context = *CONTEXT.get_or_init( ||
	{
		let mib = MEMORY_LIMIT_MIB.load( Ordering::Relaxed );
		// SAFETY: the property name is NUL-terminated and the list NULL-terminated; GObject copies the boxed settings.
		unsafe
		{
			if mib == 0 { return webkit_web_context_get_default() as usize; }
			let settings = memory_pressure_settings( mib );
			let context  = g_object_new(
				webkit_web_context_get_type(),
				b"memory-pressure-settings\0".as_ptr() as *const c_char,
				settings,
				ptr::null::<c_char>(),
			);
			webkit_memory_pressure_settings_free( settings );
			if context.is_null() { webkit_web_context_get_default() as usize } else { context as usize }
		}
	} );
	context as *mut WebKitWebContext
}