Upload files to "src"
This commit is contained in:
parent
1dc9787944
commit
d51a9eabe9
2 changed files with 165 additions and 159 deletions
|
|
@ -16,7 +16,10 @@ pub enum LinuxBackend {
|
||||||
version
|
version
|
||||||
)]
|
)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
#[arg(long, help = "Optional startup URL (defaults to https://duckduckgo.com)")]
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "Optional startup URL (defaults to https://duckduckgo.com)"
|
||||||
|
)]
|
||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
|
|
||||||
#[arg(long, help = "Set a custom window title")]
|
#[arg(long, help = "Set a custom window title")]
|
||||||
|
|
@ -32,7 +35,7 @@ pub struct Cli {
|
||||||
long,
|
long,
|
||||||
value_enum,
|
value_enum,
|
||||||
default_value_t = LinuxBackend::Auto,
|
default_value_t = LinuxBackend::Auto,
|
||||||
help = "Linux only: prefer a windowing backend (auto, x11, wayland)"
|
help = "Linux only: select a GTK windowing backend (auto, x11, wayland)"
|
||||||
)]
|
)]
|
||||||
pub linux_backend: LinuxBackend,
|
pub linux_backend: LinuxBackend,
|
||||||
|
|
||||||
|
|
|
||||||
281
src/webview.rs
281
src/webview.rs
|
|
@ -2,6 +2,8 @@
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use gtk::prelude::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
@ -9,13 +11,11 @@ use std::path::{Path, PathBuf};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use gtk::prelude::*;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use tao::platform::unix::WindowExtUnix;
|
|
||||||
use tao::dpi::LogicalSize;
|
use tao::dpi::LogicalSize;
|
||||||
use tao::event::{Event, WindowEvent};
|
use tao::event::{Event, WindowEvent};
|
||||||
use tao::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy};
|
use tao::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use tao::platform::unix::WindowExtUnix;
|
||||||
use tao::window::{Icon, Window, WindowBuilder};
|
use tao::window::{Icon, Window, WindowBuilder};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use wry::WebViewBuilderExtUnix;
|
use wry::WebViewBuilderExtUnix;
|
||||||
|
|
@ -38,13 +38,31 @@ const MAX_TAB_NAV_ENTRIES: usize = 100;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum UserEvent {
|
enum UserEvent {
|
||||||
ChromeIpc(String),
|
ChromeIpc(String),
|
||||||
TitleChanged { tab_id: u32, title: String },
|
TitleChanged {
|
||||||
PageLoaded { tab_id: u32, url: String },
|
tab_id: u32,
|
||||||
DownloadStarted { url: String, file_path: String },
|
title: String,
|
||||||
DownloadTotal { file_path: String, total_bytes: Option<u64> },
|
},
|
||||||
|
PageLoaded {
|
||||||
|
tab_id: u32,
|
||||||
|
url: String,
|
||||||
|
},
|
||||||
|
DownloadStarted {
|
||||||
|
url: String,
|
||||||
|
file_path: String,
|
||||||
|
},
|
||||||
|
DownloadTotal {
|
||||||
|
file_path: String,
|
||||||
|
total_bytes: Option<u64>,
|
||||||
|
},
|
||||||
DownloadTick,
|
DownloadTick,
|
||||||
DownloadCompleted { url: String, file_path: Option<String>, success: bool },
|
DownloadCompleted {
|
||||||
OpenInNewTab { url: String },
|
url: String,
|
||||||
|
file_path: Option<String>,
|
||||||
|
success: bool,
|
||||||
|
},
|
||||||
|
OpenInNewTab {
|
||||||
|
url: String,
|
||||||
|
},
|
||||||
Quit,
|
Quit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -713,7 +731,10 @@ pub fn launch_webkit(args: &Cli) -> Result<()> {
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.map(normalize_url)
|
.map(normalize_url)
|
||||||
.unwrap_or_else(|| DEFAULT_HOME.to_string());
|
.unwrap_or_else(|| DEFAULT_HOME.to_string());
|
||||||
let title = args.title.clone().unwrap_or_else(|| "RustyWolf".to_string());
|
let title = args
|
||||||
|
.title
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| "RustyWolf".to_string());
|
||||||
|
|
||||||
if args.dry_run {
|
if args.dry_run {
|
||||||
println!(
|
println!(
|
||||||
|
|
@ -773,11 +794,13 @@ pub fn launch_webkit(args: &Cli) -> Result<()> {
|
||||||
open_tab(&mut state, &window, &proxy, start_url)?;
|
open_tab(&mut state, &window, &proxy, start_url)?;
|
||||||
|
|
||||||
let tick_proxy = proxy.clone();
|
let tick_proxy = proxy.clone();
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || {
|
||||||
|
loop {
|
||||||
thread::sleep(Duration::from_millis(300));
|
thread::sleep(Duration::from_millis(300));
|
||||||
if tick_proxy.send_event(UserEvent::DownloadTick).is_err() {
|
if tick_proxy.send_event(UserEvent::DownloadTick).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
|
@ -790,10 +813,16 @@ pub fn launch_webkit(args: &Cli) -> Result<()> {
|
||||||
eprintln!("event error: {e:#}");
|
eprintln!("event error: {e:#}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::WindowEvent { event: WindowEvent::Resized(_size), .. } => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Resized(_size),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
reflow_layout(&window, &state);
|
reflow_layout(&window, &state);
|
||||||
}
|
}
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -808,18 +837,14 @@ fn apply_linux_runtime_overrides(_args: &Cli) {
|
||||||
|
|
||||||
match _args.linux_backend {
|
match _args.linux_backend {
|
||||||
crate::cli::LinuxBackend::Auto => {}
|
crate::cli::LinuxBackend::Auto => {}
|
||||||
crate::cli::LinuxBackend::X11 => {
|
crate::cli::LinuxBackend::X11 => unsafe {
|
||||||
unsafe {
|
|
||||||
std::env::set_var("WINIT_UNIX_BACKEND", "x11");
|
std::env::set_var("WINIT_UNIX_BACKEND", "x11");
|
||||||
std::env::set_var("GDK_BACKEND", "x11");
|
std::env::set_var("GDK_BACKEND", "x11");
|
||||||
}
|
},
|
||||||
}
|
crate::cli::LinuxBackend::Wayland => unsafe {
|
||||||
crate::cli::LinuxBackend::Wayland => {
|
|
||||||
unsafe {
|
|
||||||
std::env::set_var("WINIT_UNIX_BACKEND", "wayland");
|
std::env::set_var("WINIT_UNIX_BACKEND", "wayland");
|
||||||
std::env::set_var("GDK_BACKEND", "wayland");
|
std::env::set_var("GDK_BACKEND", "wayland");
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _args.linux_disable_dmabuf {
|
if _args.linux_disable_dmabuf {
|
||||||
|
|
@ -844,7 +869,9 @@ fn sanitize_gtk_modules_env() {
|
||||||
match std::env::var(name) {
|
match std::env::var(name) {
|
||||||
Ok(raw) => {
|
Ok(raw) => {
|
||||||
let mut kept = Vec::new();
|
let mut kept = Vec::new();
|
||||||
for token in raw.split(|c: char| c == ':' || c == ';' || c == ',' || c.is_ascii_whitespace()) {
|
for token in
|
||||||
|
raw.split(|c: char| c == ':' || c == ';' || c == ',' || c.is_ascii_whitespace())
|
||||||
|
{
|
||||||
let trimmed = token.trim();
|
let trimmed = token.trim();
|
||||||
if trimmed.is_empty() || is_appmenu_module(trimmed) {
|
if trimmed.is_empty() || is_appmenu_module(trimmed) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -882,27 +909,8 @@ fn sanitize_gtk_modules_env() {
|
||||||
fn resolve_webview_host_mode(args: &Cli) -> WebViewHostMode {
|
fn resolve_webview_host_mode(args: &Cli) -> WebViewHostMode {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
return match args.linux_backend {
|
let _ = args;
|
||||||
crate::cli::LinuxBackend::X11 => WebViewHostMode::Child,
|
|
||||||
crate::cli::LinuxBackend::Wayland => WebViewHostMode::Window,
|
|
||||||
crate::cli::LinuxBackend::Auto => {
|
|
||||||
let forced = std::env::var("WINIT_UNIX_BACKEND").ok();
|
|
||||||
if forced.as_deref() == Some("x11") {
|
|
||||||
return WebViewHostMode::Child;
|
|
||||||
}
|
|
||||||
if forced.as_deref() == Some("wayland") {
|
|
||||||
return WebViewHostMode::Window;
|
|
||||||
}
|
|
||||||
|
|
||||||
let session_type = std::env::var("XDG_SESSION_TYPE").unwrap_or_default();
|
|
||||||
let has_wayland_display = std::env::var_os("WAYLAND_DISPLAY").is_some();
|
|
||||||
if session_type.eq_ignore_ascii_case("wayland") || has_wayland_display {
|
|
||||||
WebViewHostMode::Window
|
WebViewHostMode::Window
|
||||||
} else {
|
|
||||||
WebViewHostMode::Child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
|
@ -956,7 +964,11 @@ fn handle_event(
|
||||||
state.tabs[i].url.clone(),
|
state.tabs[i].url.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let enabled = if state.adblock_enabled { "true" } else { "false" };
|
let enabled = if state.adblock_enabled {
|
||||||
|
"true"
|
||||||
|
} else {
|
||||||
|
"false"
|
||||||
|
};
|
||||||
if let Some(webview) = state.tabs[i].webview.as_ref() {
|
if let Some(webview) = state.tabs[i].webview.as_ref() {
|
||||||
let _ = webview.evaluate_script(&format!(
|
let _ = webview.evaluate_script(&format!(
|
||||||
"window.__rustywolfSetAdblockEnabled && window.__rustywolfSetAdblockEnabled({enabled});"
|
"window.__rustywolfSetAdblockEnabled && window.__rustywolfSetAdblockEnabled({enabled});"
|
||||||
|
|
@ -979,7 +991,10 @@ fn handle_event(
|
||||||
trim_downloads(state);
|
trim_downloads(state);
|
||||||
push_downloads(state);
|
push_downloads(state);
|
||||||
}
|
}
|
||||||
UserEvent::DownloadTotal { file_path, total_bytes } => {
|
UserEvent::DownloadTotal {
|
||||||
|
file_path,
|
||||||
|
total_bytes,
|
||||||
|
} => {
|
||||||
if let Some(entry) = state
|
if let Some(entry) = state
|
||||||
.downloads
|
.downloads
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
|
@ -1005,7 +1020,11 @@ fn handle_event(
|
||||||
push_downloads(state);
|
push_downloads(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UserEvent::DownloadCompleted { url, file_path, success } => {
|
UserEvent::DownloadCompleted {
|
||||||
|
url,
|
||||||
|
file_path,
|
||||||
|
success,
|
||||||
|
} => {
|
||||||
let path = file_path.unwrap_or_else(|| "Unknown destination".to_string());
|
let path = file_path.unwrap_or_else(|| "Unknown destination".to_string());
|
||||||
if let Some(entry) = state
|
if let Some(entry) = state
|
||||||
.downloads
|
.downloads
|
||||||
|
|
@ -1262,25 +1281,15 @@ fn build_chrome(
|
||||||
WebViewHostMode::Window => {
|
WebViewHostMode::Window => {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
if let Some(container) = gtk_chrome_container {
|
let container = gtk_chrome_container.ok_or_else(|| {
|
||||||
match builder().build_gtk(container) {
|
anyhow!("Failed to create chrome webview: missing Linux GTK chrome container")
|
||||||
Ok(webview) => return Ok((webview, WebViewHostMode::Window)),
|
})?;
|
||||||
Err(gtk_err) => {
|
builder()
|
||||||
return builder()
|
.build_gtk(container)
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
.map(|webview| (webview, WebViewHostMode::Window))
|
||||||
.map_err(|fallback_err| {
|
.map_err(|err| {
|
||||||
anyhow!(
|
anyhow!("Failed to create chrome webview with GTK hosting: {err}")
|
||||||
"Failed to create chrome webview: gtk hosting failed ({gtk_err}); window fallback failed ({fallback_err})"
|
})
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder()
|
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
|
||||||
.map_err(|err| anyhow!("Failed to create chrome webview: {err}"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
|
@ -1302,28 +1311,18 @@ fn build_chrome(
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
if let Some(container) = gtk_chrome_container {
|
if let Some(container) = gtk_chrome_container {
|
||||||
match builder().build_gtk(container) {
|
|
||||||
Ok(webview) => return Ok((webview, WebViewHostMode::Window)),
|
|
||||||
Err(gtk_err) => {
|
|
||||||
return builder()
|
return builder()
|
||||||
.build(window)
|
.build_gtk(container)
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
.map(|webview| (webview, WebViewHostMode::Window))
|
||||||
.map_err(|fallback_err| {
|
.map_err(|gtk_err| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to create chrome webview: child failed ({err_text}); gtk fallback failed ({gtk_err}); window fallback failed ({fallback_err})"
|
"Failed to create chrome webview: child failed ({err_text}); GTK fallback failed ({gtk_err})"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
return Err(anyhow!(
|
||||||
}
|
"Failed to create chrome webview: child failed ({err_text}); missing Linux GTK chrome container"
|
||||||
return builder()
|
));
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
|
||||||
.map_err(|fallback_err| {
|
|
||||||
anyhow!(
|
|
||||||
"Failed to create chrome webview: child failed ({err_text}); window fallback failed ({fallback_err})"
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
|
@ -1405,7 +1404,11 @@ fn build_tab_webview(
|
||||||
}
|
}
|
||||||
*destination = path.clone();
|
*destination = path.clone();
|
||||||
let path_string = path_to_string(&path);
|
let path_string = path_to_string(&path);
|
||||||
fetch_download_total(url.clone(), path_string.clone(), download_total_proxy.clone());
|
fetch_download_total(
|
||||||
|
url.clone(),
|
||||||
|
path_string.clone(),
|
||||||
|
download_total_proxy.clone(),
|
||||||
|
);
|
||||||
let _ = download_started_proxy.send_event(UserEvent::DownloadStarted {
|
let _ = download_started_proxy.send_event(UserEvent::DownloadStarted {
|
||||||
url,
|
url,
|
||||||
file_path: path_string,
|
file_path: path_string,
|
||||||
|
|
@ -1425,25 +1428,13 @@ fn build_tab_webview(
|
||||||
WebViewHostMode::Window => {
|
WebViewHostMode::Window => {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
if let Some(container) = gtk_content_container {
|
let container = gtk_content_container.ok_or_else(|| {
|
||||||
match builder().build_gtk(container) {
|
anyhow!("Failed to create tab webview: missing Linux GTK content container")
|
||||||
Ok(webview) => return Ok((webview, WebViewHostMode::Window)),
|
})?;
|
||||||
Err(gtk_err) => {
|
builder()
|
||||||
return builder()
|
.build_gtk(container)
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
.map(|webview| (webview, WebViewHostMode::Window))
|
||||||
.map_err(|fallback_err| {
|
.map_err(|err| anyhow!("Failed to create tab webview with GTK hosting: {err}"))
|
||||||
anyhow!(
|
|
||||||
"Failed to create tab webview: gtk hosting failed ({gtk_err}); window fallback failed ({fallback_err})"
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder()
|
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
|
||||||
.map_err(|err| anyhow!("Failed to create tab webview: {err}"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
|
@ -1465,28 +1456,18 @@ fn build_tab_webview(
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
if let Some(container) = gtk_content_container {
|
if let Some(container) = gtk_content_container {
|
||||||
match builder().build_gtk(container) {
|
|
||||||
Ok(webview) => return Ok((webview, WebViewHostMode::Window)),
|
|
||||||
Err(gtk_err) => {
|
|
||||||
return builder()
|
return builder()
|
||||||
.build(window)
|
.build_gtk(container)
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
.map(|webview| (webview, WebViewHostMode::Window))
|
||||||
.map_err(|fallback_err| {
|
.map_err(|gtk_err| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to create tab webview: child failed ({err_text}); gtk fallback failed ({gtk_err}); window fallback failed ({fallback_err})"
|
"Failed to create tab webview: child failed ({err_text}); GTK fallback failed ({gtk_err})"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
return Err(anyhow!(
|
||||||
}
|
"Failed to create tab webview: child failed ({err_text}); missing Linux GTK content container"
|
||||||
return builder()
|
));
|
||||||
.build(window)
|
|
||||||
.map(|webview| (webview, WebViewHostMode::Window))
|
|
||||||
.map_err(|fallback_err| {
|
|
||||||
anyhow!(
|
|
||||||
"Failed to create tab webview: child failed ({err_text}); window fallback failed ({fallback_err})"
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
|
@ -1580,7 +1561,9 @@ fn close_tab(
|
||||||
proxy: &EventLoopProxy<UserEvent>,
|
proxy: &EventLoopProxy<UserEvent>,
|
||||||
tab_id: u32,
|
tab_id: u32,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let Some(index) = state.find_index(tab_id) else { return Ok(false); };
|
let Some(index) = state.find_index(tab_id) else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
state.tabs.remove(index);
|
state.tabs.remove(index);
|
||||||
|
|
||||||
if state.tabs.is_empty() {
|
if state.tabs.is_empty() {
|
||||||
|
|
@ -1669,7 +1652,9 @@ fn apply_visibility(state: &BrowserState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_tabs(state: &BrowserState) {
|
fn push_tabs(state: &BrowserState) {
|
||||||
if state.tabs.is_empty() { return; }
|
if state.tabs.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let payload = json!({
|
let payload = json!({
|
||||||
"tabs": state.tabs.iter().map(|t| json!({
|
"tabs": state.tabs.iter().map(|t| json!({
|
||||||
"id": t.id,
|
"id": t.id,
|
||||||
|
|
@ -1705,15 +1690,19 @@ fn push_downloads(state: &BrowserState) {
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
.to_string();
|
.to_string();
|
||||||
let script = format!(
|
let script =
|
||||||
"window.__rustywolfSetDownloads && window.__rustywolfSetDownloads({payload});"
|
format!("window.__rustywolfSetDownloads && window.__rustywolfSetDownloads({payload});");
|
||||||
);
|
|
||||||
let _ = state.chrome.evaluate_script(&script);
|
let _ = state.chrome.evaluate_script(&script);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_adblock(state: &BrowserState) {
|
fn push_adblock(state: &BrowserState) {
|
||||||
let enabled = if state.adblock_enabled { "true" } else { "false" };
|
let enabled = if state.adblock_enabled {
|
||||||
let script = format!("window.__rustywolfSetAdblock && window.__rustywolfSetAdblock({enabled});");
|
"true"
|
||||||
|
} else {
|
||||||
|
"false"
|
||||||
|
};
|
||||||
|
let script =
|
||||||
|
format!("window.__rustywolfSetAdblock && window.__rustywolfSetAdblock({enabled});");
|
||||||
let _ = state.chrome.evaluate_script(&script);
|
let _ = state.chrome.evaluate_script(&script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1726,14 +1715,17 @@ fn push_popup_prompt(state: &BrowserState) {
|
||||||
None => json!({ "visible": false }),
|
None => json!({ "visible": false }),
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
let script = format!(
|
let script =
|
||||||
"window.__rustywolfSetPopupPrompt && window.__rustywolfSetPopupPrompt({payload});"
|
format!("window.__rustywolfSetPopupPrompt && window.__rustywolfSetPopupPrompt({payload});");
|
||||||
);
|
|
||||||
let _ = state.chrome.evaluate_script(&script);
|
let _ = state.chrome.evaluate_script(&script);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_adblock_setting_to_tabs(state: &BrowserState) {
|
fn apply_adblock_setting_to_tabs(state: &BrowserState) {
|
||||||
let enabled = if state.adblock_enabled { "true" } else { "false" };
|
let enabled = if state.adblock_enabled {
|
||||||
|
"true"
|
||||||
|
} else {
|
||||||
|
"false"
|
||||||
|
};
|
||||||
let script = format!(
|
let script = format!(
|
||||||
"window.__rustywolfSetAdblockEnabled && window.__rustywolfSetAdblockEnabled({enabled});"
|
"window.__rustywolfSetAdblockEnabled && window.__rustywolfSetAdblockEnabled({enabled});"
|
||||||
);
|
);
|
||||||
|
|
@ -1860,7 +1852,9 @@ fn chrome_height(state: &BrowserState) -> f64 {
|
||||||
|
|
||||||
fn normalize_url(input: &str) -> String {
|
fn normalize_url(input: &str) -> String {
|
||||||
let trimmed = input.trim();
|
let trimmed = input.trim();
|
||||||
if trimmed == "about:blank" { return trimmed.to_string(); }
|
if trimmed == "about:blank" {
|
||||||
|
return trimmed.to_string();
|
||||||
|
}
|
||||||
if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
|
if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
|
||||||
return trimmed.to_string();
|
return trimmed.to_string();
|
||||||
}
|
}
|
||||||
|
|
@ -1963,8 +1957,7 @@ fn render_properties_html(state: &BrowserState) -> String {
|
||||||
<body><h1>Browser Properties</h1><p class=\"muted\">Session history and download activity.</p>\
|
<body><h1>Browser Properties</h1><p class=\"muted\">Session history and download activity.</p>\
|
||||||
<h2>Browsing History</h2><p class=\"muted\">{}</p><table><thead><tr><th>Visited</th><th>Title</th><th>URL</th></tr></thead><tbody>{history_rows}</tbody></table>\
|
<h2>Browsing History</h2><p class=\"muted\">{}</p><table><thead><tr><th>Visited</th><th>Title</th><th>URL</th></tr></thead><tbody>{history_rows}</tbody></table>\
|
||||||
<h2>Download History</h2><p class=\"muted\">{}</p><table><thead><tr><th>Updated</th><th>Status</th><th>Saved To</th><th>Source URL</th></tr></thead><tbody>{download_rows}</tbody></table>\
|
<h2>Download History</h2><p class=\"muted\">{}</p><table><thead><tr><th>Updated</th><th>Status</th><th>Saved To</th><th>Source URL</th></tr></thead><tbody>{download_rows}</tbody></table>\
|
||||||
</body></html>"
|
</body></html>",
|
||||||
,
|
|
||||||
if history_is_truncated {
|
if history_is_truncated {
|
||||||
format!("Showing latest {PROPERTIES_MAX_ROWS} entries.")
|
format!("Showing latest {PROPERTIES_MAX_ROWS} entries.")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2105,8 +2098,8 @@ fn path_string_to_file_url(path: &str) -> String {
|
||||||
fn sanitize_filename(raw: &str) -> String {
|
fn sanitize_filename(raw: &str) -> String {
|
||||||
let mut out = String::with_capacity(raw.len());
|
let mut out = String::with_capacity(raw.len());
|
||||||
for ch in raw.chars() {
|
for ch in raw.chars() {
|
||||||
let invalid = matches!(ch, '<' | '>' | ':' | '"' | '/' | '\\' | '|' | '?' | '*')
|
let invalid =
|
||||||
|| ch.is_control();
|
matches!(ch, '<' | '>' | ':' | '"' | '/' | '\\' | '|' | '?' | '*') || ch.is_control();
|
||||||
out.push(if invalid { '_' } else { ch });
|
out.push(if invalid { '_' } else { ch });
|
||||||
}
|
}
|
||||||
let trimmed = out.trim_matches('.').trim();
|
let trimmed = out.trim_matches('.').trim();
|
||||||
|
|
@ -2119,10 +2112,10 @@ fn sanitize_filename(raw: &str) -> String {
|
||||||
|
|
||||||
fn fetch_download_total(url: String, file_path: String, proxy: EventLoopProxy<UserEvent>) {
|
fn fetch_download_total(url: String, file_path: String, proxy: EventLoopProxy<UserEvent>) {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let total_bytes = ureq::head(&url)
|
let total_bytes = ureq::head(&url).call().ok().and_then(|resp| {
|
||||||
.call()
|
resp.header("Content-Length")
|
||||||
.ok()
|
.and_then(|v| v.parse::<u64>().ok())
|
||||||
.and_then(|resp| resp.header("Content-Length").and_then(|v| v.parse::<u64>().ok()));
|
});
|
||||||
let _ = proxy.send_event(UserEvent::DownloadTotal {
|
let _ = proxy.send_event(UserEvent::DownloadTotal {
|
||||||
file_path,
|
file_path,
|
||||||
total_bytes,
|
total_bytes,
|
||||||
|
|
@ -2162,7 +2155,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn converts_search_terms_to_duckduckgo_query() {
|
fn converts_search_terms_to_duckduckgo_query() {
|
||||||
assert_eq!(normalize_url("privacy browser"), "https://duckduckgo.com/?q=privacy+browser");
|
assert_eq!(
|
||||||
|
normalize_url("privacy browser"),
|
||||||
|
"https://duckduckgo.com/?q=privacy+browser"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -2172,7 +2168,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trims_before_search() {
|
fn trims_before_search() {
|
||||||
assert_eq!(normalize_url(" rust webview "), "https://duckduckgo.com/?q=rust+webview");
|
assert_eq!(
|
||||||
|
normalize_url(" rust webview "),
|
||||||
|
"https://duckduckgo.com/?q=rust+webview"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -2183,9 +2182,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blocks_duckduckgo_internal_popup_paths() {
|
fn blocks_duckduckgo_internal_popup_paths() {
|
||||||
assert!(!should_open_new_tab_url("https://duckduckgo.com/post3.html"));
|
assert!(!should_open_new_tab_url(
|
||||||
|
"https://duckduckgo.com/post3.html"
|
||||||
|
));
|
||||||
assert!(!should_open_new_tab_url("https://duckduckgo.com/page3"));
|
assert!(!should_open_new_tab_url("https://duckduckgo.com/page3"));
|
||||||
assert!(!should_open_new_tab_url("https://duckduckgo.com/page3.html"));
|
assert!(!should_open_new_tab_url(
|
||||||
|
"https://duckduckgo.com/page3.html"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue