@@ -425,6 +425,84 @@ struct CaptureRect {
425425 height : f64 ,
426426}
427427
428+ // macOS native screen eyedropper for the styles-bar color picker. WebKit (the
429+ // app's WKWebView) does not implement the web EyeDropper API, so the previewed
430+ // page routes here through the editor. Shows the system color sampler
431+ // (NSColorSampler, macOS 10.15+) and resolves with the picked color as
432+ // "#rrggbb", or "" when the user dismisses the sampler without choosing.
433+ #[ tauri:: command]
434+ async fn pick_screen_color ( window : tauri:: Window ) -> Result < String , String > {
435+ #[ cfg( not( target_os = "macos" ) ) ]
436+ {
437+ let _ = & window;
438+ return Err ( "pick_screen_color is only implemented on macOS" . to_string ( ) ) ;
439+ }
440+
441+ #[ cfg( target_os = "macos" ) ]
442+ {
443+ let ( tx, rx) = tokio:: sync:: oneshot:: channel :: < Result < String , String > > ( ) ;
444+
445+ // with_webview runs the closure on the main (UI) thread, which
446+ // NSColorSampler requires; the webview pointer itself is unused — the
447+ // sampler is a screen-wide system picker independent of the webview.
448+ window. with_webview ( move |_webview| {
449+ unsafe {
450+ let cls = match objc:: runtime:: Class :: get ( "NSColorSampler" ) {
451+ Some ( c) => c,
452+ None => {
453+ let _ = tx. send ( Err (
454+ "NSColorSampler is unavailable on this macOS version" . to_string ( ) ) ) ;
455+ return ;
456+ }
457+ } ;
458+ // `new` returns a +1-retained instance; intentionally never
459+ // released so it outlives the async selection handler.
460+ let sampler: cocoa:: base:: id = msg_send ! [ cls, new] ;
461+
462+ // Wrap the sender so the handler closure is Fn (not FnOnce).
463+ let tx = std:: sync:: Arc :: new ( std:: sync:: Mutex :: new ( Some ( tx) ) ) ;
464+
465+ let handler = block:: ConcreteBlock :: new ( move |color : cocoa:: base:: id | {
466+ let mut guard = tx. lock ( ) . unwrap ( ) ;
467+ let tx = match guard. take ( ) {
468+ Some ( tx) => tx,
469+ None => return ,
470+ } ;
471+ if color. is_null ( ) {
472+ // dismissed without choosing a color
473+ let _ = tx. send ( Ok ( String :: new ( ) ) ) ;
474+ return ;
475+ }
476+ // Normalize to sRGB before reading components — the sampled
477+ // color can arrive in an arbitrary color space.
478+ let srgb_space: cocoa:: base:: id =
479+ msg_send ! [ class!( NSColorSpace ) , sRGBColorSpace] ;
480+ let srgb: cocoa:: base:: id = msg_send ! [ color, colorUsingColorSpace: srgb_space] ;
481+ if srgb. is_null ( ) {
482+ let _ = tx. send ( Ok ( String :: new ( ) ) ) ;
483+ return ;
484+ }
485+ let r: f64 = msg_send ! [ srgb, redComponent] ;
486+ let g: f64 = msg_send ! [ srgb, greenComponent] ;
487+ let b: f64 = msg_send ! [ srgb, blueComponent] ;
488+ let to_byte = |v : f64 | -> u8 {
489+ let n = ( v * 255.0 ) . round ( ) ;
490+ if n < 0.0 { 0 } else if n > 255.0 { 255 } else { n as u8 }
491+ } ;
492+ let hex = format ! ( "#{:02x}{:02x}{:02x}" , to_byte( r) , to_byte( g) , to_byte( b) ) ;
493+ let _ = tx. send ( Ok ( hex) ) ;
494+ } ) ;
495+ let handler = handler. copy ( ) ;
496+ let selection_handler: & block:: Block < ( cocoa:: base:: id , ) , ( ) > = & handler;
497+
498+ let ( ) = msg_send ! [ sampler, showSamplerWithSelectionHandler: selection_handler] ;
499+ }
500+ } ) . map_err ( |e| e. to_string ( ) ) ?;
501+
502+ return rx. await . map_err ( |_| "Color picker channel closed" . to_string ( ) ) ?;
503+ }
504+ }
505+
428506#[ tauri:: command]
429507async fn capture_page ( window : tauri:: Window , rect : Option < CaptureRect > ) -> Result < Vec < u8 > , String > {
430508 #[ cfg( target_os = "linux" ) ]
@@ -883,7 +961,7 @@ fn main() {
883961 put_item, get_item, get_all_items, delete_item,
884962 trust_window_aes_key, remove_trust_window_aes_key,
885963 _get_windows_drives, _rename_path, show_in_folder, move_to_trash, zoom_window,
886- _get_clipboard_files, _open_url_in_browser_win, capture_page] )
964+ _get_clipboard_files, _open_url_in_browser_win, capture_page, pick_screen_color ] )
887965 . setup ( |app| {
888966 init:: init_app ( app) ;
889967 #[ cfg( target_os = "linux" ) ]
0 commit comments