295 lines
11 KiB
Rust
295 lines
11 KiB
Rust
use std::sync::Mutex;
|
|
use serde::{Serialize, Deserialize};
|
|
use tauri::{Manager, AppHandle};
|
|
use std::path::{Path, PathBuf};
|
|
use std::env;
|
|
|
|
mod platform;
|
|
|
|
// Define cursor structure
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Cursor {
|
|
name: String,
|
|
path: String,
|
|
}
|
|
|
|
// App state to track cursors
|
|
pub struct AppState {
|
|
cursors: Vec<Cursor>,
|
|
current_index: usize,
|
|
}
|
|
|
|
// Thread-safe app state wrapper
|
|
pub struct AppStateWrapper(Mutex<AppState>);
|
|
|
|
// Command to get all cursors
|
|
#[tauri::command]
|
|
fn get_cursors(state: tauri::State<AppStateWrapper>) -> Vec<Cursor> {
|
|
let app_state = state.0.lock().unwrap();
|
|
app_state.cursors.clone()
|
|
}
|
|
|
|
// Command to get current cursor index
|
|
#[tauri::command]
|
|
fn get_current_cursor_index(state: tauri::State<AppStateWrapper>) -> usize {
|
|
let app_state = state.0.lock().unwrap();
|
|
app_state.current_index
|
|
}
|
|
|
|
// Command to select a cursor
|
|
#[tauri::command]
|
|
fn select_cursor(index: usize, state: tauri::State<AppStateWrapper>, app_handle: AppHandle) -> Result<(), String> {
|
|
println!("=== RESOURCE DEBUG [select_cursor] ===");
|
|
|
|
let mut app_state = state.0.lock().unwrap();
|
|
if index < app_state.cursors.len() {
|
|
app_state.current_index = index;
|
|
|
|
let cursor = &app_state.cursors[index];
|
|
println!("Cursor selected: {}", cursor.name);
|
|
println!("Original path: {}", cursor.path);
|
|
|
|
// Get the resource directory
|
|
let resource_dir = app_handle.path_resolver().resource_dir();
|
|
println!("Resource dir: {:?}", resource_dir);
|
|
|
|
// List contents of resource dir
|
|
if let Some(res_dir) = &resource_dir {
|
|
println!("Listing contents of resource dir: {}", res_dir.display());
|
|
if let Ok(entries) = std::fs::read_dir(res_dir) {
|
|
for (i, entry) in entries.filter_map(Result::ok).enumerate() {
|
|
println!(" {}: {}", i, entry.path().display());
|
|
|
|
// List subdirectories
|
|
if entry.path().is_dir() {
|
|
if let Ok(subentries) = std::fs::read_dir(entry.path()) {
|
|
for (j, subentry) in subentries.filter_map(Result::ok).enumerate() {
|
|
println!(" {}.{}: {}", i, j, subentry.path().display());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
println!("Failed to read resource directory");
|
|
}
|
|
}
|
|
|
|
let filename = Path::new(&cursor.path)
|
|
.file_name()
|
|
.and_then(|name| name.to_str())
|
|
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
|
|
|
println!("Extracted filename: {}", filename);
|
|
|
|
// Try using the actual file path directly
|
|
println!("Using direct file path: {}", cursor.path);
|
|
|
|
// Verify the file exists
|
|
if Path::new(&cursor.path).exists() {
|
|
println!("File exists, applying cursor...");
|
|
|
|
if let Err(e) = platform::set_system_cursor(&cursor.path) {
|
|
println!("Error applying cursor: {}", e);
|
|
return Err(format!("Failed to apply cursor '{}': {}", cursor.name, e));
|
|
}
|
|
|
|
// Emit an event to notify the frontend
|
|
let _ = app_handle.emit_all("cursor_changed", index); // Ignore error
|
|
|
|
println!("Successfully applied cursor using actual file path");
|
|
return Ok(());
|
|
} else {
|
|
println!("File doesn't exist: {}", cursor.path);
|
|
return Err(format!("Cursor file does not exist: {}", cursor.path));
|
|
}
|
|
} else {
|
|
Err("Index out of bounds".to_string())
|
|
}
|
|
}
|
|
|
|
// Command to go to the next cursor
|
|
#[tauri::command]
|
|
fn next_cursor(state: tauri::State<AppStateWrapper>, app_handle: AppHandle) -> Result<usize, String> {
|
|
println!("=== RESOURCE DEBUG [next_cursor] ===");
|
|
|
|
let mut app_state = state.0.lock().unwrap();
|
|
if !app_state.cursors.is_empty() {
|
|
app_state.current_index = (app_state.current_index + 1) % app_state.cursors.len();
|
|
|
|
let cursor = &app_state.cursors[app_state.current_index];
|
|
println!("Next cursor: {} ({})", cursor.name, 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))?;
|
|
|
|
// Try both resource paths like in select_cursor
|
|
println!("Extracted filename: {}", filename);
|
|
|
|
// Try using the actual file path directly
|
|
println!("Using direct file path: {}", cursor.path);
|
|
|
|
// Verify the file exists
|
|
if Path::new(&cursor.path).exists() {
|
|
println!("File exists, applying cursor...");
|
|
|
|
if let Err(e) = platform::set_system_cursor(&cursor.path) {
|
|
println!("Error applying cursor: {}", e);
|
|
return Err(format!("Failed to apply cursor '{}': {}", cursor.name, e));
|
|
}
|
|
|
|
// Emit an event to notify the frontend
|
|
let _ = app_handle.emit_all("cursor_changed", app_state.current_index); // Ignore error
|
|
|
|
println!("Successfully applied cursor using actual file path");
|
|
return Ok(app_state.current_index);
|
|
} else {
|
|
println!("File doesn't exist: {}", cursor.path);
|
|
return Err(format!("Cursor file does not exist: {}", cursor.path));
|
|
}
|
|
} else {
|
|
Err("No cursors available".to_string())
|
|
}
|
|
}
|
|
|
|
// Command to quit the application
|
|
#[tauri::command]
|
|
fn quit_app(app_handle: AppHandle) {
|
|
// Clean up and restore default cursor before exit
|
|
match platform::restore_system_cursor() {
|
|
Ok(_) => println!("Default cursor restored"),
|
|
Err(e) => eprintln!("Failed to restore default cursor: {}", e),
|
|
}
|
|
|
|
// Exit the application
|
|
std::thread::spawn(move || {
|
|
app_handle.exit(0);
|
|
});
|
|
}
|
|
|
|
// Function to load cursor files from src/cursors directory
|
|
fn load_cursor_files() -> Vec<Cursor> {
|
|
println!("=== RESOURCE DEBUG [load_cursor_files] ===");
|
|
let mut cursors = Vec::new();
|
|
|
|
// Determine the path to src/cursors relative to src-tauri (CARGO_MANIFEST_DIR)
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
println!("CARGO_MANIFEST_DIR: {}", manifest_dir.display());
|
|
|
|
// Check multiple possible locations
|
|
let possible_cursor_dirs = vec![
|
|
manifest_dir.join("../src/cursors"),
|
|
manifest_dir.join("src/cursors"),
|
|
manifest_dir.join("cursors"),
|
|
manifest_dir.clone(), // Check manifest dir itself
|
|
];
|
|
|
|
println!("CHECKING FOR PNG/CUR FILES IN MULTIPLE DIRECTORIES:");
|
|
for (i, cursors_dir) in possible_cursor_dirs.iter().enumerate() {
|
|
println!("Checking dir {}: {}", i+1, cursors_dir.display());
|
|
println!(" Directory exists: {}", cursors_dir.exists());
|
|
|
|
if cursors_dir.exists() {
|
|
println!(" Looking for cursor files in this directory...");
|
|
|
|
if let Ok(entries) = std::fs::read_dir(cursors_dir) {
|
|
for entry in entries.filter_map(Result::ok) {
|
|
let path = entry.path();
|
|
println!(" Found: {}", path.display());
|
|
|
|
if path.is_file() && path.extension().map_or(false, |ext| ext == "png" || ext == "cur") {
|
|
let name = path.file_stem()
|
|
.and_then(|s| s.to_str())
|
|
.unwrap_or("Unknown")
|
|
.to_string();
|
|
|
|
println!(" ADDING CURSOR: {} at path {}", name, path.display());
|
|
cursors.push(Cursor {
|
|
name,
|
|
path: path.to_string_lossy().to_string(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if !cursors.is_empty() {
|
|
println!(" Found {} cursor files in this directory.", cursors.len());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we found no cursors, use mock data with paths relative to what resolve_resource expects
|
|
if cursors.is_empty() {
|
|
println!("No cursors found in any directory. Using mock data instead.");
|
|
println!("IMPORTANT: This is probably the source of your problem!");
|
|
println!("The app could not find your cursor PNG files. Check that they exist in one of these directories:");
|
|
for dir in &possible_cursor_dirs {
|
|
println!(" {}", dir.display());
|
|
}
|
|
|
|
// Mock data paths should reflect their eventual resource path structure
|
|
cursors.push(Cursor {
|
|
name: "Default".to_string(),
|
|
path: "src/cursors/default.png".to_string(), // Filename will be 'default.png'
|
|
});
|
|
|
|
cursors.push(Cursor {
|
|
name: "Icon".to_string(),
|
|
path: "src/cursors/icon.png".to_string(), // Filename will be 'icon.png'
|
|
});
|
|
|
|
cursors.push(Cursor {
|
|
name: "Red".to_string(),
|
|
path: "src/cursors/red.png".to_string(), // Filename will be 'red.png'
|
|
});
|
|
|
|
println!("Created {} mock cursor entries", cursors.len());
|
|
}
|
|
|
|
println!("Loaded {} cursor files", cursors.len());
|
|
|
|
// Sort cursors by name for consistent ordering
|
|
cursors.sort_by(|a, b| a.name.cmp(&b.name));
|
|
cursors
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
println!("Starting Cursor Rush application");
|
|
|
|
// Initialize platform-specific cursor handling
|
|
if let Err(e) = platform::initialize() {
|
|
eprintln!("Failed to initialize platform: {}", e);
|
|
}
|
|
|
|
// Load cursors from assets directory
|
|
let cursors = load_cursor_files();
|
|
|
|
// Create app state
|
|
let app_state = AppState {
|
|
cursors,
|
|
current_index: 0,
|
|
};
|
|
|
|
// This is one of the simplest ways to initialize Tauri
|
|
tauri::Builder::default()
|
|
.manage(AppStateWrapper(Mutex::new(app_state)))
|
|
.invoke_handler(tauri::generate_handler![
|
|
get_cursors,
|
|
get_current_cursor_index,
|
|
select_cursor,
|
|
next_cursor,
|
|
quit_app
|
|
])
|
|
.setup(|_app| {
|
|
// Register for events or perform additional setup
|
|
println!("Tauri application setup complete");
|
|
Ok(())
|
|
})
|
|
// This matches exactly how it was before our changes
|
|
.run(tauri::generate_context!())
|
|
.expect("error while running tauri application");
|
|
}
|