1+ use std:: sync:: Arc ;
2+ use tauri:: { AppHandle , Emitter , Listener , Manager } ;
3+ use device_query:: { DeviceQuery , DeviceState } ;
4+ use crate :: mouse_service:: { MouseService , MouseEvent } ;
5+ use crate :: window_management:: {
6+ create_selection_icon, create_or_focus_compact_window,
7+ get_current_active_app, restore_focus_to_app
8+ } ;
9+
10+ #[ cfg( target_os = "windows" ) ]
11+ use crate :: window_management:: { get_current_active_window, restore_focus_to_window} ;
12+
13+ pub fn setup_selection_icon_events (
14+ app_handle : & AppHandle ,
15+ mouse_service : & Arc < MouseService >
16+ ) {
17+ let selection_app_handle = app_handle. clone ( ) ;
18+ let mouse_service_for_icon = mouse_service. clone ( ) ;
19+
20+ app_handle. listen ( "create-selection-icon" , move |event| {
21+ println ! ( "Received create-selection-icon event from mouse service" ) ;
22+ if let Ok ( payload) = serde_json:: from_str :: < serde_json:: Value > ( event. payload ( ) ) {
23+ if let ( Some ( text) , Some ( x) , Some ( y) ) = (
24+ payload. get ( "text" ) . and_then ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) ,
25+ payload. get ( "x" ) . and_then ( |v| v. as_i64 ( ) ) ,
26+ payload. get ( "y" ) . and_then ( |v| v. as_i64 ( ) )
27+ ) {
28+ // Get the current active app/window BEFORE showing the selection icon
29+ #[ cfg( target_os = "macos" ) ]
30+ let current_app = get_current_active_app ( ) ;
31+
32+ #[ cfg( target_os = "windows" ) ]
33+ let current_window = get_current_active_window ( ) ;
34+
35+ #[ cfg( not( any( target_os = "macos" , target_os = "windows" ) ) ) ]
36+ let _current_app: Option < String > = None ;
37+
38+ let app_handle = selection_app_handle. clone ( ) ;
39+ let mouse_service_ref = mouse_service_for_icon. clone ( ) ;
40+ tauri:: async_runtime:: spawn ( async move {
41+ match create_selection_icon ( & app_handle, x as i32 , y as i32 ) . await {
42+ Ok ( window) => {
43+ // Store the selected text in the window's state
44+ if let Err ( e) = window. emit ( "set-selected-text" , & text) {
45+ println ! ( "Failed to emit set-selected-text event: {}" , e) ;
46+ }
47+ if let Err ( e) = window. show ( ) {
48+ println ! ( "Failed to show selection icon window: {}" , e) ;
49+ }
50+
51+ // Track the selection icon bounds and visibility
52+ let icon_size = 24 ; // Icon size from create_selection_icon
53+ mouse_service_ref. set_selection_icon_bounds (
54+ x as i32 ,
55+ y as i32 ,
56+ icon_size,
57+ icon_size
58+ ) ;
59+ mouse_service_ref. set_selection_icon_visible ( true ) ;
60+ println ! ( "Selection icon bounds set: ({}, {}, {}, {})" , x, y, icon_size, icon_size) ;
61+
62+ // After showing the icon, restore focus to the original app/window
63+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
64+
65+ #[ cfg( target_os = "macos" ) ]
66+ if let Some ( app_name) = current_app {
67+ restore_focus_to_app ( & app_name) ;
68+ println ! ( "Restored focus to application: {}" , app_name) ;
69+ }
70+
71+ #[ cfg( target_os = "windows" ) ]
72+ if let Some ( hwnd) = current_window {
73+ restore_focus_to_window ( hwnd) ;
74+ println ! ( "Restored focus to previous window" ) ;
75+ }
76+ } ,
77+ Err ( e) => {
78+ println ! ( "Failed to create selection icon window: {}" , e) ;
79+ }
80+ }
81+ } ) ;
82+ } else {
83+ println ! ( "Invalid payload for create-selection-icon event" ) ;
84+ }
85+ } else {
86+ println ! ( "Failed to parse create-selection-icon event payload" ) ;
87+ }
88+ } ) ;
89+ }
90+
91+ pub fn setup_icon_click_events (
92+ app_handle : & AppHandle ,
93+ mouse_service : & Arc < MouseService >
94+ ) {
95+ let icon_app_handle = app_handle. clone ( ) ;
96+ let mouse_service_for_click = mouse_service. clone ( ) ;
97+
98+ app_handle. listen ( "icon-clicked" , move |event| {
99+ if let Some ( _icon_window) = icon_app_handle. get_webview_window ( "selection-icon" ) {
100+ // Get the current mouse position for the translate popup
101+ let device_state = DeviceState :: new ( ) ;
102+ let ( x, y) = device_state. get_mouse ( ) . coords ;
103+
104+ // Get the selected text from the event payload
105+ let selected_text = event. payload ( ) . to_owned ( ) ;
106+
107+ // Show the translate popup in a separate thread to avoid blocking
108+ let app_handle = icon_app_handle. clone ( ) ;
109+ let mouse_service_ref = mouse_service_for_click. clone ( ) ;
110+ tauri:: async_runtime:: spawn ( async move {
111+ match create_or_focus_compact_window ( & app_handle, x, y) . await {
112+ Ok ( translate_window) => {
113+ if let Err ( e) = translate_window. emit ( "shortcut-quickTranslate" , serde_json:: json!( {
114+ "text" : selected_text
115+ } ) ) {
116+ println ! ( "Failed to emit shortcut-quickTranslate event: {}" , e) ;
117+ }
118+ if let Err ( e) = translate_window. show ( ) {
119+ println ! ( "Failed to show translate window: {}" , e) ;
120+ }
121+ if let Err ( e) = translate_window. set_focus ( ) {
122+ println ! ( "Failed to set focus on translate window: {}" , e) ;
123+ }
124+
125+ // Hide the selection icon after showing the translate popup
126+ if let Some ( icon_window) = app_handle. get_webview_window ( "selection-icon" ) {
127+ if let Err ( e) = icon_window. hide ( ) {
128+ println ! ( "Failed to hide selection icon after showing translate popup: {}" , e) ;
129+ } else {
130+ mouse_service_ref. set_selection_icon_visible ( false ) ;
131+ println ! ( "Selection icon hidden after showing translate popup" ) ;
132+ }
133+ }
134+ } ,
135+ Err ( e) => {
136+ println ! ( "Failed to create translate window: {}" , e) ;
137+ }
138+ }
139+ } ) ;
140+ }
141+ } ) ;
142+ }
143+
144+ pub fn setup_mouse_events (
145+ app_handle : & AppHandle ,
146+ mouse_service : & Arc < MouseService >
147+ ) {
148+ let app_handle_for_service = app_handle. clone ( ) ;
149+ let mouse_service_for_events = mouse_service. clone ( ) ;
150+
151+ mouse_service. start ( app_handle. clone ( ) , move |event| {
152+ let app_handle = app_handle_for_service. clone ( ) ;
153+ match event {
154+ MouseEvent :: TextSelected ( text) => {
155+ let device_state = DeviceState :: new ( ) ;
156+ let ( x, y) = device_state. get_mouse ( ) . coords ;
157+
158+ // Emit event to main thread to handle window creation (thread safety)
159+ println ! ( "Text selected from mouse service, emitting event to main thread" ) ;
160+ if let Err ( e) = app_handle. emit ( "create-selection-icon" , serde_json:: json!( {
161+ "text" : text,
162+ "x" : x + 5 ,
163+ "y" : y - 5
164+ } ) ) {
165+ println ! ( "Failed to emit create-selection-icon event: {}" , e) ;
166+ }
167+ } ,
168+ MouseEvent :: ClickOutsideIcon ( x, y) => {
169+ println ! ( "Click outside icon detected at ({}, {})" , x, y) ;
170+ if let Some ( icon_window) = app_handle. get_webview_window ( "selection-icon" ) {
171+ if let Err ( e) = icon_window. hide ( ) {
172+ println ! ( "Failed to hide selection icon: {}" , e) ;
173+ } else {
174+ println ! ( "Selection icon hidden due to outside click" ) ;
175+ // Update the mouse service state
176+ mouse_service_for_events. set_selection_icon_visible ( false ) ;
177+ }
178+ }
179+ } ,
180+ _ => { }
181+ }
182+ } ) ;
183+ }
184+
185+ pub fn setup_cleanup_events ( app_handle : & AppHandle ) {
186+ let cleanup_handle = app_handle. clone ( ) ;
187+ app_handle. listen ( "app-shutdown" , move |_| {
188+ println ! ( "Application shutting down, cleaning up windows..." ) ;
189+
190+ // Close all windows properly to prevent window class issues
191+ if let Some ( window) = cleanup_handle. get_webview_window ( "translate-popup" ) {
192+ println ! ( "Closing translate-popup window" ) ;
193+ let _ = window. close ( ) ;
194+ }
195+
196+ if let Some ( window) = cleanup_handle. get_webview_window ( "selection-icon" ) {
197+ println ! ( "Closing selection-icon window" ) ;
198+ let _ = window. close ( ) ;
199+ }
200+
201+ if let Some ( window) = cleanup_handle. get_webview_window ( "main" ) {
202+ println ! ( "Closing main window" ) ;
203+ let _ = window. close ( ) ;
204+ }
205+
206+ println ! ( "Window cleanup completed" ) ;
207+ } ) ;
208+ }
0 commit comments