mac resolution
Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
parent
18a66749a1
commit
5b8e51d6b9
@ -40,3 +40,114 @@ extern "C" float BackingScaleFactor() {
|
|||||||
if (s) return [s backingScaleFactor];
|
if (s) return [s backingScaleFactor];
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/jhford/screenresolution/blob/master/cg_utils.c
|
||||||
|
// https://github.com/jdoupe/screenres/blob/master/setgetscreen.m
|
||||||
|
|
||||||
|
extern "C" bool MacGetModeNum(CGDirectDisplayID display, uint32_t *numModes) {
|
||||||
|
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
|
||||||
|
if (allModes == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*numModes = CFArrayGetCount(allModes);
|
||||||
|
CFRelease(allModes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool MacGetModes(CGDirectDisplayID display, uint32_t *widths, uint32_t *heights, uint32_t max, uint32_t *numModes) {
|
||||||
|
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
|
||||||
|
if (allModes == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*numModes = CFArrayGetCount(allModes);
|
||||||
|
for (int i = 0; i < *numModes && i < max; i++) {
|
||||||
|
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
|
||||||
|
widths[i] = (uint32_t)CGDisplayModeGetWidth(mode);
|
||||||
|
heights[i] = (uint32_t)CGDisplayModeGetHeight(mode);
|
||||||
|
}
|
||||||
|
CFRelease(allModes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool MacGetMode(CGDirectDisplayID display, uint32_t *width, uint32_t *height) {
|
||||||
|
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
|
||||||
|
if (mode == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*width = (uint32_t)CGDisplayModeGetWidth(mode);
|
||||||
|
*height = (uint32_t)CGDisplayModeGetHeight(mode);
|
||||||
|
CGDisplayModeRelease(mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bitDepth(CGDisplayModeRef mode) {
|
||||||
|
size_t depth = 0;
|
||||||
|
CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
|
||||||
|
// my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels
|
||||||
|
// are made up and possibly non-sensical
|
||||||
|
if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO32BitFloatPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 96;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 64;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO16BitFloatPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 48;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 32;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 30;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 16;
|
||||||
|
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive)) {
|
||||||
|
depth = 8;
|
||||||
|
}
|
||||||
|
CFRelease(pixelEncoding);
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) {
|
||||||
|
CGError rc;
|
||||||
|
CGDisplayConfigRef config;
|
||||||
|
rc = CGBeginDisplayConfiguration(&config);
|
||||||
|
if (rc != kCGErrorSuccess) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rc = CGConfigureDisplayWithDisplayMode(config, display, mode, NULL);
|
||||||
|
if (rc != kCGErrorSuccess) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rc = CGCompleteDisplayConfiguration(config, kCGConfigureForSession);
|
||||||
|
if (rc != kCGErrorSuccess) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" bool MacSetMode(CGDirectDisplayID display, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display);
|
||||||
|
if (currentMode == NULL) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
|
||||||
|
if (allModes == NULL) {
|
||||||
|
CGDisplayModeRelease(currentMode);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int numModes = CFArrayGetCount(allModes);
|
||||||
|
CGDisplayModeRef bestMode = NULL;
|
||||||
|
for (int i = 0; i < numModes; i++) {
|
||||||
|
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
|
||||||
|
if (width == CGDisplayModeGetWidth(mode) &&
|
||||||
|
height == CGDisplayModeGetHeight(mode) &&
|
||||||
|
bitDepth(currentMode) == bitDepth(mode) &&
|
||||||
|
CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode)) {
|
||||||
|
ret = setDisplayToMode(display, mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CGDisplayModeRelease(currentMode);
|
||||||
|
CFRelease(allModes);
|
||||||
|
return ret;
|
||||||
|
}
|
@ -17,7 +17,7 @@ use core_graphics::{
|
|||||||
display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo},
|
display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo},
|
||||||
window::{kCGWindowName, kCGWindowOwnerPID},
|
window::{kCGWindowName, kCGWindowOwnerPID},
|
||||||
};
|
};
|
||||||
use hbb_common::{allow_err, bail, log};
|
use hbb_common::{allow_err, anyhow::anyhow, bail, log, message_proto::Resolution};
|
||||||
use include_dir::{include_dir, Dir};
|
use include_dir::{include_dir, Dir};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
use scrap::{libc::c_void, quartz::ffi::*};
|
use scrap::{libc::c_void, quartz::ffi::*};
|
||||||
@ -34,6 +34,16 @@ extern "C" {
|
|||||||
static kAXTrustedCheckOptionPrompt: CFStringRef;
|
static kAXTrustedCheckOptionPrompt: CFStringRef;
|
||||||
fn AXIsProcessTrustedWithOptions(options: CFDictionaryRef) -> BOOL;
|
fn AXIsProcessTrustedWithOptions(options: CFDictionaryRef) -> BOOL;
|
||||||
fn InputMonitoringAuthStatus(_: BOOL) -> BOOL;
|
fn InputMonitoringAuthStatus(_: BOOL) -> BOOL;
|
||||||
|
fn MacGetModeNum(display: u32, numModes: *mut u32) -> BOOL;
|
||||||
|
fn MacGetModes(
|
||||||
|
display: u32,
|
||||||
|
widths: *mut u32,
|
||||||
|
heights: *mut u32,
|
||||||
|
max: u32,
|
||||||
|
numModes: *mut u32,
|
||||||
|
) -> BOOL;
|
||||||
|
fn MacGetMode(display: u32, width: *mut u32, height: *mut u32) -> BOOL;
|
||||||
|
fn MacSetMode(display: u32, width: u32, height: u32) -> BOOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_process_trusted(prompt: bool) -> bool {
|
pub fn is_process_trusted(prompt: bool) -> bool {
|
||||||
@ -594,3 +604,64 @@ pub fn handle_application_should_open_untitled_file() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolutions(name: &str) -> Vec<Resolution> {
|
||||||
|
let mut v = vec![];
|
||||||
|
if let Ok(display) = name.parse::<u32>() {
|
||||||
|
let mut num = 0;
|
||||||
|
unsafe {
|
||||||
|
if YES == MacGetModeNum(display, &mut num) {
|
||||||
|
let (mut widths, mut heights) = (vec![0; num as _], vec![0; num as _]);
|
||||||
|
let mut realNum = 0;
|
||||||
|
if YES
|
||||||
|
== MacGetModes(
|
||||||
|
display,
|
||||||
|
widths.as_mut_ptr(),
|
||||||
|
heights.as_mut_ptr(),
|
||||||
|
num,
|
||||||
|
&mut realNum,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if realNum <= num {
|
||||||
|
for i in 0..realNum {
|
||||||
|
let resolution = Resolution {
|
||||||
|
width: widths[i as usize] as _,
|
||||||
|
height: heights[i as usize] as _,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
if !v.contains(&resolution) {
|
||||||
|
v.push(resolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_resolution(name: &str) -> ResultType<Resolution> {
|
||||||
|
let display = name.parse::<u32>().map_err(|e| anyhow!(e))?;
|
||||||
|
unsafe {
|
||||||
|
let (mut width, mut height) = (0, 0);
|
||||||
|
if NO == MacGetMode(display, &mut width, &mut height) {
|
||||||
|
bail!("MacGetMode failed");
|
||||||
|
}
|
||||||
|
Ok(Resolution {
|
||||||
|
width: width as _,
|
||||||
|
height: height as _,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<()> {
|
||||||
|
let display = name.parse::<u32>().map_err(|e| anyhow!(e))?;
|
||||||
|
unsafe {
|
||||||
|
if NO == MacSetMode(display, width as _, height as _) {
|
||||||
|
bail!("MacSetMode failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user