From 26e5d8f8c3a9dca5ed88369e5ccb2ce37aa0a43e Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Mon, 26 Jan 2026 14:25:57 -0300 Subject: [PATCH] linux impl? --- Cargo.lock | 1 + crates/tauri-runtime-cef/Cargo.toml | 1 + crates/tauri-runtime-cef/src/cef_webview.rs | 2 + .../src/cef_webview/linux.rs | 169 +++++++++++++++++- 4 files changed, 165 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c23d1af4..31677c464 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9093,6 +9093,7 @@ dependencies = [ "tauri-utils", "url", "windows 0.61.1", + "x11-dl", ] [[package]] diff --git a/crates/tauri-runtime-cef/Cargo.toml b/crates/tauri-runtime-cef/Cargo.toml index 6cbd4e740..5c53cd3d9 100644 --- a/crates/tauri-runtime-cef/Cargo.toml +++ b/crates/tauri-runtime-cef/Cargo.toml @@ -36,6 +36,7 @@ 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"] diff --git a/crates/tauri-runtime-cef/src/cef_webview.rs b/crates/tauri-runtime-cef/src/cef_webview.rs index 42721e534..3b085ade4 100644 --- a/crates/tauri-runtime-cef/src/cef_webview.rs +++ b/crates/tauri-runtime-cef/src/cef_webview.rs @@ -100,4 +100,6 @@ trait CefBrowserExt { fn nsview(&self) -> Option>; #[cfg(windows)] fn hwnd(&self) -> Option<::windows::Win32::Foundation::HWND>; + #[cfg(target_os = "linux")] + fn xid(&self) -> Option; } diff --git a/crates/tauri-runtime-cef/src/cef_webview/linux.rs b/crates/tauri-runtime-cef/src/cef_webview/linux.rs index 7bbdabc1e..67fd90094 100644 --- a/crates/tauri-runtime-cef/src/cef_webview/linux.rs +++ b/crates/tauri-runtime-cef/src/cef_webview/linux.rs @@ -1,33 +1,186 @@ use cef::*; +use std::sync::LazyLock; +use x11_dl::xlib; use crate::cef_webview::CefBrowserExt; +static X11: LazyLock> = LazyLock::new(|| xlib::Xlib::open().ok()); + impl CefBrowserExt for cef::Browser { + fn xid(&self) -> Option { + let host = self.host()?; + let xid = host.window_handle() as u64; + Some(xid) + } + fn bounds(&self) -> cef::Rect { - todo!() + 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>) { - todo!() + 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, + ); + (xlib.XFlush)(display); + (xlib.XCloseDisplay)(display); + } } fn scale_factor(&self) -> f64 { - todo!() + // 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_background_color(&self, color: cef::Color) { - // TODO: + fn set_background_color(&self, _color: cef::Color) { + // TODO: Implement background color setting for Linux/X11 } fn set_visible(&self, visible: i32) { - todo!() + 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) { - todo!() + 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) { - todo!() + let Some(xid) = self.xid() else { + return; + }; + + let parent_xid = parent.window_handle() as u64; + + let Some(xlib) = X11.as_ref() else { + return; + }; + + unsafe { + let display = (xlib.XOpenDisplay)(std::ptr::null()); + if display.is_null() { + return; + } + + (xlib.XReparentWindow)( + display, + xid as xlib::Window, + parent_xid as xlib::Window, + 0, + 0, + ); + (xlib.XFlush)(display); + (xlib.XCloseDisplay)(display); + } } }