diff --git a/src/platform/windows/cursor.rs b/src/platform/windows/cursor.rs index fa37eb7..0d1e3bd 100644 --- a/src/platform/windows/cursor.rs +++ b/src/platform/windows/cursor.rs @@ -196,18 +196,49 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option { // Cleanup function to restore cursors and clean up resources pub fn cleanup() { + println!("Running cursor cleanup..."); + // 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..."); - unsafe { - // Force Windows to reload default cursor settings - SystemParametersInfoW(SPI_SETCURSORS, 0, null_mut(), 0); - // Also try the A version just in case - super::state::reset_system_cursors(); - } - // Reset to default arrow cursor unsafe { + // Try multiple approaches to ensure cursors are restored + + // 1. First try to restore original cursors if we saved them + 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); + } + + // Destroy the original cursor we saved + 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)); if !arrow_cursor.is_null() { SetCursor(arrow_cursor); @@ -222,14 +253,19 @@ pub fn cleanup() { let custom_cursor_to_destroy = CUSTOM_CURSOR.lock().unwrap().take(); if let Some(cursor_wrapper) = custom_cursor_to_destroy { unsafe { - DestroyIcon(cursor_wrapper.0); - println!("Custom cursor destroyed during cleanup."); + if !cursor_wrapper.0.is_null() { + DestroyIcon(cursor_wrapper.0); + println!("Custom cursor destroyed during cleanup."); + } } } // Reset the last known cursor position *LAST_CURSOR_POS.lock().unwrap() = None; + // Clear the current cursor image + *CURRENT_CURSOR_IMAGE.lock().unwrap() = None; + // Unregister control handler if CTRL_HANDLER_REGISTERED.load(Ordering::SeqCst) { unsafe { @@ -241,6 +277,8 @@ pub fn cleanup() { } } } + + println!("Cursor cleanup complete."); } // --- Public API Functions --- @@ -291,6 +329,8 @@ pub fn hide_system_cursor() -> bool { // Update the cursor image using CursorInfo (with caching) 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 let image = if let Some(ref cached_image) = cursor_info.image { 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()); unsafe { - // Use cached Windows cursor if available - #[cfg(windows)] - if let Some(cached_cursor) = cursor_info.win_cursor { - println!("Using cached Windows cursor handle for: {}", cursor_info.name); + // Create a new cursor first before destroying the old one + // This minimizes the time when no custom cursor is active + let new_cursor = if let Some(ref cached_image) = cursor_info.image { + // 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 - let success = apply_cursor_to_all_system_cursors(cached_cursor.0); - if !success { - 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); + if let Some(new_cursor_wrapper) = new_cursor { + // Apply the new cursor to all system cursors first + let success = apply_cursor_to_all_system_cursors(new_cursor_wrapper.0); + + // Now that the new cursor is applied, we can clean up the old one + let mut cursor_guard = CUSTOM_CURSOR.lock().unwrap(); + if let Some(old_cursor) = cursor_guard.take() { + // Only destroy the old cursor after the new one is applied + DestroyIcon(old_cursor.0); } - return true; - } + // Store the new cursor + *cursor_guard = Some(new_cursor_wrapper); - // Clean up old cursor if it exists - let mut cursor_guard = CUSTOM_CURSOR.lock().unwrap(); - if let Some(cursor_wrapper) = cursor_guard.take() { - DestroyIcon(cursor_wrapper.0); - } - - // Create new cursor - if let Some(cursor_wrapper) = create_cursor_from_image(&image) { - // 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)] { - println!("Caching Windows cursor handle for: {}", cursor_info.name); - cursor_info.win_cursor = Some(cursor_wrapper); + // Always update the cached cursor to the fresh one + 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 { 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 - SetCursor(cursor_wrapper.0); + SetCursor(new_cursor_wrapper.0); } return true; } else { 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; } } @@ -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 { 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 - for &cursor_id in SYSTEM_CURSORS.iter() { - // Make a copy of the cursor for each system cursor type + // Start with the most commonly used cursors first + 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); 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; continue; } // Set the system cursor 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 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 }