Skip to content

Commit

Permalink
feat(CGDisplay): add displays_with_point and displays_with_rect (#657)
Browse files Browse the repository at this point in the history
* feat(CGDisplay): add displays_with_point and displays_with_rect

* inline to match other fns in this module

* add tests for CGDisplay::displays_with_point and displays_with_rect

* refactor: use kCGErrorSuccess
  • Loading branch information
mattjbray authored Aug 14, 2024
1 parent 6541d9a commit 743b793
Showing 1 changed file with 159 additions and 0 deletions.
159 changes: 159 additions & 0 deletions core-graphics/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use crate::geometry::{CGPoint, CGRect, CGSize};
use crate::image::CGImage;
use core_foundation::base::{CFRetain, TCFType};
use core_foundation::string::{CFString, CFStringRef};
use core_graphics_types::base::kCGErrorSuccess;
use foreign_types::{foreign_type, ForeignType};

pub type CGDirectDisplayID = u32;
Expand Down Expand Up @@ -177,6 +178,90 @@ impl CGDisplay {
CGDisplay::new(kCGNullDirectDisplayID)
}

/// Return the number of online displays with bounds that include the
/// specified point.
#[inline]
pub fn display_count_with_point(point: CGPoint) -> Result<u32, CGError> {
let mut matching_display_count: u32 = 0;
let result = unsafe {
CGGetDisplaysWithPoint(point, 0, ptr::null_mut(), &mut matching_display_count)
};
if result == kCGErrorSuccess {
Ok(matching_display_count)
} else {
Err(result)
}
}

/// Return a list of online displays with bounds that include the specified
/// point.
#[inline]
pub fn displays_with_point(
point: CGPoint,
max_displays: u32,
) -> Result<(Vec<CGDirectDisplayID>, u32), CGError> {
let count = CGDisplay::display_count_with_point(point)?;
let count = u32::max(u32::min(count, max_displays), 1);

let mut matching_display_count: u32 = 0;
let mut displays: Vec<CGDirectDisplayID> = vec![0; count as usize];
let result = unsafe {
CGGetDisplaysWithPoint(
point,
max_displays,
displays.as_mut_ptr(),
&mut matching_display_count,
)
};

if result == kCGErrorSuccess {
Ok((displays, matching_display_count))
} else {
Err(result)
}
}

/// Return the number of online displays with bounds that intersect the
/// specified rectangle.
#[inline]
pub fn display_count_with_rect(rect: CGRect) -> Result<u32, CGError> {
let mut matching_display_count: u32 = 0;
let result =
unsafe { CGGetDisplaysWithRect(rect, 0, ptr::null_mut(), &mut matching_display_count) };
if result == kCGErrorSuccess {
Ok(matching_display_count)
} else {
Err(result)
}
}

/// Return a list of online displays with bounds that intersect the specified rectangle.
#[inline]
pub fn displays_with_rect(
rect: CGRect,
max_displays: u32,
) -> Result<(Vec<CGDirectDisplayID>, u32), CGError> {
let count = CGDisplay::display_count_with_rect(rect)?;
let count = u32::max(u32::min(count, max_displays), 1);

let mut matching_display_count: u32 = 0;
let mut displays: Vec<CGDirectDisplayID> = vec![0; count as usize];
let result = unsafe {
CGGetDisplaysWithRect(
rect,
max_displays,
displays.as_mut_ptr(),
&mut matching_display_count,
)
};

if result == kCGErrorSuccess {
Ok((displays, matching_display_count))
} else {
Err(result)
}
}

/// Returns the bounds of a display in the global display coordinate space.
#[inline]
pub fn bounds(&self) -> CGRect {
Expand Down Expand Up @@ -714,6 +799,12 @@ extern "C" {
active_displays: *mut CGDirectDisplayID,
display_count: *mut u32,
) -> CGError;
pub fn CGGetDisplaysWithPoint(
point: CGPoint,
max_displays: u32,
displays: *mut CGDirectDisplayID,
matching_display_count: *mut u32,
) -> CGError;
pub fn CGGetDisplaysWithRect(
rect: CGRect,
max_displays: u32,
Expand Down Expand Up @@ -839,3 +930,71 @@ extern "C" {
imageOptions: CGWindowImageOption,
) -> crate::sys::CGImageRef;
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_display_count_with_point() {
let result = CGDisplay::display_count_with_point(CGPoint::new(0., 0.));
assert!(result.is_ok());
}

#[test]
fn test_displays_with_point_0() {
let result = CGDisplay::displays_with_point(CGPoint::new(0., 0.), 0);
assert!(result.is_ok());
let (displays, count) = result.unwrap();
assert_eq!(displays.len(), count as usize);
}

#[test]
fn test_displays_with_point_5() {
let result = CGDisplay::displays_with_point(CGPoint::new(0., 0.), 5);
assert!(result.is_ok());
let (displays, count) = result.unwrap();
assert_eq!(displays.len(), count as usize);
}

// NOTE: CGMainDisplayID must be called before CGGetDisplaysWithRect to avoid:
// Assertion failed: (did_initialize), function CGS_REQUIRE_INIT, file CGInitialization.c, line 44.
// See https://github.com/JXA-Cookbook/JXA-Cookbook/issues/27#issuecomment-277517668

#[test]
fn test_display_count_with_rect() {
let _ = CGDisplay::main();

let result = CGDisplay::display_count_with_rect(CGRect::new(
&CGPoint::new(10., 10.),
&CGSize::new(100., 100.),
));
assert!(result.is_ok());
}

#[test]
fn test_displays_with_rect_0() {
let _ = CGDisplay::main();

let result = CGDisplay::displays_with_rect(
CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(100., 100.)),
0,
);
assert!(result.is_ok());
let (displays, count) = result.unwrap();
assert_eq!(displays.len(), count as usize);
}

#[test]
fn test_displays_with_rect_5() {
let _ = CGDisplay::main();

let result = CGDisplay::displays_with_rect(
CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(100., 100.)),
5,
);
assert!(result.is_ok());
let (displays, count) = result.unwrap();
assert_eq!(displays.len(), count as usize);
}
}

0 comments on commit 743b793

Please sign in to comment.