(chore): update codebase
This commit is contained in:
parent
fd15215f15
commit
4e8d46b20e
106 changed files with 29936 additions and 1023 deletions
55
apps/tauri/src-tauri/vendor/tauri-runtime-cef/Cargo.toml
vendored
Normal file
55
apps/tauri/src-tauri/vendor/tauri-runtime-cef/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
[package]
|
||||
name = "tauri-runtime-cef"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
categories.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
dioxus-debug-cell = "0.1"
|
||||
tauri-runtime = { version = "2.9.2", path = "../tauri-runtime" }
|
||||
tauri-utils = { version = "2.8.0", path = "../tauri-utils", features = [
|
||||
"html-manipulation",
|
||||
] }
|
||||
html5ever = "0.29"
|
||||
raw-window-handle = "0.6"
|
||||
url = "2"
|
||||
http = "1"
|
||||
cef = { version = "=146.4.1", default-features = false }
|
||||
# Not actually used directly, just locking it.
|
||||
cef-dll-sys = "=146.4.1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
kuchiki = { package = "kuchikiki", version = "0.8.8-speedreader" }
|
||||
sha2 = "0.10"
|
||||
base64 = "0.22"
|
||||
dirs = "6"
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
windows = { version = "0.61", features = [
|
||||
"Win32_Graphics",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_UI_HiDpi",
|
||||
"Win32_UI_Input",
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_System_LibraryLoader",
|
||||
] }
|
||||
|
||||
[target."cfg(target_os = \"macos\")".dependencies]
|
||||
objc2 = "0.6"
|
||||
objc2-app-kit = { version = "0.3", features = [] }
|
||||
objc2-foundation = { version = "0.3", features = ["NSNotification"] }
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||
gtk = { version = "0.18", features = ["v3_24"] }
|
||||
x11-dl = "2.21"
|
||||
|
||||
[features]
|
||||
default = ["sandbox"]
|
||||
devtools = []
|
||||
macos-private-api = ["tauri-runtime/macos-private-api"]
|
||||
sandbox = ["cef/sandbox"]
|
||||
4351
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl.rs
vendored
Normal file
4351
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
82
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/cookie.rs
vendored
Normal file
82
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/cookie.rs
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use cef::{rc::*, *};
|
||||
use std::sync::{Arc, Mutex, mpsc::Sender};
|
||||
|
||||
cef::wrap_cookie_visitor! {
|
||||
pub struct CollectUrlCookiesVisitor {
|
||||
pub tx: Sender<tauri_runtime::Result<Vec<tauri_runtime::Cookie<'static>>>>,
|
||||
pub collected: Arc<Mutex<Vec<tauri_runtime::Cookie<'static>>>>,
|
||||
}
|
||||
|
||||
impl CookieVisitor {
|
||||
fn visit(
|
||||
&self,
|
||||
cookie: Option<&cef::Cookie>,
|
||||
count: ::std::os::raw::c_int,
|
||||
total: ::std::os::raw::c_int,
|
||||
_delete_cookie: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
if let Some(c) = cookie {
|
||||
let name = c.name.to_string();
|
||||
let value = c.value.to_string();
|
||||
let domain = c.domain.to_string();
|
||||
let path = c.path.to_string();
|
||||
|
||||
let mut builder = tauri_runtime::Cookie::build((name, value));
|
||||
if !domain.is_empty() { builder = builder.domain(domain); }
|
||||
if !path.is_empty() { builder = builder.path(path); }
|
||||
if c.secure == 1 { builder = builder.secure(true); }
|
||||
if c.httponly == 1 { builder = builder.http_only(true); }
|
||||
let ck = builder.build();
|
||||
|
||||
self.collected.lock().unwrap().push(ck.into_owned());
|
||||
}
|
||||
|
||||
if (count + 1) >= total {
|
||||
let _ = self.tx.send(Ok(self.collected.lock().unwrap().clone()));
|
||||
}
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cef::wrap_cookie_visitor! {
|
||||
pub struct CollectAllCookiesVisitor {
|
||||
pub tx: Sender<tauri_runtime::Result<Vec<tauri_runtime::Cookie<'static>>>>,
|
||||
pub collected: Arc<Mutex<Vec<tauri_runtime::Cookie<'static>>>>,
|
||||
}
|
||||
|
||||
impl CookieVisitor {
|
||||
fn visit(
|
||||
&self,
|
||||
cookie: Option<&cef::Cookie>,
|
||||
count: ::std::os::raw::c_int,
|
||||
total: ::std::os::raw::c_int,
|
||||
_delete_cookie: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
if let Some(c) = cookie {
|
||||
let name = c.name.to_string();
|
||||
let value = c.value.to_string();
|
||||
let domain = c.domain.to_string();
|
||||
let path = c.path.to_string();
|
||||
|
||||
let mut builder = tauri_runtime::Cookie::build((name, value));
|
||||
if !domain.is_empty() { builder = builder.domain(domain); }
|
||||
if !path.is_empty() { builder = builder.path(path); }
|
||||
if c.secure == 1 { builder = builder.secure(true); }
|
||||
if c.httponly == 1 { builder = builder.http_only(true); }
|
||||
let ck = builder.build();
|
||||
|
||||
self.collected.lock().unwrap().push(ck.into_owned());
|
||||
}
|
||||
|
||||
if (count + 1) >= total {
|
||||
let _ = self.tx.send(Ok(self.collected.lock().unwrap().clone()));
|
||||
}
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
72
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/drag_window.rs
vendored
Normal file
72
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/drag_window.rs
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows {
|
||||
use cef::*;
|
||||
use windows::Win32::Foundation::*;
|
||||
use windows::Win32::UI::WindowsAndMessaging::*;
|
||||
use windows::core::{PCWSTR, w};
|
||||
|
||||
/// Same as [WNDPROC] but without the Option wrapper.
|
||||
type WindowProc = unsafe extern "system" fn(HWND, u32, WPARAM, LPARAM) -> LRESULT;
|
||||
|
||||
const ORIGINAL_WND_PROP: PCWSTR = w!("TAURI_CEF_ORIGINAL_WND_PROC");
|
||||
|
||||
/// Subclasses the given window to handle draggable regions
|
||||
/// by replacing its window procedure with `root_window_proc`
|
||||
/// and storing the original procedure as a property to be called later.
|
||||
pub fn subclass_window_for_dragging(window: &mut cef::Window) {
|
||||
let hwnd = window.window_handle();
|
||||
let hwnd = HWND(hwnd.0 as _);
|
||||
subclass_window(hwnd, root_window_proc);
|
||||
}
|
||||
|
||||
/// Subclasses a window by replacing its window procedure with the given `proc`
|
||||
/// and storing the original procedure as a property for later use.
|
||||
fn subclass_window(hwnd: HWND, proc: WindowProc) {
|
||||
// If already subclassed, return early
|
||||
let orginial_wnd_proc = unsafe { GetPropW(hwnd, ORIGINAL_WND_PROP) };
|
||||
if !orginial_wnd_proc.is_invalid() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset last error
|
||||
unsafe { SetLastError(ERROR_SUCCESS) };
|
||||
|
||||
// Set the new window procedure and get the orginal one
|
||||
let original_wnd_proc = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, proc as isize) };
|
||||
if original_wnd_proc == 0 && unsafe { GetLastError() } != ERROR_SUCCESS {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Store the original window proc as a property for later use
|
||||
let _ = SetPropW(
|
||||
hwnd,
|
||||
ORIGINAL_WND_PROP,
|
||||
Some(HANDLE(original_wnd_proc as _)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The root window procedure to handle WM_NCLBUTTONDOWN
|
||||
/// by calling DefWindowProcW directly to allow dragging
|
||||
/// and forwarding other messages to the original CEF window procedure.
|
||||
unsafe extern "system" fn root_window_proc(
|
||||
hwnd: HWND,
|
||||
msg: u32,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> LRESULT {
|
||||
if msg == WM_NCLBUTTONDOWN {
|
||||
return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) };
|
||||
}
|
||||
|
||||
// For other messages, call the original CEF window procedure
|
||||
let original_wnd_proc = GetPropW(hwnd, ORIGINAL_WND_PROP);
|
||||
let original_wnd_proc = std::mem::transmute::<_, WindowProc>(original_wnd_proc.0);
|
||||
CallWindowProcW(Some(original_wnd_proc), hwnd, msg, wparam, lparam)
|
||||
}
|
||||
}
|
||||
432
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/request_handler.rs
vendored
Normal file
432
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_impl/request_handler.rs
vendored
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
io::{Cursor, Read},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use cef::{rc::*, *};
|
||||
use dioxus_debug_cell::RefCell;
|
||||
use html5ever::{LocalName, interface::QualName, namespace_url, ns};
|
||||
use http::{
|
||||
HeaderMap, HeaderName, HeaderValue,
|
||||
header::{CONTENT_SECURITY_POLICY, CONTENT_TYPE},
|
||||
};
|
||||
use kuchiki::NodeRef;
|
||||
use tauri_runtime::webview::UriSchemeProtocolHandler;
|
||||
use tauri_utils::{
|
||||
config::{Csp, CspDirectiveSources},
|
||||
html::{parse as parse_html, serialize_node},
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use super::CefInitScript;
|
||||
|
||||
type HttpResponse = Arc<RefCell<Option<http::Response<Cursor<Vec<u8>>>>>>;
|
||||
|
||||
fn csp_inject_initialization_scripts_hashes(
|
||||
existing_csp: String,
|
||||
initialization_scripts: &[CefInitScript],
|
||||
) -> String {
|
||||
if initialization_scripts.is_empty() {
|
||||
return existing_csp;
|
||||
}
|
||||
|
||||
// For custom schemes, include ALL script hashes (we inject all scripts into HTML)
|
||||
// This matches the HTML injection behavior in inject_scripts_into_html_body
|
||||
let script_hashes: Vec<String> = initialization_scripts
|
||||
.iter()
|
||||
.map(|s| s.hash.clone())
|
||||
.collect();
|
||||
|
||||
if script_hashes.is_empty() {
|
||||
return existing_csp;
|
||||
}
|
||||
|
||||
// Parse CSP using tauri-utils
|
||||
let mut csp_map: std::collections::HashMap<String, CspDirectiveSources> =
|
||||
Csp::Policy(existing_csp.to_string()).into();
|
||||
|
||||
// Update or create script-src directive with script hashes
|
||||
let script_src = csp_map
|
||||
.entry("script-src".to_string())
|
||||
.or_insert_with(|| CspDirectiveSources::List(vec!["'self'".to_string()]));
|
||||
|
||||
// Extend with script hashes
|
||||
script_src.extend(script_hashes);
|
||||
|
||||
// Convert back to CSP string
|
||||
Csp::DirectiveMap(csp_map).to_string()
|
||||
}
|
||||
|
||||
/// Helper function to inject initialization scripts into HTML body
|
||||
fn inject_scripts_into_html_body(
|
||||
body: &[u8],
|
||||
initialization_scripts: &[CefInitScript],
|
||||
) -> Option<Vec<u8>> {
|
||||
// Check if body is valid UTF-8 HTML
|
||||
let Ok(body_str) = std::str::from_utf8(body) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// Parse HTML and inject scripts
|
||||
let document = parse_html(body_str.to_string());
|
||||
|
||||
let head = if let Ok(ref head_node) = document.select_first("head") {
|
||||
head_node.as_node().clone()
|
||||
} else {
|
||||
let head_node = NodeRef::new_element(
|
||||
QualName::new(None, ns!(html), LocalName::from("head")),
|
||||
None,
|
||||
);
|
||||
document.prepend(head_node.clone());
|
||||
head_node
|
||||
};
|
||||
|
||||
// Inject initialization scripts (for custom schemes, inject all scripts)
|
||||
for init_script in initialization_scripts.iter().rev() {
|
||||
let script_el = NodeRef::new_element(QualName::new(None, ns!(html), "script".into()), None);
|
||||
script_el.append(NodeRef::new_text(init_script.script.script.as_str()));
|
||||
head.prepend(script_el);
|
||||
}
|
||||
|
||||
// Serialize the modified HTML
|
||||
Some(serialize_node(&document))
|
||||
}
|
||||
|
||||
wrap_resource_request_handler! {
|
||||
pub struct WebResourceRequestHandler {
|
||||
initialization_scripts: Arc<Vec<CefInitScript>>,
|
||||
}
|
||||
|
||||
impl ResourceRequestHandler {
|
||||
|
||||
|
||||
fn on_before_resource_load(
|
||||
&self,
|
||||
_browser: Option<&mut Browser>,
|
||||
_frame: Option<&mut Frame>,
|
||||
_request: Option<&mut Request>,
|
||||
_callback: Option<&mut Callback>,
|
||||
) -> ReturnValue {
|
||||
sys::cef_return_value_t::RV_CONTINUE.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrap_request_handler! {
|
||||
pub struct WebRequestHandler {
|
||||
initialization_scripts: Arc<Vec<CefInitScript>>,
|
||||
navigation_handler: Option<Arc<tauri_runtime::webview::NavigationHandler>>,
|
||||
}
|
||||
|
||||
impl RequestHandler {
|
||||
fn on_before_browse(
|
||||
&self,
|
||||
_browser: Option<&mut Browser>,
|
||||
frame: Option<&mut Frame>,
|
||||
request: Option<&mut Request>,
|
||||
_user_gesture: ::std::os::raw::c_int,
|
||||
_is_redirect: ::std::os::raw::c_int,
|
||||
) -> ::std::os::raw::c_int {
|
||||
let Some(frame) = frame else {
|
||||
return 0;
|
||||
};
|
||||
// we only fire main frame navigation events to match the behavior of the wry runtime
|
||||
if frame.is_main() == 0 {
|
||||
return 0;
|
||||
}
|
||||
let Some(handler) = &self.navigation_handler else {
|
||||
return 0;
|
||||
};
|
||||
let Some(request) = request else {
|
||||
return 0;
|
||||
};
|
||||
|
||||
let url_str = CefString::from(&request.url()).to_string();
|
||||
let Ok(url) = url::Url::parse(&url_str) else {
|
||||
return 0;
|
||||
};
|
||||
let should_navigate = handler(&url);
|
||||
if should_navigate {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_request_handler(
|
||||
&self,
|
||||
_browser: Option<&mut Browser>,
|
||||
_frame: Option<&mut Frame>,
|
||||
_request: Option<&mut Request>,
|
||||
_is_navigation: ::std::os::raw::c_int,
|
||||
_is_download: ::std::os::raw::c_int,
|
||||
_request_initiator: Option<&CefString>,
|
||||
_disable_default_handling: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> Option<ResourceRequestHandler> {
|
||||
Some(WebResourceRequestHandler::new(
|
||||
self.initialization_scripts.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrap_resource_handler! {
|
||||
pub struct WebResourceHandler {
|
||||
webview_label: String,
|
||||
handler: Arc<Box<UriSchemeProtocolHandler>>,
|
||||
initialization_scripts: Arc<Vec<CefInitScript>>,
|
||||
// we clone response to send it to the handler thread
|
||||
response: HttpResponse,
|
||||
}
|
||||
|
||||
impl ResourceHandler {
|
||||
fn process_request(
|
||||
&self,
|
||||
request: Option<&mut Request>,
|
||||
callback: Option<&mut Callback>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
let Some(request) = request else { return 0 };
|
||||
let Some(callback) = callback else { return 0 };
|
||||
|
||||
let url = CefString::from(&request.url()).to_string();
|
||||
let url = Url::parse(&url).ok();
|
||||
|
||||
if let Some(url) = url {
|
||||
let callback = ThreadSafe(callback.clone());
|
||||
let response_store = ThreadSafe(self.response.clone());
|
||||
let initialization_scripts = self.initialization_scripts.clone();
|
||||
let responder = Box::new(move |response: http::Response<Cow<'static, [u8]>>| {
|
||||
// Check if this is an HTML response that needs script injection
|
||||
let content_type = response.headers().get(CONTENT_TYPE);
|
||||
let is_html = content_type
|
||||
.and_then(|ct| ct.to_str().ok())
|
||||
.map(|ct| ct.to_lowercase().starts_with("text/html"))
|
||||
.unwrap_or(false);
|
||||
|
||||
let (parts, body) = response.into_parts();
|
||||
let body_bytes = body.into_owned();
|
||||
|
||||
let modified_body = if is_html {
|
||||
inject_scripts_into_html_body(&body_bytes, &initialization_scripts)
|
||||
.unwrap_or(body_bytes)
|
||||
} else {
|
||||
body_bytes
|
||||
};
|
||||
|
||||
let mut response = http::Response::from_parts(parts, Cursor::new(modified_body));
|
||||
|
||||
|
||||
let csp = response
|
||||
.headers_mut()
|
||||
.get_mut(CONTENT_SECURITY_POLICY);
|
||||
|
||||
if let Some(csp) = csp {
|
||||
let csp_string = csp.to_str().unwrap().to_string();
|
||||
let new_csp = csp_inject_initialization_scripts_hashes(
|
||||
csp_string,
|
||||
&initialization_scripts,
|
||||
);
|
||||
*csp = HeaderValue::from_str(&new_csp).unwrap();
|
||||
}
|
||||
|
||||
|
||||
response_store.into_owned().borrow_mut().replace(response);
|
||||
|
||||
let callback = callback.into_owned();
|
||||
callback.cont();
|
||||
});
|
||||
|
||||
let label = self.webview_label.clone();
|
||||
let handler = self.handler.clone();
|
||||
|
||||
let data = read_request_body(request);
|
||||
let headers = get_request_headers(request);
|
||||
let method_str = CefString::from(&request.method()).to_string();
|
||||
let method = http::Method::from_bytes(method_str.as_bytes())
|
||||
.unwrap_or(http::Method::GET);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let mut http_request = http::Request::builder().method(method).uri(url.as_str()).body(data).unwrap();
|
||||
*http_request.headers_mut() = headers;
|
||||
// handler is Arc<Box<UriSchemeProtocol>>, so we need to dereference to call it
|
||||
(**handler)(&label, http_request, responder);
|
||||
});
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn read(
|
||||
&self,
|
||||
data_out: *mut u8,
|
||||
bytes_to_read: ::std::os::raw::c_int,
|
||||
bytes_read: Option<&mut ::std::os::raw::c_int>,
|
||||
_callback: Option<&mut ResourceReadCallback>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
let Ok(bytes_to_read) = usize::try_from(bytes_to_read) else {
|
||||
return 0;
|
||||
};
|
||||
let data_out = unsafe { std::slice::from_raw_parts_mut(data_out, bytes_to_read) };
|
||||
let count = self.response.borrow_mut().as_mut().and_then(|response| response.body_mut().read(data_out).ok()).unwrap_or(0);
|
||||
if let Some(bytes_read) = bytes_read {
|
||||
let Ok(count) = count.try_into() else {
|
||||
return 0;
|
||||
};
|
||||
*bytes_read = count;
|
||||
if count > 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
fn response_headers(
|
||||
&self,
|
||||
response: Option<&mut Response>,
|
||||
response_length: Option<&mut i64>,
|
||||
redirect_url: Option<&mut CefString>,
|
||||
) {
|
||||
let (Some(response), Some(response_data)) = (response, &*self.response.borrow()) else { return };
|
||||
|
||||
response.set_status(response_data.status().as_u16() as i32);
|
||||
let mut content_type = None;
|
||||
|
||||
// First pass: collect CSP header and set other headers
|
||||
for (name, value) in response_data.headers() {
|
||||
let Ok(value) = value.to_str() else { continue; };
|
||||
|
||||
response.set_header_by_name(Some(&name.as_str().into()), Some(&value.into()), 0);
|
||||
|
||||
if name == CONTENT_TYPE {
|
||||
content_type.replace(value.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
response.set_header_by_name(
|
||||
Some(&"Cache-Control".into()),
|
||||
Some(&"no-store".into()),
|
||||
1,
|
||||
);
|
||||
|
||||
let mime_type = content_type
|
||||
.as_ref()
|
||||
.and_then(|t| t.split(';').next())
|
||||
.map(str::trim)
|
||||
.unwrap_or("text/plain");
|
||||
response.set_mime_type(Some(&mime_type.into()));
|
||||
|
||||
if let Some(length) = response_length { *length = -1; }
|
||||
|
||||
if let Some(redirect_url) = redirect_url {
|
||||
let _ = std::mem::take(redirect_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrap_scheme_handler_factory! {
|
||||
pub struct UriSchemeHandlerFactory {
|
||||
registry: super::SchemeHandlerRegistry,
|
||||
scheme: String,
|
||||
}
|
||||
|
||||
impl SchemeHandlerFactory {
|
||||
fn create(
|
||||
&self,
|
||||
browser: Option<&mut Browser>,
|
||||
_frame: Option<&mut Frame>,
|
||||
_scheme_name: Option<&CefString>,
|
||||
_request: Option<&mut Request>,
|
||||
) -> Option<ResourceHandler> {
|
||||
let browser = browser?;
|
||||
let id = browser.identifier();
|
||||
|
||||
// get handler from our regsitry based on browser ID and scheme
|
||||
let (webview_label, handler, initialization_scripts) = self
|
||||
.registry
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&(id, self.scheme.clone()))
|
||||
.cloned()?;
|
||||
|
||||
Some(WebResourceHandler::new(webview_label, handler, initialization_scripts, Arc::new(RefCell::new(None))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ThreadSafe<T>(T);
|
||||
|
||||
impl<T> ThreadSafe<T> {
|
||||
fn into_owned(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for ThreadSafe<T> {}
|
||||
unsafe impl<T> Sync for ThreadSafe<T> {}
|
||||
|
||||
fn read_request_body(request: &mut Request) -> Vec<u8> {
|
||||
let mut body = Vec::new();
|
||||
|
||||
if let Some(post_data) = request.post_data() {
|
||||
let mut elements = vec![None; post_data.element_count()];
|
||||
post_data.elements(Some(&mut elements));
|
||||
for element in elements.into_iter().flatten() {
|
||||
match element.get_type().as_ref() {
|
||||
sys::cef_postdataelement_type_t::PDE_TYPE_BYTES => {
|
||||
let size = element.bytes_count();
|
||||
if size > 0 {
|
||||
let mut buf = vec![0u8; size];
|
||||
// Copy bytes into our buffer
|
||||
let copied = element.bytes(size, buf.as_mut_ptr());
|
||||
// Safety: CEF promises it wrote `copied` bytes into buf
|
||||
unsafe {
|
||||
buf.set_len(copied);
|
||||
}
|
||||
body.extend(buf);
|
||||
}
|
||||
}
|
||||
sys::cef_postdataelement_type_t::PDE_TYPE_FILE => {
|
||||
// Read file from disk
|
||||
let file_path = CefString::from(&element.file()).to_string();
|
||||
if let Ok(mut file) = std::fs::File::open(&file_path) {
|
||||
use std::io::Read;
|
||||
let mut buf = Vec::new();
|
||||
if file.read_to_end(&mut buf).is_ok() {
|
||||
body.extend(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body
|
||||
}
|
||||
|
||||
fn get_request_headers(request: &mut Request) -> HeaderMap {
|
||||
let mut headers = HeaderMap::new();
|
||||
|
||||
let mut map = CefStringMultimap::new();
|
||||
|
||||
request.header_map(Some(&mut map));
|
||||
|
||||
// Iterate through all entries
|
||||
for (name, value) in map {
|
||||
for v in value {
|
||||
headers.append(
|
||||
HeaderName::from_bytes(name.as_bytes()).unwrap(),
|
||||
HeaderValue::from_str(&v).unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
headers
|
||||
}
|
||||
110
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview.rs
vendored
Normal file
110
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview.rs
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
use cef::*;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CefWebview {
|
||||
BrowserView(cef::BrowserView),
|
||||
Browser(cef::Browser),
|
||||
}
|
||||
|
||||
impl CefWebview {
|
||||
pub fn is_browser(&self) -> bool {
|
||||
matches!(self, CefWebview::Browser(_))
|
||||
}
|
||||
|
||||
pub fn browser(&self) -> Option<cef::Browser> {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view.browser(),
|
||||
CefWebview::Browser(browser) => Some(browser.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn browser_id(&self) -> i32 {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view.browser().map_or(-1, |b| b.identifier()),
|
||||
CefWebview::Browser(browser) => browser.identifier(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_background_color(&self, color: Option<u32>) {
|
||||
if let CefWebview::BrowserView(view) = self {
|
||||
let window = view.window();
|
||||
let color = color.or_else(|| {
|
||||
window.map(|w| w.theme_color(ColorId::COLOR_PRIMARY_BACKGROUND.get_raw() as _))
|
||||
});
|
||||
|
||||
if let Some(color) = color {
|
||||
view.set_background_color(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bounds(&self) -> cef::Rect {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view.bounds(),
|
||||
CefWebview::Browser(browser) => browser.bounds(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_bounds(&self, rect: Option<&cef::Rect>) {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view.set_bounds(rect),
|
||||
CefWebview::Browser(browser) => browser.set_bounds(rect),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view
|
||||
.window()
|
||||
.and_then(|w| w.display())
|
||||
.map_or(1.0, |d| d.device_scale_factor() as f64),
|
||||
CefWebview::Browser(browser) => browser.scale_factor(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_visible(&self, visible: i32) {
|
||||
match self {
|
||||
CefWebview::BrowserView(view) => view.set_visible(visible),
|
||||
CefWebview::Browser(browser) => browser.set_visible(visible),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
match self {
|
||||
CefWebview::BrowserView(_) => {}
|
||||
CefWebview::Browser(browser) => browser.close(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_parent(&self, parent: &cef::Window) {
|
||||
match self {
|
||||
CefWebview::BrowserView(_) => {}
|
||||
CefWebview::Browser(browser) => browser.set_parent(parent),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait CefBrowserExt {
|
||||
fn bounds(&self) -> cef::Rect;
|
||||
fn set_bounds(&self, rect: Option<&cef::Rect>);
|
||||
fn scale_factor(&self) -> f64;
|
||||
fn set_visible(&self, visible: i32);
|
||||
fn close(&self);
|
||||
fn set_parent(&self, parent: &cef::Window);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn nsview(&self) -> Option<objc2::rc::Retained<objc2_app_kit::NSView>>;
|
||||
#[cfg(windows)]
|
||||
fn hwnd(&self) -> Option<::windows::Win32::Foundation::HWND>;
|
||||
#[cfg(target_os = "linux")]
|
||||
fn xid(&self) -> Option<u64>;
|
||||
}
|
||||
208
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/linux.rs
vendored
Normal file
208
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/linux.rs
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
use cef::*;
|
||||
use std::sync::LazyLock;
|
||||
use x11_dl::xlib;
|
||||
|
||||
use crate::cef_webview::CefBrowserExt;
|
||||
|
||||
static X11: LazyLock<Option<xlib::Xlib>> = LazyLock::new(|| xlib::Xlib::open().ok());
|
||||
|
||||
impl CefBrowserExt for cef::Browser {
|
||||
fn xid(&self) -> Option<u64> {
|
||||
let host = self.host()?;
|
||||
let xid = host.window_handle();
|
||||
Some(xid)
|
||||
}
|
||||
|
||||
fn bounds(&self) -> cef::Rect {
|
||||
let Some(xid) = self.xid() else {
|
||||
return cef::Rect::default();
|
||||
};
|
||||
|
||||
let Some(xlib) = X11.as_ref() else {
|
||||
return cef::Rect::default();
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let display = (xlib.XOpenDisplay)(std::ptr::null());
|
||||
if display.is_null() {
|
||||
return cef::Rect::default();
|
||||
}
|
||||
|
||||
let mut root: xlib::Window = 0;
|
||||
let mut x: i32 = 0;
|
||||
let mut y: i32 = 0;
|
||||
let mut width: u32 = 0;
|
||||
let mut height: u32 = 0;
|
||||
let mut border_width: u32 = 0;
|
||||
let mut depth: u32 = 0;
|
||||
|
||||
let status = (xlib.XGetGeometry)(
|
||||
display,
|
||||
xid as xlib::Window,
|
||||
&mut root,
|
||||
&mut x,
|
||||
&mut y,
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut border_width,
|
||||
&mut depth,
|
||||
);
|
||||
|
||||
(xlib.XCloseDisplay)(display);
|
||||
|
||||
if status == 0 {
|
||||
return cef::Rect::default();
|
||||
}
|
||||
|
||||
// XGetGeometry returns position relative to parent, which is what we need
|
||||
cef::Rect {
|
||||
x,
|
||||
y,
|
||||
width: width as i32,
|
||||
height: height as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_bounds(&self, rect: Option<&cef::Rect>) {
|
||||
let Some(rect) = rect else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(xid) = self.xid() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(xlib) = X11.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let display = (xlib.XOpenDisplay)(std::ptr::null());
|
||||
if display.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
(xlib.XMoveResizeWindow)(
|
||||
display,
|
||||
xid as xlib::Window,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width as u32,
|
||||
rect.height as u32,
|
||||
);
|
||||
// Ensure window is mapped and raised after setting bounds
|
||||
(xlib.XMapRaised)(display, xid as xlib::Window);
|
||||
(xlib.XFlush)(display);
|
||||
(xlib.XCloseDisplay)(display);
|
||||
}
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f64 {
|
||||
// Get scale factor from primary display
|
||||
// CEF on Linux doesn't provide direct access to the window's display,
|
||||
// so we use the primary display as a reasonable default
|
||||
cef::display_get_primary()
|
||||
.map(|d| d.device_scale_factor() as f64)
|
||||
.unwrap_or(1.0)
|
||||
}
|
||||
|
||||
fn set_visible(&self, visible: i32) {
|
||||
let Some(xid) = self.xid() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(xlib) = X11.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let display = (xlib.XOpenDisplay)(std::ptr::null());
|
||||
if display.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
if visible != 0 {
|
||||
(xlib.XMapWindow)(display, xid as xlib::Window);
|
||||
} else {
|
||||
(xlib.XUnmapWindow)(display, xid as xlib::Window);
|
||||
}
|
||||
(xlib.XFlush)(display);
|
||||
(xlib.XCloseDisplay)(display);
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
let Some(xid) = self.xid() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(xlib) = X11.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let display = (xlib.XOpenDisplay)(std::ptr::null());
|
||||
if display.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
(xlib.XDestroyWindow)(display, xid as xlib::Window);
|
||||
(xlib.XFlush)(display);
|
||||
(xlib.XCloseDisplay)(display);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: &cef::Window) {
|
||||
let Some(xid) = self.xid() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let parent_xid = parent.window_handle();
|
||||
if parent_xid == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(xlib) = X11.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let display = (xlib.XOpenDisplay)(std::ptr::null());
|
||||
if display.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if window exists before reparenting
|
||||
let mut root: xlib::Window = 0;
|
||||
let mut parent_window: xlib::Window = 0;
|
||||
let mut children: *mut xlib::Window = std::ptr::null_mut();
|
||||
let mut nchildren: u32 = 0;
|
||||
let status = (xlib.XQueryTree)(
|
||||
display,
|
||||
xid as xlib::Window,
|
||||
&mut root,
|
||||
&mut parent_window,
|
||||
&mut children,
|
||||
&mut nchildren,
|
||||
);
|
||||
|
||||
if status != 0 && !children.is_null() {
|
||||
(xlib.XFree)(children as *mut std::ffi::c_void);
|
||||
}
|
||||
|
||||
(xlib.XReparentWindow)(
|
||||
display,
|
||||
xid as xlib::Window,
|
||||
parent_xid as xlib::Window,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
// Ensure window is mapped and raised after reparenting
|
||||
(xlib.XMapRaised)(display, xid as xlib::Window);
|
||||
(xlib.XFlush)(display);
|
||||
(xlib.XCloseDisplay)(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/macos.rs
vendored
Normal file
99
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/macos.rs
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use crate::cef_webview::CefBrowserExt;
|
||||
use cef::*;
|
||||
use objc2::rc::Retained;
|
||||
use objc2_app_kit::NSView;
|
||||
use objc2_foundation::{NSPoint, NSRect, NSSize};
|
||||
|
||||
impl CefBrowserExt for cef::Browser {
|
||||
fn nsview(&self) -> Option<objc2::rc::Retained<objc2_app_kit::NSView>> {
|
||||
let host = self.host()?;
|
||||
let nsview = host.window_handle() as *mut NSView;
|
||||
unsafe { Retained::<NSView>::retain(nsview) }
|
||||
}
|
||||
|
||||
fn bounds(&self) -> cef::Rect {
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return cef::Rect::default();
|
||||
};
|
||||
|
||||
let parent = unsafe { nsview.superview().unwrap() };
|
||||
let parent_frame = parent.frame();
|
||||
let webview_frame = nsview.frame();
|
||||
|
||||
cef::Rect {
|
||||
x: webview_frame.origin.x as i32,
|
||||
y: (parent_frame.size.height - webview_frame.origin.y - webview_frame.size.height) as i32,
|
||||
width: webview_frame.size.width as i32,
|
||||
height: webview_frame.size.height as i32,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_bounds(&self, rect: Option<&cef::Rect>) {
|
||||
let Some(rect) = rect else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let parent = unsafe { nsview.superview().unwrap() };
|
||||
let parent_frame = parent.frame();
|
||||
|
||||
let origin = NSPoint {
|
||||
x: rect.x as f64,
|
||||
y: (parent_frame.size.height - (rect.y as f64 + rect.height as f64)),
|
||||
};
|
||||
|
||||
let size = NSSize {
|
||||
width: rect.width as f64,
|
||||
height: rect.height as f64,
|
||||
};
|
||||
|
||||
unsafe { nsview.setFrame(NSRect { origin, size }) };
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f64 {
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
let screen = nsview.window().and_then(|w| w.screen());
|
||||
screen.map(|s| s.backingScaleFactor()).unwrap_or(1.0)
|
||||
}
|
||||
|
||||
fn set_visible(&self, visible: i32) {
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if visible != 0 {
|
||||
nsview.setHidden(false);
|
||||
} else {
|
||||
nsview.setHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe { nsview.removeFromSuperview() };
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: &cef::Window) {
|
||||
crate::cef_impl::ensure_valid_content_view(parent.window_handle());
|
||||
|
||||
let Some(nsview) = self.nsview() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let parent_nsview = parent.window_handle();
|
||||
let Some(parent_nsview) = (unsafe { Retained::<NSView>::retain(parent_nsview as _) }) else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe { parent_nsview.addSubview(&nsview) };
|
||||
}
|
||||
}
|
||||
210
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/windows.rs
vendored
Normal file
210
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/cef_webview/windows.rs
vendored
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
use cef::*;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::cef_webview::CefBrowserExt;
|
||||
use windows::{
|
||||
Win32::{
|
||||
Foundation::*,
|
||||
Graphics::Gdi::*,
|
||||
System::LibraryLoader::*,
|
||||
UI::{HiDpi::*, WindowsAndMessaging::*},
|
||||
},
|
||||
core::{HRESULT, HSTRING, PCSTR},
|
||||
};
|
||||
|
||||
impl CefBrowserExt for cef::Browser {
|
||||
fn hwnd(&self) -> Option<HWND> {
|
||||
let host = self.host()?;
|
||||
let hwnd = host.window_handle();
|
||||
Some(HWND(hwnd.0 as _))
|
||||
}
|
||||
|
||||
fn bounds(&self) -> cef::Rect {
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return cef::Rect::default();
|
||||
};
|
||||
|
||||
let mut rect = RECT::default();
|
||||
let _ = unsafe { GetClientRect(hwnd, &mut rect) };
|
||||
|
||||
let position_point = &mut [POINT {
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
}];
|
||||
unsafe { MapWindowPoints(Some(hwnd), GetParent(hwnd).ok(), position_point) };
|
||||
|
||||
cef::Rect {
|
||||
x: position_point[0].x,
|
||||
y: position_point[0].y,
|
||||
width: (rect.right - rect.left) as i32,
|
||||
height: (rect.bottom - rect.top) as i32,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_bounds(&self, rect: Option<&cef::Rect>) {
|
||||
let Some(rect) = rect else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = unsafe {
|
||||
SetWindowPos(
|
||||
hwnd,
|
||||
None,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOZORDER,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f64 {
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
let dpi = unsafe { hwnd_dpi(hwnd) };
|
||||
dpi_to_scale_factor(dpi)
|
||||
}
|
||||
|
||||
fn set_visible(&self, visible: i32) {
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if visible != 0 {
|
||||
let _ = unsafe { ShowWindow(hwnd, SW_SHOW) };
|
||||
unsafe { ensure_render_target(hwnd) };
|
||||
} else {
|
||||
let _ = unsafe { ShowWindow(hwnd, SW_HIDE) };
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = unsafe { DestroyWindow(hwnd) };
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: &cef::Window) {
|
||||
let Some(hwnd) = self.hwnd() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let parent_hwnd = HWND(parent.window_handle().0 as _);
|
||||
let _ = unsafe { SetParent(hwnd, Some(parent_hwnd)) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle visibility on Chrome_WidgetWin_1 children to force CEF to rebind
|
||||
/// the compositor surface and emit a fresh paint after the child webview has
|
||||
/// been hidden.
|
||||
///
|
||||
/// Required when the child has been hidden, particularly when paired with CDP
|
||||
/// `Page.setWebLifecycleState: frozen`, which pauses the renderer's compositor.
|
||||
/// The Chrome_RenderWidgetHostHWND host window survives the freeze, but its
|
||||
/// compositor surface is stale and won't repaint on its own when the parent is
|
||||
/// shown again — leaving the widget visible with blank content. The hide+show
|
||||
/// dance on Chrome_WidgetWin_1 forces Chromium to rebind the surface and
|
||||
/// schedule a paint.
|
||||
unsafe fn ensure_render_target(hwnd: HWND) {
|
||||
use windows::core::PCWSTR;
|
||||
|
||||
const CHROME_WIDGET: PCWSTR = windows::core::w!("Chrome_WidgetWin_1");
|
||||
|
||||
let mut child = unsafe { FindWindowExW(Some(hwnd), None, CHROME_WIDGET, PCWSTR::null()) };
|
||||
while let Ok(child_hwnd) = child {
|
||||
let _ = unsafe { ShowWindow(child_hwnd, SW_HIDE) };
|
||||
let _ = unsafe { ShowWindow(child_hwnd, SW_SHOW) };
|
||||
child = unsafe { FindWindowExW(Some(hwnd), Some(child_hwnd), CHROME_WIDGET, PCWSTR::null()) };
|
||||
}
|
||||
}
|
||||
|
||||
fn get_function_impl(library: &str, function: &str) -> FARPROC {
|
||||
let library = HSTRING::from(library);
|
||||
assert_eq!(function.chars().last(), Some('\0'));
|
||||
|
||||
// Library names we will use are ASCII so we can use the A version to avoid string conversion.
|
||||
let module = unsafe { LoadLibraryW(&library) }.unwrap_or_default();
|
||||
if module.is_invalid() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe { GetProcAddress(module, PCSTR::from_raw(function.as_ptr())) }
|
||||
}
|
||||
|
||||
macro_rules! get_function {
|
||||
($lib:expr, $func:ident) => {
|
||||
get_function_impl($lib, concat!(stringify!($func), '\0'))
|
||||
.map(|f| unsafe { std::mem::transmute::<_, $func>(f) })
|
||||
};
|
||||
}
|
||||
|
||||
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32;
|
||||
pub type GetDpiForMonitor = unsafe extern "system" fn(
|
||||
hmonitor: HMONITOR,
|
||||
dpi_type: MONITOR_DPI_TYPE,
|
||||
dpi_x: *mut u32,
|
||||
dpi_y: *mut u32,
|
||||
) -> HRESULT;
|
||||
|
||||
static GET_DPI_FOR_WINDOW: LazyLock<Option<GetDpiForWindow>> =
|
||||
LazyLock::new(|| get_function!("user32.dll", GetDpiForWindow));
|
||||
static GET_DPI_FOR_MONITOR: LazyLock<Option<GetDpiForMonitor>> =
|
||||
LazyLock::new(|| get_function!("shcore.dll", GetDpiForMonitor));
|
||||
|
||||
pub const BASE_DPI: u32 = 96;
|
||||
pub fn dpi_to_scale_factor(dpi: u32) -> f64 {
|
||||
dpi as f64 / BASE_DPI as f64
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
|
||||
if let Some(GetDpiForWindow) = *GET_DPI_FOR_WINDOW {
|
||||
// We are on Windows 10 Anniversary Update (1607) or later.
|
||||
match GetDpiForWindow(hwnd) {
|
||||
0 => BASE_DPI, // 0 is returned if hwnd is invalid
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
dpi => dpi as u32,
|
||||
}
|
||||
} else if let Some(GetDpiForMonitor) = *GET_DPI_FOR_MONITOR {
|
||||
// We are on Windows 8.1 or later.
|
||||
let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if monitor.is_invalid() {
|
||||
return BASE_DPI;
|
||||
}
|
||||
|
||||
let mut dpi_x = 0;
|
||||
let mut dpi_y = 0;
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
if GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y) == S_OK {
|
||||
dpi_x as u32
|
||||
} else {
|
||||
BASE_DPI
|
||||
}
|
||||
} else {
|
||||
let hdc = GetDC(Some(hwnd));
|
||||
if hdc.is_invalid() {
|
||||
return BASE_DPI;
|
||||
}
|
||||
|
||||
// We are on Vista or later.
|
||||
if IsProcessDPIAware().as_bool() {
|
||||
// If the process is DPI aware, then scaling must be handled by the application using
|
||||
// this DPI value.
|
||||
GetDeviceCaps(Some(hdc), LOGPIXELSX) as u32
|
||||
} else {
|
||||
// If the process is DPI unaware, then scaling is performed by the OS; we thus return
|
||||
// 96 (scale factor 1.0) to prevent the window from being re-scaled by both the
|
||||
// application and the WM.
|
||||
BASE_DPI
|
||||
}
|
||||
}
|
||||
}
|
||||
2541
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/lib.rs
vendored
Normal file
2541
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
42
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/utils.rs
vendored
Normal file
42
apps/tauri/src-tauri/vendor/tauri-runtime-cef/src/utils.rs
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#[cfg(windows)]
|
||||
pub mod windows {
|
||||
use tauri_runtime::dpi::PhysicalSize;
|
||||
use windows::Win32::Foundation::*;
|
||||
use windows::Win32::UI::WindowsAndMessaging::*;
|
||||
|
||||
pub fn inner_size(hwnd: cef::sys::HWND) -> PhysicalSize<u32> {
|
||||
let hwnd = HWND(hwnd.0 as _);
|
||||
let mut rect = RECT::default();
|
||||
let _ = unsafe { GetClientRect(hwnd, &mut rect) };
|
||||
|
||||
PhysicalSize::new(
|
||||
(rect.right - rect.left) as u32,
|
||||
(rect.bottom - rect.top) as u32,
|
||||
)
|
||||
}
|
||||
|
||||
/// Adjusts the given size to account for window borders, so that the resulting inner size matches the requested size.
|
||||
///
|
||||
/// Expects and returns a size in physical pixels.
|
||||
pub fn adjust_size(hwnd: cef::sys::HWND, size: cef::Size) -> cef::Size {
|
||||
let hwnd = HWND(hwnd.0 as _);
|
||||
|
||||
let mut client_rect = RECT::default();
|
||||
let _ = unsafe { GetClientRect(hwnd, &mut client_rect) };
|
||||
let client_width = client_rect.right - client_rect.left;
|
||||
let client_height = client_rect.bottom - client_rect.top;
|
||||
|
||||
let mut window_rect = RECT::default();
|
||||
let _ = unsafe { GetWindowRect(hwnd, &mut window_rect) };
|
||||
let window_width = window_rect.right - window_rect.left;
|
||||
let window_height = window_rect.bottom - window_rect.top;
|
||||
|
||||
let width_diff = window_width - client_width;
|
||||
let height_diff = window_height - client_height;
|
||||
|
||||
cef::Size {
|
||||
width: size.width + width_diff,
|
||||
height: size.height + height_diff,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue