From 16fc8949b393b23fdce61903c78f8067c34920ff Mon Sep 17 00:00:00 2001 From: JobyGitGud Date: Fri, 30 May 2025 21:20:33 -0500 Subject: [PATCH] Fixed window dragging for main menu --- frontend/src-tauri/build.rs | 2 +- frontend/src-tauri/src/integrations/steam.rs | 14 ++++ frontend/src-tauri/src/lib.rs | 70 +++++++++++++++++- frontend/src-tauri/src/platform/mod.rs | 16 +++- .../src-tauri/src/platform/windows/cursor.rs | 73 +++++++++++++++++-- .../src-tauri/src/platform/windows/mod.rs | 6 ++ frontend/src/App.jsx | 37 ++++++++++ frontend/src/components/Header.css | 13 +++- frontend/src/components/Header.jsx | 29 +++++++- .../components/content_modules/Settings.css | 32 +++++++- .../components/content_modules/Settings.jsx | 25 +++++++ frontend/src/main.jsx | 4 +- 12 files changed, 307 insertions(+), 14 deletions(-) diff --git a/frontend/src-tauri/build.rs b/frontend/src-tauri/build.rs index d9806c7..7047b73 100644 --- a/frontend/src-tauri/build.rs +++ b/frontend/src-tauri/build.rs @@ -1,4 +1,4 @@ -use std::{env, fs::{self, read_dir}, path::{Path, PathBuf}}; +use std::{env, fs::{self, read_dir}, path::PathBuf}; fn main() -> Result<(), Box> { tauri_build::build(); diff --git a/frontend/src-tauri/src/integrations/steam.rs b/frontend/src-tauri/src/integrations/steam.rs index 876c818..6675add 100644 --- a/frontend/src-tauri/src/integrations/steam.rs +++ b/frontend/src-tauri/src/integrations/steam.rs @@ -11,6 +11,7 @@ pub struct Steam { impl Steam { pub fn new() -> Self { let (client, single) = Client::init_app(AppId(1430270)).unwrap(); + println!("Steam client initialized successfully"); Self { client, single } } @@ -23,4 +24,17 @@ impl Steam { // In a real implementation with the correct API version, we would use: // self.client.get_inventory().trigger_item_drop(item_def_id); } + + pub fn shutdown(&self) { + println!("Steam client shutting down"); + // The steamworks crate handles cleanup automatically when the client is dropped + // But we can add any additional cleanup logic here if needed + } +} + +impl Drop for Steam { + fn drop(&mut self) { + println!("Steam client being dropped, performing cleanup"); + self.shutdown(); + } } diff --git a/frontend/src-tauri/src/lib.rs b/frontend/src-tauri/src/lib.rs index 39538ed..d560e9e 100644 --- a/frontend/src-tauri/src/lib.rs +++ b/frontend/src-tauri/src/lib.rs @@ -171,12 +171,22 @@ fn next_cursor( // Command to quit the application #[tauri::command] fn quit_app(app_handle: AppHandle) { + println!("Quit app command received, performing cleanup"); + + // Clean up Steam integration + { + let steam = STEAM.lock(); + steam.shutdown(); + } + // 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), } + println!("Cleanup complete, exiting application"); + // Exit the application std::thread::spawn(move || { app_handle.exit(0); @@ -204,6 +214,52 @@ fn minimize_to_tray(app_handle: AppHandle) -> Result<(), String> { Ok(()) } +// Command to temporarily restore system cursor (for drag operations) +#[tauri::command] +fn temporarily_restore_cursor() -> Result<(), String> { + match platform::restore_system_cursor_temporarily() { + Ok(_) => { + println!("System cursor temporarily restored for drag operation"); + Ok(()) + } + Err(e) => Err(format!("Failed to restore system cursor: {}", e)), + } +} + +// Command to re-apply custom cursor (after drag operations) +#[tauri::command] +fn reapply_custom_cursor(state: tauri::State) -> Result<(), String> { + let app_state = state.0.lock(); + if !app_state.cursors.is_empty() && app_state.current_index < app_state.cursors.len() { + let current_cursor = &app_state.cursors[app_state.current_index]; + match platform::set_system_cursor(¤t_cursor.path) { + Ok(_) => { + println!("Custom cursor re-applied after drag operation"); + Ok(()) + } + Err(e) => Err(format!("Failed to re-apply custom cursor: {}", e)), + } + } else { + Err("No cursor to re-apply".to_string()) + } +} + +// Command to manually restore default cursors +#[tauri::command] +fn restore_default_cursors() -> Result<(), String> { + println!("Manual restore default cursors command received"); + match platform::restore_system_cursor() { + Ok(_) => { + println!("Default cursors restored successfully"); + Ok(()) + } + Err(e) => { + eprintln!("Failed to restore default cursors: {}", e); + Err(format!("Failed to restore default cursors: {}", e)) + } + } +} + // Function to load cursor files from src/cursors directory fn load_cursor_files() -> Vec { println!("=== RESOURCE DEBUG [load_cursor_files] ==="); @@ -403,11 +459,20 @@ pub fn run() { } "quit" => { println!("Quit requested from tray"); + + // Clean up Steam integration + { + let steam = STEAM.lock(); + steam.shutdown(); + } + // 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), } + + println!("Cleanup complete, exiting from tray"); app.exit(0); } _ => {} @@ -441,7 +506,10 @@ pub fn run() { select_cursor, next_cursor, quit_app, - minimize_to_tray + minimize_to_tray, + temporarily_restore_cursor, + reapply_custom_cursor, + restore_default_cursors ]) .setup(|_app| { // Register for events or perform additional setup diff --git a/frontend/src-tauri/src/platform/mod.rs b/frontend/src-tauri/src/platform/mod.rs index 0594ba5..f302649 100644 --- a/frontend/src-tauri/src/platform/mod.rs +++ b/frontend/src-tauri/src/platform/mod.rs @@ -20,7 +20,7 @@ pub type Result = std::result::Result; // Platform-agnostic interface for cursor handling #[cfg(target_os = "windows")] -pub use self::windows::{set_cursor, restore_default_cursor, init}; +pub use self::windows::{set_cursor, restore_default_cursor, restore_default_cursor_temporarily, init}; #[cfg(target_os = "macos")] pub use self::macos::{set_cursor, restore_default_cursor, init}; @@ -52,6 +52,20 @@ pub fn restore_system_cursor() -> Result<()> { restore_default_cursor() } +// Cross-platform implementation for temporarily restoring default cursor +pub fn restore_system_cursor_temporarily() -> Result<()> { + println!("Temporarily restoring system cursor"); + #[cfg(target_os = "windows")] + { + restore_default_cursor_temporarily() + } + #[cfg(not(target_os = "windows"))] + { + // For non-Windows platforms, just use the regular restore for now + restore_default_cursor() + } +} + // Default implementations for non-supported platforms #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] pub fn set_cursor(_path: &str) -> Result<()> { diff --git a/frontend/src-tauri/src/platform/windows/cursor.rs b/frontend/src-tauri/src/platform/windows/cursor.rs index 4792105..2fe87f2 100644 --- a/frontend/src-tauri/src/platform/windows/cursor.rs +++ b/frontend/src-tauri/src/platform/windows/cursor.rs @@ -202,6 +202,13 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option { pub fn cleanup() { println!("Running cursor cleanup..."); + // Check if we have original cursors saved before attempting restoration + let has_original_cursors = { + let guard = ORIGINAL_CURSORS.lock().unwrap(); + guard.is_some() + }; + println!("Has original cursors saved: {}", has_original_cursors); + // Restore system cursors if they were hidden // Use swap to ensure it runs only once if CURSOR_HIDDEN.swap(false, Ordering::SeqCst) { @@ -211,15 +218,24 @@ pub fn cleanup() { // 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(); + let original_cursors_opt = { + let mut guard = ORIGINAL_CURSORS.lock().unwrap(); + guard.take() + }; + if let Some(original_cursors) = original_cursors_opt { - println!("Restoring {} saved original cursors", original_cursors.len()); + let total_cursors = original_cursors.len(); + println!("Restoring {} saved original cursors", total_cursors); + let mut restored_count = 0; 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 { + if SetSystemCursor(cursor_copy, cursor_id) != 0 { + restored_count += 1; + println!("Successfully restored cursor for ID: {}", cursor_id); + } else { eprintln!("Failed to restore original cursor for ID: {}", cursor_id); DestroyIcon(cursor_copy); } @@ -231,8 +247,25 @@ pub fn cleanup() { DestroyIcon(cursor.0); } } + println!("Restored {} out of {} original cursors", restored_count, total_cursors); } else { - println!("No saved original cursors found"); + println!("No saved original cursors found, using fallback restoration methods"); + + // Try to restore each system cursor to its default + for &cursor_id in SYSTEM_CURSORS.iter() { + let default_cursor = LoadCursorW(null_mut(), MAKEINTRESOURCEW(cursor_id as u16)); + if !default_cursor.is_null() { + let cursor_copy = CopyIcon(default_cursor); + if !cursor_copy.is_null() { + if SetSystemCursor(cursor_copy, cursor_id) != 0 { + println!("Restored default cursor for ID: {}", cursor_id); + } else { + eprintln!("Failed to restore default cursor for ID: {}", cursor_id); + DestroyIcon(cursor_copy); + } + } + } + } } // 2. Force Windows to reload default cursor settings @@ -310,19 +343,26 @@ pub fn hide_system_cursor() -> bool { // Save original cursors for restoration let mut original_cursors = Vec::new(); unsafe { + println!("Saving original cursors for restoration..."); for &cursor_id in SYSTEM_CURSORS.iter() { // Get the original cursor let original_cursor = CopyIcon(LoadCursorW(null_mut(), MAKEINTRESOURCEW(cursor_id as u16))); if !original_cursor.is_null() { // Save the original cursor for restoration original_cursors.push((cursor_id, SyncHCURSOR(original_cursor))); + println!("Saved original cursor for ID: {}", cursor_id); + } else { + eprintln!("Failed to save original cursor for ID: {}", cursor_id); } } } // Store original cursors for restoration if !original_cursors.is_empty() { + println!("Storing {} original cursors for later restoration", original_cursors.len()); *ORIGINAL_CURSORS.lock().unwrap() = Some(original_cursors); + } else { + eprintln!("No original cursors were saved!"); } // Mark as hidden - this is now just a flag to indicate we've saved the original cursors @@ -497,7 +537,30 @@ unsafe fn apply_cursor_to_all_system_cursors(cursor: winapi::shared::windef::HCU success } -// Restore the system cursor +// Restore the system cursor temporarily (without affecting cleanup state) +pub fn restore_cursor_temporarily() { + println!("Temporarily restoring system cursors..."); + + unsafe { + // Force Windows to reload default cursor settings + println!("Forcing Windows to reload default cursor settings"); + SystemParametersInfoW(SPI_SETCURSORS, 0, null_mut(), 0); + + // Also try the A version for maximum compatibility + super::state::reset_system_cursors(); + + // Reset to default arrow cursor + let arrow_cursor = LoadCursorW(null_mut(), MAKEINTRESOURCEW(IDC_ARROW as u16)); + if !arrow_cursor.is_null() { + SetCursor(arrow_cursor); + println!("Reset to default arrow cursor temporarily."); + } + } + + println!("Temporary cursor restoration complete."); +} + +// Restore the system cursor permanently (full cleanup) pub fn restore_cursor() { cleanup(); } diff --git a/frontend/src-tauri/src/platform/windows/mod.rs b/frontend/src-tauri/src/platform/windows/mod.rs index 45dad1e..cbd7414 100644 --- a/frontend/src-tauri/src/platform/windows/mod.rs +++ b/frontend/src-tauri/src/platform/windows/mod.rs @@ -36,6 +36,12 @@ pub fn restore_default_cursor() -> Result<()> { Ok(()) } +pub fn restore_default_cursor_temporarily() -> Result<()> { + println!("Windows platform: temporarily restoring default cursor"); + cursor::restore_cursor_temporarily(); + Ok(()) +} + pub fn init() -> Result<()> { println!("Windows platform: initializing cursor system"); if !cursor::hide_system_cursor() { diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 00caadf..0224975 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -47,6 +47,35 @@ function App() { } }, []); + // Function to handle window focus/show events to re-apply cursor + useEffect(() => { + const setupFocusHandler = async () => { + const unlistenFocus = await appWindow.onFocusChanged(async ({ payload: focused }) => { + if (focused) { + console.log('Window gained focus, re-applying custom cursor'); + try { + await invoke("reapply_custom_cursor"); + } catch (error) { + console.error('Failed to re-apply cursor on focus:', error); + } + } + }); + + return unlistenFocus; + }; + + let unlistenFocusFn; + setupFocusHandler().then(unlisten => { + unlistenFocusFn = unlisten; + }).catch(err => console.error('Failed to set up focus handler:', err)); + + return () => { + if (unlistenFocusFn) { + unlistenFocusFn(); + } + }; + }, []); + // Load cursors on mount and set up event listeners useEffect(() => { const loadCursors = async () => { @@ -87,6 +116,14 @@ function App() { // Prevent the window from closing event.preventDefault(); + // Temporarily restore cursor before hiding to tray + try { + console.log('Temporarily restoring cursor before hiding to tray'); + await invoke("temporarily_restore_cursor"); + } catch (error) { + console.error('Failed to restore cursor before hiding:', error); + } + // Hide the window instead try { console.log('Calling minimizeToTray function'); diff --git a/frontend/src/components/Header.css b/frontend/src/components/Header.css index cf3e4ed..42c4a91 100644 --- a/frontend/src/components/Header.css +++ b/frontend/src/components/Header.css @@ -6,7 +6,8 @@ position: relative; z-index: 10; background-color: transparent; /* Reverted to original */ - /* cursor: move; */ /* Removed, should be handled by drag region or default */ + -webkit-app-region: drag; /* Ensure the header is draggable */ + /* cursor: move; */ /* Let the system handle cursor during drag operations */ } .tabs-container { @@ -64,6 +65,16 @@ color: rgba(205, 214, 244, 0.8); } +/* Dedicated drag area */ +.drag-area { + flex: 1; /* Take up remaining space */ + height: 100%; + min-width: 50px; /* Ensure there's always some draggable space */ + -webkit-app-region: drag; /* Explicitly set as draggable */ + /* cursor: move; */ /* Let the system handle cursor during drag operations */ + background-color: transparent; +} + /* Window control buttons */ .window-controls { -webkit-app-region: no-drag; /* Override drag region for buttons */ diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index 891c749..a7d175c 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -1,6 +1,8 @@ import React from 'react'; import './Header.css'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { appWindow } from '@tauri-apps/api/window'; +import { invoke } from '@tauri-apps/api/tauri'; import { faGripVertical, faBoxOpen, @@ -36,8 +38,29 @@ function Header({ activePage, setActivePage, minimizeToTray, quitApp, settings } } }; + // Handle window dragging programmatically as a fallback + const handleMouseDown = async (e) => { + // Only start dragging on left mouse button and if not clicking on interactive elements + if (e.button === 0 && !e.target.closest('.tab, .window-controls')) { + try { + // Temporarily restore system cursor for dragging + await invoke('temporarily_restore_cursor'); + await appWindow.startDragging(); + } catch (error) { + console.error('Failed to start window dragging:', error); + } finally { + // Re-apply custom cursor after dragging + try { + await invoke('reapply_custom_cursor'); + } catch (error) { + console.error('Failed to re-apply custom cursor:', error); + } + } + } + }; + return ( -
+
{navItems.map((item) => (
))} + + {/* Dedicated drag area */} +
+
+

+ Manually restore the system's default cursors if they're not working properly. +

+
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 774fd95..2ac6b13 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -3,7 +3,5 @@ import ReactDOM from "react-dom/client"; import App from "./App"; ReactDOM.createRoot(document.getElementById("root")).render( - - - , + );