@@ -20,6 +20,7 @@ pub use crate::geometry::{CGPoint, CGRect, CGSize};
2020use crate :: image:: CGImage ;
2121use core_foundation:: base:: { CFRetain , TCFType } ;
2222use core_foundation:: string:: { CFString , CFStringRef } ;
23+ use core_graphics_types:: base:: kCGErrorSuccess;
2324use foreign_types:: { foreign_type, ForeignType } ;
2425
2526pub type CGDirectDisplayID = u32 ;
@@ -177,6 +178,90 @@ impl CGDisplay {
177178 CGDisplay :: new ( kCGNullDirectDisplayID)
178179 }
179180
181+ /// Return the number of online displays with bounds that include the
182+ /// specified point.
183+ #[ inline]
184+ pub fn display_count_with_point ( point : CGPoint ) -> Result < u32 , CGError > {
185+ let mut matching_display_count: u32 = 0 ;
186+ let result = unsafe {
187+ CGGetDisplaysWithPoint ( point, 0 , ptr:: null_mut ( ) , & mut matching_display_count)
188+ } ;
189+ if result == kCGErrorSuccess {
190+ Ok ( matching_display_count)
191+ } else {
192+ Err ( result)
193+ }
194+ }
195+
196+ /// Return a list of online displays with bounds that include the specified
197+ /// point.
198+ #[ inline]
199+ pub fn displays_with_point (
200+ point : CGPoint ,
201+ max_displays : u32 ,
202+ ) -> Result < ( Vec < CGDirectDisplayID > , u32 ) , CGError > {
203+ let count = CGDisplay :: display_count_with_point ( point) ?;
204+ let count = u32:: max ( u32:: min ( count, max_displays) , 1 ) ;
205+
206+ let mut matching_display_count: u32 = 0 ;
207+ let mut displays: Vec < CGDirectDisplayID > = vec ! [ 0 ; count as usize ] ;
208+ let result = unsafe {
209+ CGGetDisplaysWithPoint (
210+ point,
211+ max_displays,
212+ displays. as_mut_ptr ( ) ,
213+ & mut matching_display_count,
214+ )
215+ } ;
216+
217+ if result == kCGErrorSuccess {
218+ Ok ( ( displays, matching_display_count) )
219+ } else {
220+ Err ( result)
221+ }
222+ }
223+
224+ /// Return the number of online displays with bounds that intersect the
225+ /// specified rectangle.
226+ #[ inline]
227+ pub fn display_count_with_rect ( rect : CGRect ) -> Result < u32 , CGError > {
228+ let mut matching_display_count: u32 = 0 ;
229+ let result =
230+ unsafe { CGGetDisplaysWithRect ( rect, 0 , ptr:: null_mut ( ) , & mut matching_display_count) } ;
231+ if result == kCGErrorSuccess {
232+ Ok ( matching_display_count)
233+ } else {
234+ Err ( result)
235+ }
236+ }
237+
238+ /// Return a list of online displays with bounds that intersect the specified rectangle.
239+ #[ inline]
240+ pub fn displays_with_rect (
241+ rect : CGRect ,
242+ max_displays : u32 ,
243+ ) -> Result < ( Vec < CGDirectDisplayID > , u32 ) , CGError > {
244+ let count = CGDisplay :: display_count_with_rect ( rect) ?;
245+ let count = u32:: max ( u32:: min ( count, max_displays) , 1 ) ;
246+
247+ let mut matching_display_count: u32 = 0 ;
248+ let mut displays: Vec < CGDirectDisplayID > = vec ! [ 0 ; count as usize ] ;
249+ let result = unsafe {
250+ CGGetDisplaysWithRect (
251+ rect,
252+ max_displays,
253+ displays. as_mut_ptr ( ) ,
254+ & mut matching_display_count,
255+ )
256+ } ;
257+
258+ if result == kCGErrorSuccess {
259+ Ok ( ( displays, matching_display_count) )
260+ } else {
261+ Err ( result)
262+ }
263+ }
264+
180265 /// Returns the bounds of a display in the global display coordinate space.
181266 #[ inline]
182267 pub fn bounds ( & self ) -> CGRect {
@@ -714,6 +799,12 @@ extern "C" {
714799 active_displays : * mut CGDirectDisplayID ,
715800 display_count : * mut u32 ,
716801 ) -> CGError ;
802+ pub fn CGGetDisplaysWithPoint (
803+ point : CGPoint ,
804+ max_displays : u32 ,
805+ displays : * mut CGDirectDisplayID ,
806+ matching_display_count : * mut u32 ,
807+ ) -> CGError ;
717808 pub fn CGGetDisplaysWithRect (
718809 rect : CGRect ,
719810 max_displays : u32 ,
@@ -839,3 +930,71 @@ extern "C" {
839930 imageOptions : CGWindowImageOption ,
840931 ) -> crate :: sys:: CGImageRef ;
841932}
933+
934+ #[ cfg( test) ]
935+ mod test {
936+ use super :: * ;
937+
938+ #[ test]
939+ fn test_display_count_with_point ( ) {
940+ let result = CGDisplay :: display_count_with_point ( CGPoint :: new ( 0. , 0. ) ) ;
941+ assert ! ( result. is_ok( ) ) ;
942+ }
943+
944+ #[ test]
945+ fn test_displays_with_point_0 ( ) {
946+ let result = CGDisplay :: displays_with_point ( CGPoint :: new ( 0. , 0. ) , 0 ) ;
947+ assert ! ( result. is_ok( ) ) ;
948+ let ( displays, count) = result. unwrap ( ) ;
949+ assert_eq ! ( displays. len( ) , count as usize ) ;
950+ }
951+
952+ #[ test]
953+ fn test_displays_with_point_5 ( ) {
954+ let result = CGDisplay :: displays_with_point ( CGPoint :: new ( 0. , 0. ) , 5 ) ;
955+ assert ! ( result. is_ok( ) ) ;
956+ let ( displays, count) = result. unwrap ( ) ;
957+ assert_eq ! ( displays. len( ) , count as usize ) ;
958+ }
959+
960+ // NOTE: CGMainDisplayID must be called before CGGetDisplaysWithRect to avoid:
961+ // Assertion failed: (did_initialize), function CGS_REQUIRE_INIT, file CGInitialization.c, line 44.
962+ // See https://github.com/JXA-Cookbook/JXA-Cookbook/issues/27#issuecomment-277517668
963+
964+ #[ test]
965+ fn test_display_count_with_rect ( ) {
966+ let _ = CGDisplay :: main ( ) ;
967+
968+ let result = CGDisplay :: display_count_with_rect ( CGRect :: new (
969+ & CGPoint :: new ( 10. , 10. ) ,
970+ & CGSize :: new ( 100. , 100. ) ,
971+ ) ) ;
972+ assert ! ( result. is_ok( ) ) ;
973+ }
974+
975+ #[ test]
976+ fn test_displays_with_rect_0 ( ) {
977+ let _ = CGDisplay :: main ( ) ;
978+
979+ let result = CGDisplay :: displays_with_rect (
980+ CGRect :: new ( & CGPoint :: new ( 0. , 0. ) , & CGSize :: new ( 100. , 100. ) ) ,
981+ 0 ,
982+ ) ;
983+ assert ! ( result. is_ok( ) ) ;
984+ let ( displays, count) = result. unwrap ( ) ;
985+ assert_eq ! ( displays. len( ) , count as usize ) ;
986+ }
987+
988+ #[ test]
989+ fn test_displays_with_rect_5 ( ) {
990+ let _ = CGDisplay :: main ( ) ;
991+
992+ let result = CGDisplay :: displays_with_rect (
993+ CGRect :: new ( & CGPoint :: new ( 0. , 0. ) , & CGSize :: new ( 100. , 100. ) ) ,
994+ 5 ,
995+ ) ;
996+ assert ! ( result. is_ok( ) ) ;
997+ let ( displays, count) = result. unwrap ( ) ;
998+ assert_eq ! ( displays. len( ) , count as usize ) ;
999+ }
1000+ }
0 commit comments