Fix cursor swapping issues and minimize cursor flashing

This commit is contained in:
2025-05-11 18:48:04 -05:00
parent b3d85106a8
commit a92ef1e07c
+132 -38
View File
@@ -196,18 +196,49 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
// Cleanup function to restore cursors and clean up resources // Cleanup function to restore cursors and clean up resources
pub fn cleanup() { pub fn cleanup() {
println!("Running cursor cleanup...");
// Restore system cursors if they were hidden // Restore system cursors if they were hidden
if CURSOR_HIDDEN.swap(false, Ordering::SeqCst) { // Use swap to ensure it runs only once // Use swap to ensure it runs only once
if CURSOR_HIDDEN.swap(false, Ordering::SeqCst) {
println!("Restoring system cursors..."); println!("Restoring system cursors...");
unsafe { unsafe {
// Force Windows to reload default cursor settings // Try multiple approaches to ensure cursors are restored
SystemParametersInfoW(SPI_SETCURSORS, 0, null_mut(), 0);
// Also try the A version just in case // 1. First try to restore original cursors if we saved them
super::state::reset_system_cursors(); let original_cursors_opt = ORIGINAL_CURSORS.lock().unwrap().take();
if let Some(original_cursors) = original_cursors_opt {
println!("Restoring {} saved original cursors", original_cursors.len());
for (cursor_id, cursor) in original_cursors {
if !cursor.0.is_null() {
// Make a copy of the original cursor
let cursor_copy = CopyIcon(cursor.0);
if !cursor_copy.is_null() {
if SetSystemCursor(cursor_copy, cursor_id) == 0 {
eprintln!("Failed to restore original cursor for ID: {}", cursor_id);
DestroyIcon(cursor_copy);
}
} else {
eprintln!("Failed to copy original cursor for ID: {}", cursor_id);
} }
// Reset to default arrow cursor // Destroy the original cursor we saved
unsafe { DestroyIcon(cursor.0);
}
}
} else {
println!("No saved original cursors found");
}
// 2. Force Windows to reload default cursor settings
println!("Forcing Windows to reload default cursor settings");
SystemParametersInfoW(SPI_SETCURSORS, 0, null_mut(), 0);
// 3. Also try the A version for maximum compatibility
super::state::reset_system_cursors();
// 4. Reset to default arrow cursor
let arrow_cursor = LoadCursorW(null_mut(), MAKEINTRESOURCEW(IDC_ARROW as u16)); let arrow_cursor = LoadCursorW(null_mut(), MAKEINTRESOURCEW(IDC_ARROW as u16));
if !arrow_cursor.is_null() { if !arrow_cursor.is_null() {
SetCursor(arrow_cursor); SetCursor(arrow_cursor);
@@ -222,14 +253,19 @@ pub fn cleanup() {
let custom_cursor_to_destroy = CUSTOM_CURSOR.lock().unwrap().take(); let custom_cursor_to_destroy = CUSTOM_CURSOR.lock().unwrap().take();
if let Some(cursor_wrapper) = custom_cursor_to_destroy { if let Some(cursor_wrapper) = custom_cursor_to_destroy {
unsafe { unsafe {
if !cursor_wrapper.0.is_null() {
DestroyIcon(cursor_wrapper.0); DestroyIcon(cursor_wrapper.0);
println!("Custom cursor destroyed during cleanup."); println!("Custom cursor destroyed during cleanup.");
} }
} }
}
// Reset the last known cursor position // Reset the last known cursor position
*LAST_CURSOR_POS.lock().unwrap() = None; *LAST_CURSOR_POS.lock().unwrap() = None;
// Clear the current cursor image
*CURRENT_CURSOR_IMAGE.lock().unwrap() = None;
// Unregister control handler // Unregister control handler
if CTRL_HANDLER_REGISTERED.load(Ordering::SeqCst) { if CTRL_HANDLER_REGISTERED.load(Ordering::SeqCst) {
unsafe { unsafe {
@@ -241,6 +277,8 @@ pub fn cleanup() {
} }
} }
} }
println!("Cursor cleanup complete.");
} }
// --- Public API Functions --- // --- Public API Functions ---
@@ -291,6 +329,8 @@ pub fn hide_system_cursor() -> bool {
// Update the cursor image using CursorInfo (with caching) // Update the cursor image using CursorInfo (with caching)
pub fn update_cursor_info(cursor_info: &mut crate::platform::CursorInfo) -> bool { pub fn update_cursor_info(cursor_info: &mut crate::platform::CursorInfo) -> bool {
println!("Updating cursor to: {}", cursor_info.name);
// Use cached image if available, otherwise load from disk // Use cached image if available, otherwise load from disk
let image = if let Some(ref cached_image) = cursor_info.image { let image = if let Some(ref cached_image) = cursor_info.image {
println!("Using cached image for cursor: {}", cursor_info.name); println!("Using cached image for cursor: {}", cursor_info.name);
@@ -315,51 +355,58 @@ pub fn update_cursor_info(cursor_info: &mut crate::platform::CursorInfo) -> bool
*CURRENT_CURSOR_IMAGE.lock().unwrap() = Some(image.clone()); *CURRENT_CURSOR_IMAGE.lock().unwrap() = Some(image.clone());
unsafe { unsafe {
// Use cached Windows cursor if available // Create a new cursor first before destroying the old one
#[cfg(windows)] // This minimizes the time when no custom cursor is active
if let Some(cached_cursor) = cursor_info.win_cursor { let new_cursor = if let Some(ref cached_image) = cursor_info.image {
println!("Using cached Windows cursor handle for: {}", cursor_info.name); // Always create a fresh cursor from the image to avoid invalid handle issues
create_cursor_from_image(cached_image)
} else {
create_cursor_from_image(&image)
};
// Apply the cached cursor to all system cursors if let Some(new_cursor_wrapper) = new_cursor {
let success = apply_cursor_to_all_system_cursors(cached_cursor.0); // Apply the new cursor to all system cursors first
if !success { let success = apply_cursor_to_all_system_cursors(new_cursor_wrapper.0);
eprintln!("Failed to apply cached cursor to all system cursors");
// Even if we failed to set all system cursors, try to at least set the current cursor
SetCursor(cached_cursor.0);
}
return true; // Now that the new cursor is applied, we can clean up the old one
}
// Clean up old cursor if it exists
let mut cursor_guard = CUSTOM_CURSOR.lock().unwrap(); let mut cursor_guard = CUSTOM_CURSOR.lock().unwrap();
if let Some(cursor_wrapper) = cursor_guard.take() { if let Some(old_cursor) = cursor_guard.take() {
DestroyIcon(cursor_wrapper.0); // Only destroy the old cursor after the new one is applied
DestroyIcon(old_cursor.0);
} }
// Create new cursor // Store the new cursor
if let Some(cursor_wrapper) = create_cursor_from_image(&image) { *cursor_guard = Some(new_cursor_wrapper);
// Store the cursor for later use
*cursor_guard = Some(cursor_wrapper);
// Cache the Windows cursor handle in the CursorInfo // Update the cached cursor in CursorInfo
#[cfg(windows)] #[cfg(windows)]
{ {
println!("Caching Windows cursor handle for: {}", cursor_info.name); // Always update the cached cursor to the fresh one
cursor_info.win_cursor = Some(cursor_wrapper); cursor_info.win_cursor = Some(new_cursor_wrapper);
} }
// Apply the custom cursor to all system cursors
let success = apply_cursor_to_all_system_cursors(cursor_wrapper.0);
if !success { if !success {
eprintln!("Failed to apply cursor to all system cursors"); eprintln!("Failed to apply cursor to all system cursors");
// Even if we failed to set all system cursors, try to at least set the current cursor // Even if we failed to set all system cursors, try to at least set the current cursor
SetCursor(cursor_wrapper.0); SetCursor(new_cursor_wrapper.0);
} }
return true; return true;
} else { } else {
eprintln!("Failed to create cursor from image"); eprintln!("Failed to create cursor from image");
// If we failed to create a new cursor, try to use the cached one as a fallback
#[cfg(windows)]
if let Some(cached_cursor) = cursor_info.win_cursor {
if !cached_cursor.0.is_null() {
println!("Falling back to cached cursor as a last resort");
let mut cursor_guard = CUSTOM_CURSOR.lock().unwrap();
*cursor_guard = Some(cached_cursor);
SetCursor(cached_cursor.0);
return true;
}
}
return false; return false;
} }
} }
@@ -371,24 +418,71 @@ pub fn update_cursor_info(cursor_info: &mut crate::platform::CursorInfo) -> bool
unsafe fn apply_cursor_to_all_system_cursors(cursor: winapi::shared::windef::HCURSOR) -> bool { unsafe fn apply_cursor_to_all_system_cursors(cursor: winapi::shared::windef::HCURSOR) -> bool {
let mut success = true; let mut success = true;
// First, ensure the cursor is valid
if cursor.is_null() {
eprintln!("Cannot apply null cursor to system cursors");
return false;
}
// Immediately set the current cursor to minimize flashing
SetCursor(cursor);
// Apply the cursor to all system cursor types // Apply the cursor to all system cursor types
for &cursor_id in SYSTEM_CURSORS.iter() { // Start with the most commonly used cursors first
// Make a copy of the cursor for each system cursor type let priority_cursors = [
32512, // IDC_ARROW (most important)
32513, // IDC_IBEAM (text cursor)
32649, // IDC_HAND (links)
];
// Apply to priority cursors first
for &cursor_id in priority_cursors.iter() {
// Make a copy of the cursor
let cursor_copy = CopyIcon(cursor); let cursor_copy = CopyIcon(cursor);
if cursor_copy.is_null() { if cursor_copy.is_null() {
eprintln!("Failed to copy cursor for system cursor ID: {}", cursor_id); let error = std::io::Error::last_os_error();
eprintln!("Failed to copy cursor for priority ID: {} - Error: {}", cursor_id, error);
success = false; success = false;
continue; continue;
} }
// Set the system cursor // Set the system cursor
if SetSystemCursor(cursor_copy, cursor_id) == 0 { if SetSystemCursor(cursor_copy, cursor_id) == 0 {
eprintln!("Failed to set system cursor for ID: {}", cursor_id); let error = std::io::Error::last_os_error();
eprintln!("Failed to set cursor for priority ID: {} - Error: {}", cursor_id, error);
DestroyIcon(cursor_copy); // Clean up the copy if we failed to set it DestroyIcon(cursor_copy); // Clean up the copy if we failed to set it
success = false; success = false;
} }
} }
// Now apply to the remaining cursors
for &cursor_id in SYSTEM_CURSORS.iter() {
// Skip the priority cursors we already processed
if priority_cursors.contains(&cursor_id) {
continue;
}
// Make a copy of the cursor
let cursor_copy = CopyIcon(cursor);
if cursor_copy.is_null() {
// Don't log errors for non-priority cursors to reduce console spam
success = false;
continue;
}
// Set the system cursor
if SetSystemCursor(cursor_copy, cursor_id) == 0 {
// Don't log errors for non-priority cursors to reduce console spam
DestroyIcon(cursor_copy); // Clean up the copy if we failed to set it
success = false;
}
}
// If we had any failures, set the current cursor again as a fallback
if !success {
SetCursor(cursor);
}
success success
} }