1- use crate :: injector :: { self , WindowInfo } ;
1+ use crate :: native :: { self , WindowInfo } ;
22use eframe:: {
33 Renderer ,
44 egui:: {
5- self , Color32 , ColorImage , Direction , FontData , FontDefinitions , FontFamily , FontId ,
6- IconData , Layout , Margin , RichText , TextStyle , Theme ,
5+ self , Atom , AtomExt , Color32 , ColorImage , Direction , FontData , FontDefinitions , FontFamily ,
6+ FontId , IconData , Image , Layout , Margin , RichText , TextStyle , Theme , Vec2 ,
77 } ,
88} ;
99use image:: { GenericImageView , ImageFormat , ImageReader } ;
10- use std:: sync:: { Arc , Mutex } ;
1110use std:: thread;
11+ use std:: {
12+ collections:: HashMap ,
13+ sync:: { Arc , Mutex } ,
14+ } ;
1215use std:: { io:: Cursor , mem} ;
1316use windows_capture:: {
1417 capture:: { CaptureControl , Context , GraphicsCaptureApiHandler } ,
@@ -21,8 +24,8 @@ use windows_capture::{
2124} ;
2225
2326enum CaptureWorkerEvent {
24- CAPTURE ( Monitor ) ,
25- NONE ,
27+ Capture ( Monitor ) ,
28+ StopCapture ,
2629}
2730
2831struct ScreenCapture {
@@ -81,6 +84,7 @@ struct Gui {
8184 hide_from_taskbar : bool ,
8285 show_desktop_preview : bool ,
8386 active_monitor : usize ,
87+ icon_cache : HashMap < ( u32 , u32 ) , Option < egui:: TextureHandle > > ,
8488}
8589
8690impl Gui {
@@ -95,17 +99,17 @@ impl Gui {
9599 match event {
96100 InjectorWorkerEvent :: UPDATE => {
97101 println ! ( "populating" ) ;
98- let mut w = injector :: get_top_level_windows ( ) ;
102+ let mut w = native :: get_top_level_windows ( ) ;
99103 * windows_copy. lock ( ) . unwrap ( ) = mem:: take ( & mut w) ;
100104 println ! ( "populating done" ) ;
101105 }
102106 InjectorWorkerEvent :: HIDE ( pid, hwnd, show_on_taskbar) => {
103107 println ! ( "wanna hide {:?}" , hwnd) ;
104- injector :: set_window_props_with_pid ( pid, hwnd, true , show_on_taskbar) ;
108+ native :: set_window_props_with_pid ( pid, hwnd, true , show_on_taskbar) ;
105109 }
106110 InjectorWorkerEvent :: SHOW ( pid, hwnd, show_on_taskbar) => {
107111 println ! ( "wanna show {:?}" , hwnd) ;
108- injector :: set_window_props_with_pid ( pid, hwnd, false , show_on_taskbar) ;
112+ native :: set_window_props_with_pid ( pid, hwnd, false , show_on_taskbar) ;
109113 }
110114 }
111115 }
@@ -123,7 +127,7 @@ impl Gui {
123127 }
124128
125129 match event {
126- CaptureWorkerEvent :: CAPTURE ( monitor) => {
130+ CaptureWorkerEvent :: Capture ( monitor) => {
127131 let settings = Settings :: new (
128132 monitor,
129133 CursorCaptureSettings :: Default ,
@@ -139,15 +143,15 @@ impl Gui {
139143 active_capture_control = Some ( capture_control) ;
140144 }
141145 }
142- CaptureWorkerEvent :: NONE => ( ) ,
146+ CaptureWorkerEvent :: StopCapture => ( ) ,
143147 }
144148 }
145149 } ) ;
146150
147151 let monitors = Monitor :: enumerate ( ) . unwrap_or_default ( ) ;
148152
149153 if monitors. len ( ) > 0 {
150- let _ = capture_event_send. send ( CaptureWorkerEvent :: CAPTURE ( monitors[ 0 ] ) ) ;
154+ let _ = capture_event_send. send ( CaptureWorkerEvent :: Capture ( monitors[ 0 ] ) ) ;
151155 }
152156
153157 Gui {
@@ -160,25 +164,46 @@ impl Gui {
160164 capture_tex : None ,
161165 hide_from_taskbar : false ,
162166 active_monitor : 0 ,
167+ icon_cache : HashMap :: new ( ) ,
163168 }
164169 }
165170
171+ fn get_icon < ' a > (
172+ icon_cache : & ' a mut HashMap < ( u32 , u32 ) , Option < egui:: TextureHandle > > ,
173+ ctx : & egui:: Context ,
174+ pid : u32 ,
175+ hwnd : u32 ,
176+ ) -> & ' a Option < egui:: TextureHandle > {
177+ if !icon_cache. contains_key ( & ( pid, hwnd) ) {
178+ let icon = match native:: get_icon ( hwnd) {
179+ Some ( ( width, height, buffer) ) => {
180+ let image = ColorImage :: from_rgba_unmultiplied ( [ width, height] , & buffer) ;
181+ Some ( ctx. load_texture ( "icon" , image, egui:: TextureOptions :: LINEAR ) )
182+ }
183+ None => None ,
184+ } ;
185+
186+ icon_cache. insert ( ( pid, hwnd) , icon) ;
187+ }
188+
189+ icon_cache. get ( & ( pid, hwnd) ) . unwrap ( )
190+ }
191+
166192 fn add_section_header (
167193 ui : & mut egui:: Ui ,
168194 theme : Theme ,
169195 header : impl Into < String > ,
170196 desc : impl Into < String > ,
171197 ) {
172- let ( header_color, desc_color) = if theme == Theme :: Light {
173- (
198+ let ( header_color, desc_color) = match theme {
199+ Theme :: Light => (
174200 Color32 :: from_rgb ( 34 , 34 , 34 ) ,
175201 Color32 :: from_rgb ( 119 , 119 , 119 ) ,
176- )
177- } else {
178- (
202+ ) ,
203+ Theme :: Dark => (
179204 Color32 :: from_rgb ( 242 , 242 , 242 ) ,
180205 Color32 :: from_rgb ( 148 , 148 , 148 ) ,
181- )
206+ ) ,
182207 } ;
183208
184209 ui. label ( RichText :: new ( header) . heading ( ) . color ( header_color) ) ;
@@ -189,25 +214,36 @@ impl Gui {
189214
190215impl eframe:: App for Gui {
191216 fn update ( & mut self , ctx : & egui:: Context , _frame : & mut eframe:: Frame ) {
192- let theme = ctx. theme ( ) ;
193- let ( events, focused) = ctx. input ( |i| ( i. events . clone ( ) , i. focused ) ) ;
217+ // graceful close
218+ if ctx. input ( |i| i. viewport ( ) . close_requested ( ) ) {
219+ let _ = self
220+ . capture_event_send
221+ . send ( CaptureWorkerEvent :: StopCapture ) ;
222+ return ;
223+ }
194224
195- for event in events {
225+ // check if focus has changed
226+ for event in ctx. input ( |i| i. events . clone ( ) ) {
196227 if let egui:: Event :: WindowFocused ( focused) = event {
197228 if focused {
198229 println ! ( "focused" ) ;
199230 self . event_sender . send ( InjectorWorkerEvent :: UPDATE ) . unwrap ( ) ;
200231 if self . show_desktop_preview {
201- let _ = self . capture_event_send . send ( CaptureWorkerEvent :: CAPTURE (
232+ let _ = self . capture_event_send . send ( CaptureWorkerEvent :: Capture (
202233 self . monitors [ self . active_monitor ] ,
203234 ) ) ;
204235 }
205236 } else {
206- let _ = self . capture_event_send . send ( CaptureWorkerEvent :: NONE ) ;
237+ let _ = self
238+ . capture_event_send
239+ . send ( CaptureWorkerEvent :: StopCapture ) ;
207240 }
208241 }
209242 }
210243
244+ let theme = ctx. theme ( ) ;
245+ let focused = ctx. input ( |i| i. focused ) ;
246+
211247 egui:: CentralPanel :: default ( )
212248 . frame ( egui:: Frame :: central_panel ( & ctx. style ( ) ) . inner_margin ( Margin :: same ( 14 ) ) )
213249 . show ( ctx, |ui| {
@@ -259,7 +295,7 @@ impl eframe::App for Gui {
259295 self . active_monitor = i;
260296 let _ = self
261297 . capture_event_send
262- . send ( CaptureWorkerEvent :: CAPTURE ( * monitor) ) ;
298+ . send ( CaptureWorkerEvent :: Capture ( * monitor) ) ;
263299 }
264300 }
265301 } ) ;
@@ -277,8 +313,29 @@ impl eframe::App for Gui {
277313
278314 for window_info in self . windows . lock ( ) . unwrap ( ) . iter_mut ( ) {
279315 ui. style_mut ( ) . wrap_mode = Some ( egui:: TextWrapMode :: Truncate ) ; // elide with "…"
316+
317+ let icon_atom = if let Some ( texture) = Gui :: get_icon (
318+ & mut self . icon_cache ,
319+ ctx,
320+ window_info. pid ,
321+ window_info. hwnd ,
322+ ) {
323+ Image :: from_texture ( texture)
324+ . max_height ( 16.0 )
325+ . atom_max_width ( 16.0 )
326+ } else {
327+ Atom :: grow ( ) . atom_size ( Vec2 :: new ( 16.0 , 0.0 ) )
328+ } ;
329+
330+ let checkbox_label = (
331+ Atom :: grow ( ) . atom_size ( Vec2 :: new ( 0.0 , 0.0 ) ) ,
332+ icon_atom,
333+ Atom :: grow ( ) . atom_size ( Vec2 :: new ( 0.0 , 0.0 ) ) ,
334+ & window_info. title ,
335+ ) ;
336+
280337 let checkbox_response =
281- ui. checkbox ( & mut window_info. hidden , & window_info . title ) ;
338+ ui. checkbox ( & mut window_info. hidden , checkbox_label ) ;
282339 if checkbox_response. changed ( ) {
283340 let event = if window_info. hidden {
284341 InjectorWorkerEvent :: HIDE (
@@ -295,6 +352,7 @@ impl eframe::App for Gui {
295352 } ;
296353 self . event_sender . send ( event) . unwrap ( ) ;
297354 }
355+ ui. add_space ( 2.0 ) ;
298356 }
299357 ui. add_space ( 10.0 ) ;
300358 ui. collapsing ( "Advanced settings" , |ui| {
@@ -303,10 +361,10 @@ impl eframe::App for Gui {
303361 ui. checkbox ( & mut self . show_desktop_preview , "Show desktop preview" ) ;
304362 if preview_checkbox_response. changed ( ) {
305363 let event = if self . show_desktop_preview {
306- CaptureWorkerEvent :: CAPTURE ( self . monitors [ self . active_monitor ] )
364+ CaptureWorkerEvent :: Capture ( self . monitors [ self . active_monitor ] )
307365 } else {
308366 self . capture_tex = None ;
309- CaptureWorkerEvent :: NONE
367+ CaptureWorkerEvent :: StopCapture
310368 } ;
311369 self . capture_event_send . send ( event) . unwrap ( ) ;
312370 }
0 commit comments