use crate::compat::Vec;
use crate::platform::types::Display;
#[cfg(target_env = "ohos")]
mod sys {
use super::Display;
use crate::compat::Vec;
use crate::core::Rect;
use crate::platform::types::DisplayId;
use core::ffi::{c_char, c_void};
const DISPLAY_MANAGER_OK: i32 = 0;
const DISPLAY_NAME_LENGTH: usize = 32;
#[repr(C)]
struct NativeDisplayManager_DisplayInfo {
id: u32,
name: [c_char; DISPLAY_NAME_LENGTH + 1],
is_alive: u8,
width: i32,
height: i32,
physical_width: i32,
physical_height: i32,
refresh_rate: u32,
available_width: u32,
available_height: u32,
density_dpi: f32,
density_pixels: f32,
scaled_density: f32,
x_dpi: f32,
y_dpi: f32,
rotation: i32,
state: i32,
orientation: i32,
hdr_format: *mut c_void,
color_space: *mut c_void,
}
#[repr(C)]
struct NativeDisplayManager_DisplaysInfo {
displays_length: u32,
displays_info: *mut NativeDisplayManager_DisplayInfo,
}
extern "C" {
fn OH_NativeDisplayManager_CreateAllDisplays(
all_displays: *mut *mut NativeDisplayManager_DisplaysInfo,
) -> i32;
fn OH_NativeDisplayManager_DestroyAllDisplays(
all_displays: *mut NativeDisplayManager_DisplaysInfo,
);
fn OH_NativeDisplayManager_GetDisplayPosition(
display_id: u64,
x: *mut i32,
y: *mut i32,
) -> i32;
fn OH_NativeDisplayManager_GetDefaultDisplayId(display_id: *mut u64) -> i32;
}
pub(super) fn displays() -> Vec<Display> {
let mut all: *mut NativeDisplayManager_DisplaysInfo = core::ptr::null_mut();
let status = unsafe { OH_NativeDisplayManager_CreateAllDisplays(&mut all) };
if status != DISPLAY_MANAGER_OK || all.is_null() {
log::warn!(
"[harmony displays] OH_NativeDisplayManager_CreateAllDisplays answered {status}"
);
return Vec::new();
}
let mut default_id = 0u64;
let has_default = unsafe { OH_NativeDisplayManager_GetDefaultDisplayId(&mut default_id) }
== DISPLAY_MANAGER_OK;
let mut out = Vec::new();
let count = unsafe { (*all).displays_length as usize };
let first = unsafe { (*all).displays_info };
if !first.is_null() {
for index in 0..count {
let info = unsafe { &*first.add(index) };
if info.is_alive == 0 {
continue;
}
let width = info.width.max(0) as u32;
let height = info.height.max(0) as u32;
let mut x = 0i32;
let mut y = 0i32;
let positioned = unsafe {
OH_NativeDisplayManager_GetDisplayPosition(info.id as u64, &mut x, &mut y)
} == DISPLAY_MANAGER_OK;
let origin_x = if positioned { x } else { 0 };
let origin_y = if positioned { y } else { 0 };
let work_width =
if info.available_width > 0 { info.available_width } else { width };
let work_height =
if info.available_height > 0 { info.available_height } else { height };
out.push(Display {
id: DisplayId::new(info.id as u64),
bounds: Rect::new(origin_x, origin_y, width, height),
work_area: Rect::new(origin_x, origin_y, work_width, work_height),
scale: if info.density_pixels > 0.0 { info.density_pixels } else { 1.0 },
is_primary: if has_default { info.id as u64 == default_id } else { index == 0 },
});
}
}
unsafe { OH_NativeDisplayManager_DestroyAllDisplays(all) };
out
}
pub(super) fn generation() -> u64 {
const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
let displays = displays();
if displays.is_empty() {
return 0;
}
let mut hash = FNV_OFFSET;
for display in displays {
for part in [
display.id.get(),
display.bounds.x as i64 as u64,
display.bounds.y as i64 as u64,
display.bounds.width as u64,
display.bounds.height as u64,
display.work_area.x as i64 as u64,
display.work_area.y as i64 as u64,
display.work_area.width as u64,
display.work_area.height as u64,
display.scale.to_bits() as u64,
display.is_primary as u64,
] {
hash ^= part;
hash = hash.wrapping_mul(FNV_PRIME);
}
}
hash
}
}
#[cfg(not(target_env = "ohos"))]
mod sys {
use super::Display;
use crate::compat::Vec;
pub(super) fn displays() -> Vec<Display> {
Vec::new()
}
pub(super) fn generation() -> u64 {
0
}
}
pub(crate) fn displays() -> Vec<Display> {
sys::displays()
}
pub(crate) fn generation() -> u64 {
sys::generation()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_host_without_the_display_manager_reports_no_displays() {
if cfg!(target_env = "ohos") {
return;
}
assert!(displays().is_empty());
assert_eq!(generation(), 0);
}
}