use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU32, Ordering};
use cef::*;
use crate::new_tab::register_buffr_scheme;
use crate::view_source_scheme::register_buffr_src_scheme;
use hjkl_config;
static FORCE_RENDERER_ACCESSIBILITY: AtomicBool = AtomicBool::new(false);
static NEXT_MESSAGE_PUMP_DELAY_MS: AtomicI64 = AtomicI64::new(-1);
static DEVICE_SCALE_FACTOR_X1000: AtomicU32 = AtomicU32::new(0);
pub fn set_device_scale_factor(scale: f32) {
let v = (scale * 1000.0).round().max(0.0) as u32;
DEVICE_SCALE_FACTOR_X1000.store(v, Ordering::SeqCst);
}
pub fn device_scale_factor() -> Option<f32> {
let v = DEVICE_SCALE_FACTOR_X1000.load(Ordering::SeqCst);
(v > 0).then(|| v as f32 / 1000.0)
}
pub fn set_force_renderer_accessibility(on: bool) {
FORCE_RENDERER_ACCESSIBILITY.store(on, Ordering::SeqCst);
}
pub fn force_renderer_accessibility_enabled() -> bool {
FORCE_RENDERER_ACCESSIBILITY.load(Ordering::SeqCst)
}
pub fn take_scheduled_message_pump_delay_ms() -> Option<i64> {
let delay = NEXT_MESSAGE_PUMP_DELAY_MS.swap(-1, Ordering::SeqCst);
(delay >= 0).then_some(delay)
}
use buffr_engine::ProfilePaths;
wrap_app! {
pub struct BuffrApp;
impl App {
fn on_register_custom_schemes(&self, registrar: Option<&mut SchemeRegistrar>) {
if let Some(r) = registrar {
register_buffr_scheme(r);
register_buffr_src_scheme(r);
}
}
fn on_before_command_line_processing(
&self,
_process_type: Option<&CefString>,
command_line: Option<&mut CommandLine>,
) {
let Some(command_line) = command_line else { return };
append_switch_with_value(
command_line,
"enable-features",
"UseOzonePlatform,VaapiVideoDecodeLinuxGL,\
AcceleratedVideoDecodeLinuxGL,VaapiVideoEncoder,\
CanvasOopRasterization",
);
append_switch_with_value(
command_line,
"disable-features",
"AutofillServerCommunication,\
AutofillEnableAccountWalletStorage,\
PasswordManagerOnboarding,\
AutofillAddressProfileSavePromptNicknameSupport",
);
append_switch(command_line, "disable-save-password-bubble");
append_switch(command_line, "enable-gpu");
append_switch(command_line, "enable-gpu-compositing");
append_switch(command_line, "enable-gpu-rasterization");
append_switch(command_line, "enable-zero-copy");
append_switch(command_line, "ignore-gpu-blocklist");
append_switch(command_line, "no-sandbox");
#[cfg(all(target_os = "macos", debug_assertions))]
append_switch(command_line, "use-mock-keychain");
if force_renderer_accessibility_enabled() {
append_switch(command_line, "force-renderer-accessibility");
}
#[cfg(target_os = "linux")]
if let Some(scale) = device_scale_factor()
&& (scale - 1.0).abs() > 0.01
{
append_switch_with_value(
command_line,
"force-device-scale-factor",
&format!("{scale}"),
);
append_switch_with_value(command_line, "high-dpi-support", "1");
}
}
fn browser_process_handler(&self) -> Option<BrowserProcessHandler> {
Some(BuffrBrowserProcessHandler::new())
}
}
}
wrap_browser_process_handler! {
pub struct BuffrBrowserProcessHandler;
impl BrowserProcessHandler {
fn on_context_initialized(&self) {
tracing::debug!("cef: context initialized");
}
fn on_schedule_message_pump_work(&self, delay_ms: i64) {
tracing::trace!(delay_ms, "cef: schedule message pump work");
NEXT_MESSAGE_PUMP_DELAY_MS.store(delay_ms.max(0), Ordering::SeqCst);
}
}
}
fn append_switch(cmd: &CommandLine, name: &str) {
let name = CefString::from(name);
cmd.append_switch(Some(&name));
}
fn append_switch_with_value(cmd: &CommandLine, name: &str, value: &str) {
let name = CefString::from(name);
let value = CefString::from(value);
cmd.append_switch_with_value(Some(&name), Some(&value));
}
pub fn profile_paths() -> Result<ProfilePaths, buffr_core::CoreError> {
let cache =
hjkl_config::cache_dir("buffr").map_err(|_| buffr_core::CoreError::NoProjectDirs)?;
let data = hjkl_config::data_dir("buffr").map_err(|_| buffr_core::CoreError::NoProjectDirs)?;
Ok(ProfilePaths { cache, data })
}