Files
cursor_rush/frontend/src-tauri/src/lib.rs
T
2025-05-16 17:38:33 +02:00

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");
}