@@ -9,6 +9,7 @@ use native_windows_gui as nwg;
99use super :: auto_attach_tab:: AutoAttachTab ;
1010use super :: connected_tab:: ConnectedTab ;
1111use super :: persisted_tab:: PersistedTab ;
12+ use crate :: usbipd:: UsbDevice ;
1213use crate :: {
1314 auto_attach:: AutoAttacher ,
1415 win_utils:: { self , DeviceNotification } ,
@@ -25,6 +26,7 @@ pub(super) trait GuiTab {
2526#[ derive( Default , NwgUi ) ]
2627pub struct UsbipdGui {
2728 device_notification : Cell < DeviceNotification > ,
29+ menu_tray_event_handler : RefCell < Option < nwg:: EventHandler > > ,
2830
2931 #[ nwg_resource]
3032 embed : nwg:: EmbedResource ,
@@ -75,37 +77,22 @@ pub struct UsbipdGui {
7577
7678 // Tray icon
7779 #[ nwg_control( icon: Some ( & data. app_icon) , tip: Some ( "WSL USB Manager" ) ) ]
78- #[ nwg_events( OnContextMenu : [ UsbipdGui :: show_tray_menu ] , MousePressLeftUp : [ UsbipdGui :: show] ) ]
80+ #[ nwg_events( OnContextMenu : [ UsbipdGui :: show_menu_tray ( RC_SELF ) ] , MousePressLeftUp : [ UsbipdGui :: show( RC_SELF ) ] ) ]
7981 tray : nwg:: TrayNotification ,
8082
81- // Tray menu
82- #[ nwg_control( parent: window, popup: true ) ]
83- menu_tray : nwg:: Menu ,
84-
85- #[ nwg_control( parent: menu_tray, text: "Open" ) ]
86- #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: show] ) ]
87- menu_tray_open : nwg:: MenuItem ,
88-
89- #[ nwg_control( parent: menu_tray) ]
90- menu_tray_sep : nwg:: MenuSeparator ,
91-
92- #[ nwg_control( parent: menu_tray, text: "Exit" ) ]
93- #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: exit] ) ]
94- menu_tray_exit : nwg:: MenuItem ,
95-
9683 // File menu
9784 #[ nwg_control( parent: window, text: "File" , popup: false ) ]
9885 menu_file : nwg:: Menu ,
9986
10087 #[ nwg_control( parent: menu_file, text: "Refresh" ) ]
101- #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: refresh] ) ]
88+ #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: refresh( RC_SELF ) ] ) ]
10289 menu_file_refresh : nwg:: MenuItem ,
10390
10491 #[ nwg_control( parent: menu_file) ]
10592 menu_file_sep1 : nwg:: MenuSeparator ,
10693
10794 #[ nwg_control( parent: menu_file, text: "Exit" ) ]
108- #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: exit] ) ]
95+ #[ nwg_events( OnMenuItemSelected : [ UsbipdGui :: exit( ) ] ) ]
10996 menu_file_exit : nwg:: MenuItem ,
11097}
11198
@@ -150,22 +137,120 @@ impl UsbipdGui {
150137 self . window . set_visible ( false ) ;
151138 }
152139
153- fn show ( & self ) {
140+ fn show ( self : & Rc < UsbipdGui > ) {
154141 self . window . set_visible ( true ) ;
155142 }
156143
157- fn show_tray_menu ( & self ) {
144+ fn show_menu_tray ( self : & Rc < UsbipdGui > ) {
145+ if let Some ( handler) = self . menu_tray_event_handler . borrow ( ) . as_ref ( ) {
146+ nwg:: unbind_event_handler ( handler) ;
147+ }
148+
149+ let mut menu_tray = nwg:: Menu :: default ( ) ;
150+ nwg:: Menu :: builder ( )
151+ . popup ( true )
152+ . parent ( self . window . handle )
153+ . build ( & mut menu_tray)
154+ . unwrap ( ) ;
155+
156+ let devices = self
157+ . connected_tab_content
158+ . connected_devices
159+ . borrow ( )
160+ . iter ( )
161+ . cloned ( )
162+ . collect :: < Vec < _ > > ( ) ;
163+
164+ let mut menu_items: Vec < ( nwg:: MenuItem , Rc < UsbDevice > ) > = Vec :: with_capacity ( devices. len ( ) ) ;
165+ for device in devices {
166+ let device_name = device. description . as_deref ( ) ;
167+ let vid_pid = device. vid_pid ( ) ;
168+ let description = device_name. map ( |s| s. to_string ( ) ) . unwrap_or (
169+ vid_pid
170+ . clone ( )
171+ . unwrap_or_else ( || "Unknown Device" . to_string ( ) ) ,
172+ ) ;
173+
174+ if device. is_bound ( ) {
175+ let menu_item = self
176+ . new_menu_item ( menu_tray. handle , & description, device. is_attached ( ) )
177+ . unwrap ( ) ;
178+
179+ menu_items. push ( ( menu_item, Rc :: new ( device. clone ( ) ) ) ) ;
180+ }
181+ }
182+
183+ self . new_menu_separator ( menu_tray. handle ) . unwrap ( ) ;
184+ let open_item = self . new_menu_item ( menu_tray. handle , "Open" , false ) . unwrap ( ) ;
185+ self . new_menu_separator ( menu_tray. handle ) . unwrap ( ) ;
186+ let exit_item = self . new_menu_item ( menu_tray. handle , "Exit" , false ) . unwrap ( ) ;
187+
188+ let rc_self_weak = Rc :: downgrade ( & self ) ;
189+ * self . menu_tray_event_handler . borrow_mut ( ) = Some ( nwg:: full_bind_event_handler (
190+ & self . window . handle ,
191+ move |evt, _evt_data, handle| {
192+ if let Some ( rc_self) = rc_self_weak. upgrade ( ) {
193+ match evt {
194+ nwg:: Event :: OnMenuItemSelected => {
195+ if handle == open_item. handle {
196+ UsbipdGui :: show ( & rc_self) ;
197+ } else if handle == exit_item. handle {
198+ UsbipdGui :: exit ( ) ;
199+ } else {
200+ for ( menu_item, device) in menu_items. iter ( ) {
201+ if handle == menu_item. handle {
202+ if device. is_attached ( ) {
203+ device. detach ( ) . ok ( ) ;
204+ } else {
205+ device. attach ( ) . ok ( ) ;
206+ }
207+ }
208+ }
209+ }
210+ }
211+ _ => ( ) ,
212+ }
213+ }
214+ } ,
215+ ) ) ;
216+
158217 let ( x, y) = nwg:: GlobalCursor :: position ( ) ;
159- self . menu_tray . popup ( x, y) ;
218+ menu_tray. popup ( x, y) ;
219+ }
220+
221+ fn new_menu_item (
222+ self : & Rc < UsbipdGui > ,
223+ parent : nwg:: ControlHandle ,
224+ text : & str ,
225+ check : bool ,
226+ ) -> Result < nwg:: MenuItem , nwg:: NwgError > {
227+ let mut menu_item = nwg:: MenuItem :: default ( ) ;
228+ nwg:: MenuItem :: builder ( )
229+ . text ( text)
230+ . parent ( parent)
231+ . check ( check)
232+ . build ( & mut menu_item)
233+ . map ( |_| menu_item)
234+ }
235+
236+ fn new_menu_separator (
237+ self : & Rc < UsbipdGui > ,
238+ parent : nwg:: ControlHandle ,
239+ ) -> Result < nwg:: MenuSeparator , nwg:: NwgError > {
240+ let mut sep = nwg:: MenuSeparator :: default ( ) ;
241+ nwg:: MenuSeparator :: builder ( )
242+ . parent ( parent)
243+ . build ( & mut sep)
244+ . map ( |_| sep)
160245 }
161246
162- fn refresh ( & self ) {
247+ fn refresh ( self : & Rc < UsbipdGui > ) {
163248 self . connected_tab_content . refresh ( ) ;
164249 self . persisted_tab_content . refresh ( ) ;
165250 self . auto_attach_tab_content . refresh ( ) ;
166251 }
167252
168- fn exit ( & self ) {
253+ fn exit ( ) {
169254 nwg:: stop_thread_dispatch ( ) ;
170255 }
171256}
0 commit comments