fix(windows): align custom shell rounded frame
This commit is contained in:
1 parent
f83a5339c7
commit
4ea8389ceb
5 files changed
+109
-4
No files matched your search
@@ -53,8 +53,11 @@ objc2-foundation = "0.2"
|
||||
objc2-app-kit = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
raw-window-handle = "0.6"
|
||||
windows = { version = "0.58", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics_Dwm",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
|
||||
@@ -113,6 +113,7 @@ pub fn run() {
|
||||
if let Err(e) = apply_mica(&main, None) {
|
||||
log::warn!("[main] mica failed: {e}");
|
||||
}
|
||||
apply_windows_rounded_frame(&main);
|
||||
}
|
||||
if let Err(e) = main.show() {
|
||||
log::warn!("[main] initial show failed: {e}");
|
||||
@@ -219,10 +220,16 @@ pub fn run() {
|
||||
RunEvent::Reopen { .. } => show_main_window(app),
|
||||
RunEvent::WindowEvent { label, event, .. } => {
|
||||
if label == "main" {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
if let tauri::WindowEvent::CloseRequested { ref api, .. } = event {
|
||||
api.prevent_close();
|
||||
hide_main_window(app);
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
if matches!(event, tauri::WindowEvent::Resized(_) | tauri::WindowEvent::ScaleFactorChanged { .. }) {
|
||||
if let Some(main) = app.get_webview_window("main") {
|
||||
apply_windows_rounded_frame(&main);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RunEvent::Exit => {
|
||||
@@ -234,6 +241,97 @@ pub fn run() {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn apply_windows_rounded_frame<R: Runtime>(window: &tauri::WebviewWindow<R>) {
|
||||
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
|
||||
use windows::Win32::Foundation::{BOOL, HWND, RECT};
|
||||
use windows::Win32::Graphics::Dwm::{
|
||||
DwmSetWindowAttribute, DWMWA_BORDER_COLOR, DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_ROUND,
|
||||
};
|
||||
use windows::Win32::Graphics::Gdi::{CreateRoundRectRgn, SetWindowRgn, HRGN};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{
|
||||
GetWindowLongW, GetWindowRect, SetWindowLongW, SetWindowPos, GWL_STYLE, SWP_FRAMECHANGED,
|
||||
SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WS_CAPTION, WS_THICKFRAME,
|
||||
};
|
||||
|
||||
let handle = match window.window_handle().map(|h| h.as_raw()) {
|
||||
Ok(RawWindowHandle::Win32(handle)) => handle,
|
||||
Ok(other) => {
|
||||
log::warn!("[main] unexpected raw window handle for DWM frame: {other:?}");
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("[main] read raw window handle failed: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let hwnd = HWND(handle.hwnd.get() as *mut core::ffi::c_void);
|
||||
|
||||
unsafe {
|
||||
let style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
let native_frame_bits = (WS_CAPTION.0 | WS_THICKFRAME.0) as i32;
|
||||
if style & native_frame_bits != 0 {
|
||||
SetWindowLongW(hwnd, GWL_STYLE, style & !native_frame_bits);
|
||||
if let Err(e) = SetWindowPos(
|
||||
hwnd,
|
||||
HWND::default(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED,
|
||||
) {
|
||||
log::warn!("[main] refresh native frame after style update failed: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
if window.is_maximized().unwrap_or(false) {
|
||||
let _ = SetWindowRgn(hwnd, HRGN::default(), BOOL(1));
|
||||
return;
|
||||
}
|
||||
|
||||
let corner_preference = DWMWCP_ROUND;
|
||||
if let Err(e) = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&corner_preference as *const _ as *const core::ffi::c_void,
|
||||
std::mem::size_of_val(&corner_preference) as u32,
|
||||
) {
|
||||
log::warn!("[main] set DWM rounded corners failed: {e}");
|
||||
}
|
||||
|
||||
// Remove DWM's fallback 1px light border; the React shell draws the visual stroke.
|
||||
let border_color_none: u32 = 0xFFFFFFFE;
|
||||
if let Err(e) = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_BORDER_COLOR,
|
||||
&border_color_none as *const _ as *const core::ffi::c_void,
|
||||
std::mem::size_of_val(&border_color_none) as u32,
|
||||
) {
|
||||
log::warn!("[main] remove DWM border color failed: {e}");
|
||||
}
|
||||
|
||||
let mut rect = RECT::default();
|
||||
if let Err(e) = GetWindowRect(hwnd, &mut rect) {
|
||||
log::warn!("[main] read window rect for rounded region failed: {e}");
|
||||
return;
|
||||
}
|
||||
let width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
if width <= 0 || height <= 0 {
|
||||
return;
|
||||
}
|
||||
let region = CreateRoundRectRgn(0, 0, width + 1, height + 1, 18, 18);
|
||||
if region.is_invalid() {
|
||||
log::warn!("[main] create rounded window region failed");
|
||||
return;
|
||||
}
|
||||
if SetWindowRgn(hwnd, region, BOOL(1)) == 0 {
|
||||
log::warn!("[main] apply rounded window region failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn restart_app(app: AppHandle) {
|
||||
// macOS:自动更新会让新装的 .app 带 com.apple.quarantine(无论 Tauri updater
|
||||
|
||||
@@ -255,7 +255,7 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
||||
flex: 1, minWidth: 0,
|
||||
overflow: 'hidden',
|
||||
background: 'var(--ol-surface)',
|
||||
borderRadius: os === 'mac' ? 20 : 14,
|
||||
borderRadius: os === 'mac' ? 20 : 10,
|
||||
border: '0.5px solid rgba(0,0,0,0.06)',
|
||||
boxShadow: '0 1px 0 rgba(255,255,255,0.8) inset, 0 8px 24px -12px rgba(15,17,22,0.10), 0 2px 6px -2px rgba(15,17,22,0.06)',
|
||||
display: 'flex',
|
||||
|
||||
@@ -30,6 +30,8 @@ export function detectOS(): OS {
|
||||
|
||||
const MAC_TITLEBAR_HEIGHT = 36;
|
||||
const MAC_SYSTEM_CONTROLS_RESERVED_WIDTH = 80;
|
||||
const MAC_WINDOW_RADIUS = 20;
|
||||
const WIN_WINDOW_RADIUS = 0;
|
||||
|
||||
interface WindowChromeProps {
|
||||
os?: OS;
|
||||
@@ -45,7 +47,7 @@ export function WindowChrome({ os = 'mac', title = 'OpenLess', children, height
|
||||
width: '100%',
|
||||
height,
|
||||
position: 'relative',
|
||||
borderRadius: os === 'mac' ? 20 : 14,
|
||||
borderRadius: os === 'mac' ? MAC_WINDOW_RADIUS : WIN_WINDOW_RADIUS,
|
||||
boxShadow: 'var(--ol-shadow-xl)',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
|
||||
@@ -3,17 +3,19 @@ html, body, #root {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
background: transparent;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
Reference in new issue
Block a user