Refactor large functions into smaller components
This commit is contained in:
@@ -99,7 +99,7 @@ fn select_cursor(
|
||||
|
||||
let cursor = &app_state.cursors[index];
|
||||
|
||||
let filename = Path::new(&cursor.path)
|
||||
let _filename = Path::new(&cursor.path)
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
||||
@@ -123,7 +123,7 @@ fn next_cursor(
|
||||
|
||||
let cursor = &app_state.cursors[app_state.current_index];
|
||||
|
||||
let filename = Path::new(&cursor.path)
|
||||
let _filename = Path::new(&cursor.path)
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
||||
@@ -200,25 +200,20 @@ fn restore_default_cursors() -> Result<(), String> {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load cursor files from src/cursors directory
|
||||
fn load_cursor_files() -> Vec<Cursor> {
|
||||
let mut cursors = Vec::new();
|
||||
|
||||
// Determine the path to src/cursors relative to src-tauri (CARGO_MANIFEST_DIR)
|
||||
// Get possible cursor directory paths
|
||||
fn get_cursor_directory_paths() -> Vec<PathBuf> {
|
||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
|
||||
// Check multiple possible locations
|
||||
let possible_cursor_dirs = vec![
|
||||
vec![
|
||||
manifest_dir.join("../src/cursors"),
|
||||
manifest_dir.join("src/cursors"),
|
||||
manifest_dir.join("cursors"),
|
||||
manifest_dir.clone(), // Check manifest dir itself
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
for cursors_dir in possible_cursor_dirs.iter() {
|
||||
if cursors_dir.exists() {
|
||||
if let Ok(entries) = std::fs::read_dir(cursors_dir) {
|
||||
for entry in entries.filter_map(Result::ok) {
|
||||
// Process a single cursor file entry
|
||||
fn process_cursor_file(entry: std::fs::DirEntry) -> Option<Cursor> {
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file()
|
||||
@@ -232,39 +227,63 @@ fn load_cursor_files() -> Vec<Cursor> {
|
||||
.unwrap_or("Unknown")
|
||||
.to_string();
|
||||
|
||||
cursors.push(Cursor {
|
||||
Some(Cursor {
|
||||
name,
|
||||
path: path.to_string_lossy().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Scan cursor directories for cursor files
|
||||
fn scan_cursor_directories() -> Vec<Cursor> {
|
||||
let possible_cursor_dirs = get_cursor_directory_paths();
|
||||
|
||||
for cursors_dir in possible_cursor_dirs.iter() {
|
||||
if cursors_dir.exists() {
|
||||
if let Ok(entries) = std::fs::read_dir(cursors_dir) {
|
||||
let cursors: Vec<Cursor> = entries
|
||||
.filter_map(Result::ok)
|
||||
.filter_map(process_cursor_file)
|
||||
.collect();
|
||||
|
||||
if !cursors.is_empty() {
|
||||
break;
|
||||
return cursors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found no cursors, use mock data with paths relative to what resolve_resource expects
|
||||
if cursors.is_empty() {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
// Create fallback cursors when no files are found
|
||||
fn create_fallback_cursors() -> Vec<Cursor> {
|
||||
eprintln!("No cursor files found, using fallback cursors");
|
||||
|
||||
// Mock data paths should reflect their eventual resource path structure
|
||||
cursors.push(Cursor {
|
||||
vec![
|
||||
Cursor {
|
||||
name: "Default".to_string(),
|
||||
path: "src/cursors/default.png".to_string(), // Filename will be 'default.png'
|
||||
});
|
||||
|
||||
cursors.push(Cursor {
|
||||
path: "src/cursors/default.png".to_string(),
|
||||
},
|
||||
Cursor {
|
||||
name: "Icon".to_string(),
|
||||
path: "src/cursors/icon.png".to_string(), // Filename will be 'icon.png'
|
||||
});
|
||||
|
||||
cursors.push(Cursor {
|
||||
path: "src/cursors/icon.png".to_string(),
|
||||
},
|
||||
Cursor {
|
||||
name: "Red".to_string(),
|
||||
path: "src/cursors/red.png".to_string(), // Filename will be 'red.png'
|
||||
});
|
||||
path: "src/cursors/red.png".to_string(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Function to load cursor files from src/cursors directory
|
||||
fn load_cursor_files() -> Vec<Cursor> {
|
||||
let mut cursors = scan_cursor_directories();
|
||||
|
||||
if cursors.is_empty() {
|
||||
cursors = create_fallback_cursors();
|
||||
}
|
||||
|
||||
// Sort cursors by name for consistent ordering
|
||||
|
||||
@@ -15,6 +15,7 @@ use winapi::{
|
||||
},
|
||||
um::consoleapi::SetConsoleCtrlHandler,
|
||||
shared::minwindef::{TRUE, FALSE, DWORD},
|
||||
shared::windef::{HDC, HBITMAP, HGDIOBJ},
|
||||
};
|
||||
use ::image::{RgbaImage, open as image_open};
|
||||
|
||||
@@ -27,20 +28,48 @@ extern "system" fn ctrl_handler(_ctrl_type: u32) -> i32 {
|
||||
FALSE // Allow other handlers (like default exit) to run
|
||||
}
|
||||
|
||||
// Create a cursor from an RGBA image
|
||||
unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
let (width, height) = image.dimensions();
|
||||
let width_i32 = width as i32;
|
||||
let height_i32 = height as i32;
|
||||
// Device context setup result
|
||||
struct DeviceContexts {
|
||||
screen_dc: HDC,
|
||||
color_dc: HDC,
|
||||
mask_dc: HDC,
|
||||
}
|
||||
|
||||
// Create device context and bitmap for the color data
|
||||
impl DeviceContexts {
|
||||
unsafe fn cleanup(&self) {
|
||||
DeleteDC(self.mask_dc);
|
||||
DeleteDC(self.color_dc);
|
||||
ReleaseDC(null_mut(), self.screen_dc);
|
||||
}
|
||||
}
|
||||
|
||||
// Bitmap creation result
|
||||
struct CursorBitmaps {
|
||||
color_bitmap: HBITMAP,
|
||||
mask_bitmap: HBITMAP,
|
||||
color_bits_ptr: *mut winapi::ctypes::c_void,
|
||||
mask_bits_ptr: *mut winapi::ctypes::c_void,
|
||||
old_color_bitmap: HGDIOBJ,
|
||||
old_mask_bitmap: HGDIOBJ,
|
||||
}
|
||||
|
||||
impl CursorBitmaps {
|
||||
unsafe fn cleanup(&self, contexts: &DeviceContexts) {
|
||||
SelectObject(contexts.color_dc, self.old_color_bitmap);
|
||||
SelectObject(contexts.mask_dc, self.old_mask_bitmap);
|
||||
DeleteObject(self.color_bitmap as _);
|
||||
DeleteObject(self.mask_bitmap as _);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup device contexts for cursor creation
|
||||
unsafe fn setup_device_contexts() -> Option<DeviceContexts> {
|
||||
let screen_dc = GetDC(null_mut());
|
||||
if screen_dc.is_null() {
|
||||
eprintln!("Failed to get screen DC");
|
||||
return None;
|
||||
}
|
||||
|
||||
// Create a compatible DC for our bitmap
|
||||
let color_dc = CreateCompatibleDC(screen_dc);
|
||||
if color_dc.is_null() {
|
||||
eprintln!("Failed to create compatible DC for color");
|
||||
@@ -48,7 +77,6 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Create a compatible DC for our mask bitmap
|
||||
let mask_dc = CreateCompatibleDC(screen_dc);
|
||||
if mask_dc.is_null() {
|
||||
eprintln!("Failed to create compatible DC for mask");
|
||||
@@ -57,11 +85,24 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(DeviceContexts {
|
||||
screen_dc,
|
||||
color_dc,
|
||||
mask_dc,
|
||||
})
|
||||
}
|
||||
|
||||
// Create bitmaps for cursor creation
|
||||
unsafe fn create_cursor_bitmaps(
|
||||
contexts: &DeviceContexts,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Option<CursorBitmaps> {
|
||||
// Set up BITMAPINFO structure for DIB
|
||||
let mut bitmap_info: BITMAPINFO = std::mem::zeroed();
|
||||
bitmap_info.bmiHeader.biSize = std::mem::size_of::<BITMAPINFOHEADER>() as u32;
|
||||
bitmap_info.bmiHeader.biWidth = width_i32;
|
||||
bitmap_info.bmiHeader.biHeight = -height_i32; // Negative for top-down DIB
|
||||
bitmap_info.bmiHeader.biWidth = width;
|
||||
bitmap_info.bmiHeader.biHeight = -height; // Negative for top-down DIB
|
||||
bitmap_info.bmiHeader.biPlanes = 1;
|
||||
bitmap_info.bmiHeader.biBitCount = 32; // 32 bits per pixel (BGRA)
|
||||
bitmap_info.bmiHeader.biCompression = BI_RGB;
|
||||
@@ -70,7 +111,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
let mut color_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
||||
let mut ppv_bits_color: *mut winapi::ctypes::c_void = color_bits_ptr;
|
||||
let color_bitmap = CreateDIBSection(
|
||||
color_dc,
|
||||
contexts.color_dc,
|
||||
&bitmap_info,
|
||||
DIB_RGB_COLORS,
|
||||
&mut ppv_bits_color,
|
||||
@@ -81,9 +122,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
|
||||
if color_bitmap.is_null() || color_bits_ptr.is_null() {
|
||||
eprintln!("Failed to create color DIB section");
|
||||
DeleteDC(mask_dc);
|
||||
DeleteDC(color_dc);
|
||||
ReleaseDC(null_mut(), screen_dc);
|
||||
contexts.cleanup();
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -92,7 +131,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
let mut mask_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
||||
let mut ppv_bits: *mut winapi::ctypes::c_void = mask_bits_ptr;
|
||||
let mask_bitmap = CreateDIBSection(
|
||||
mask_dc,
|
||||
contexts.mask_dc,
|
||||
&bitmap_info,
|
||||
DIB_RGB_COLORS,
|
||||
&mut ppv_bits,
|
||||
@@ -104,32 +143,51 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
if mask_bitmap.is_null() || mask_bits_ptr.is_null() {
|
||||
eprintln!("Failed to create mask DIB section");
|
||||
DeleteObject(color_bitmap as _);
|
||||
DeleteDC(mask_dc);
|
||||
DeleteDC(color_dc);
|
||||
ReleaseDC(null_mut(), screen_dc);
|
||||
contexts.cleanup();
|
||||
return None;
|
||||
}
|
||||
|
||||
// Select the bitmaps into the DCs
|
||||
let old_color_bitmap = SelectObject(color_dc, color_bitmap as _);
|
||||
let old_mask_bitmap = SelectObject(mask_dc, mask_bitmap as _);
|
||||
let old_color_bitmap = SelectObject(contexts.color_dc, color_bitmap as _);
|
||||
let old_mask_bitmap = SelectObject(contexts.mask_dc, mask_bitmap as _);
|
||||
|
||||
if old_color_bitmap.is_null() || old_mask_bitmap.is_null() {
|
||||
eprintln!("Failed to select bitmaps into DCs");
|
||||
DeleteObject(mask_bitmap as _);
|
||||
DeleteObject(color_bitmap as _);
|
||||
DeleteDC(mask_dc);
|
||||
DeleteDC(color_dc);
|
||||
ReleaseDC(null_mut(), screen_dc);
|
||||
contexts.cleanup();
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(CursorBitmaps {
|
||||
color_bitmap,
|
||||
mask_bitmap,
|
||||
color_bits_ptr,
|
||||
mask_bits_ptr,
|
||||
old_color_bitmap,
|
||||
old_mask_bitmap,
|
||||
})
|
||||
}
|
||||
|
||||
// Process image data and populate bitmaps
|
||||
unsafe fn process_image_data(
|
||||
image: &RgbaImage,
|
||||
bitmaps: &CursorBitmaps,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) {
|
||||
// Copy the image data to the color DIB, converting RGBA to BGRA
|
||||
let color_bits = std::slice::from_raw_parts_mut(color_bits_ptr as *mut u8, (width * height * 4) as usize);
|
||||
let color_bits = std::slice::from_raw_parts_mut(
|
||||
bitmaps.color_bits_ptr as *mut u8,
|
||||
(width * height * 4) as usize,
|
||||
);
|
||||
|
||||
// Calculate mask stride in bytes (1 bit per pixel, padded to DWORD)
|
||||
let mask_stride = ((width + 31) / 32) * 4;
|
||||
let mask_bits = std::slice::from_raw_parts_mut(mask_bits_ptr as *mut u8, (mask_stride * height) as usize);
|
||||
let mask_bits = std::slice::from_raw_parts_mut(
|
||||
bitmaps.mask_bits_ptr as *mut u8,
|
||||
(mask_stride * height) as usize,
|
||||
);
|
||||
|
||||
// Clear mask bits (all transparent initially)
|
||||
for i in 0..(mask_stride * height) as usize {
|
||||
@@ -165,29 +223,25 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create cursor from prepared bitmaps
|
||||
unsafe fn create_cursor_from_bitmaps(
|
||||
bitmaps: &CursorBitmaps,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Option<SyncHCURSOR> {
|
||||
// Create ICONINFO structure
|
||||
let mut icon_info: ICONINFO = std::mem::zeroed();
|
||||
icon_info.fIcon = FALSE; // This is a cursor, not an icon
|
||||
icon_info.xHotspot = width as DWORD / 2; // Center hotspot
|
||||
icon_info.yHotspot = height as DWORD / 2;
|
||||
icon_info.hbmMask = mask_bitmap;
|
||||
icon_info.hbmColor = color_bitmap;
|
||||
icon_info.hbmMask = bitmaps.mask_bitmap;
|
||||
icon_info.hbmColor = bitmaps.color_bitmap;
|
||||
|
||||
// Create the cursor
|
||||
let cursor = CreateIconIndirect(&mut icon_info as *mut _);
|
||||
|
||||
// Clean up resources
|
||||
SelectObject(color_dc, old_color_bitmap);
|
||||
SelectObject(mask_dc, old_mask_bitmap);
|
||||
DeleteDC(color_dc);
|
||||
DeleteDC(mask_dc);
|
||||
ReleaseDC(null_mut(), screen_dc);
|
||||
|
||||
// Windows makes a copy of the bitmaps for the cursor, so we can delete them
|
||||
DeleteObject(color_bitmap as _);
|
||||
DeleteObject(mask_bitmap as _);
|
||||
|
||||
if cursor.is_null() {
|
||||
eprintln!("Failed to create cursor");
|
||||
return None;
|
||||
@@ -197,6 +251,25 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
Some(SyncHCURSOR(cursor))
|
||||
}
|
||||
|
||||
// Create a cursor from an RGBA image
|
||||
unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||
let (width, height) = image.dimensions();
|
||||
let width_i32 = width as i32;
|
||||
let height_i32 = height as i32;
|
||||
|
||||
let contexts = setup_device_contexts()?;
|
||||
let bitmaps = create_cursor_bitmaps(&contexts, width_i32, height_i32)?;
|
||||
|
||||
process_image_data(image, &bitmaps, width, height);
|
||||
|
||||
let cursor = create_cursor_from_bitmaps(&bitmaps, width, height);
|
||||
|
||||
bitmaps.cleanup(&contexts);
|
||||
contexts.cleanup();
|
||||
|
||||
cursor
|
||||
}
|
||||
|
||||
// Helper function to safely lock a mutex with error handling
|
||||
fn safe_lock<'a, T>(mutex: &'a std::sync::Mutex<T>, operation_name: &str) -> Option<std::sync::MutexGuard<'a, T>> {
|
||||
match mutex.lock() {
|
||||
|
||||
Reference in New Issue
Block a user