Auto merge of #268 - pcwalton:additions-0.17.3, r=jdm
CFArray, Core Animation, and Quartz Window Services additions Here's your regularly scheduled set of additions to the Core Foundation bindings. I needed these for the testing infrastructure I'm developing for https://github.com/pcwalton/planeshift. r? @jdm <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/core-foundation-rs/268) <!-- Reviewable:end -->
This commit is contained in:
+261
-3
@@ -7,13 +7,16 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use core_foundation::array::{CFArray, CFArrayRef};
|
||||
use core_foundation::base::{CFTypeRef, TCFType};
|
||||
use core_foundation::base::{CFType, CFTypeRef, TCFType};
|
||||
use core_foundation::date::CFTimeInterval;
|
||||
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
|
||||
use core_foundation::string::{CFString, CFStringRef};
|
||||
use core_graphics::base::CGFloat;
|
||||
use core_graphics::color::{CGColor, SysCGColorRef};
|
||||
use core_graphics::color_space::CGColorSpace;
|
||||
use core_graphics::context::CGContext;
|
||||
use core_graphics::geometry::{CGAffineTransform, CGPoint, CGRect, CGSize};
|
||||
use core_graphics::path::{CGPath, SysCGPathRef};
|
||||
@@ -21,9 +24,18 @@ use foreign_types::ForeignType;
|
||||
use std::ops::Mul;
|
||||
use std::ptr;
|
||||
|
||||
use appkit::CGLContextObj;
|
||||
use base::{BOOL, id, nil, YES};
|
||||
use foundation::NSUInteger;
|
||||
|
||||
// CABase.h
|
||||
|
||||
pub fn current_media_time() -> CFTimeInterval {
|
||||
unsafe {
|
||||
CACurrentMediaTime()
|
||||
}
|
||||
}
|
||||
|
||||
// CALayer.h
|
||||
|
||||
pub struct CALayer(id);
|
||||
@@ -1356,11 +1368,169 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
// CARenderer.h
|
||||
|
||||
pub struct CARenderer(id);
|
||||
|
||||
unsafe impl Send for CARenderer {}
|
||||
unsafe impl Sync for CARenderer {}
|
||||
|
||||
impl Clone for CARenderer {
|
||||
#[inline]
|
||||
fn clone(&self) -> CARenderer {
|
||||
unsafe {
|
||||
CARenderer(msg_send![self.id(), retain])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CARenderer {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
msg_send![self.id(), release]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CARenderer {
|
||||
#[inline]
|
||||
pub fn id(&self) -> id {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_cgl_context(context: CGLContextObj, color_space: Option<CGColorSpace>)
|
||||
-> CARenderer {
|
||||
let mut pairs: Vec<(CFString, CFType)> = vec![];
|
||||
if let Some(color_space) = color_space {
|
||||
pairs.push((CFString::wrap_under_get_rule(kCARendererColorSpace),
|
||||
CFType::wrap_under_get_rule(color_space.as_ptr() as *const _ as *const _)))
|
||||
}
|
||||
|
||||
let options: CFDictionary<CFString, CFType> = CFDictionary::from_CFType_pairs(&pairs);
|
||||
|
||||
let renderer: id =
|
||||
msg_send![class!(CARenderer), rendererWithCGLContext:context
|
||||
options:options.as_CFTypeRef()];
|
||||
debug_assert!(renderer != nil);
|
||||
CARenderer(renderer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_metal_texture(metal_texture: id,
|
||||
metal_command_queue: id,
|
||||
color_space: Option<CGColorSpace>)
|
||||
-> CARenderer {
|
||||
let mut pairs: Vec<(CFString, CFType)> = vec![
|
||||
(CFString::wrap_under_get_rule(kCARendererMetalCommandQueue),
|
||||
CFType::wrap_under_get_rule(metal_command_queue as *const _ as *const _)),
|
||||
];
|
||||
if let Some(color_space) = color_space {
|
||||
pairs.push((CFString::wrap_under_get_rule(kCARendererColorSpace),
|
||||
CFType::wrap_under_get_rule(color_space.as_ptr() as *const _ as *const _)))
|
||||
}
|
||||
|
||||
let options: CFDictionary<CFString, CFType> = CFDictionary::from_CFType_pairs(&pairs);
|
||||
|
||||
let renderer: id =
|
||||
msg_send![class!(CARenderer), rendererWithMTLTexture:metal_texture
|
||||
options:options.as_CFTypeRef()];
|
||||
debug_assert!(renderer != nil);
|
||||
CARenderer(renderer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layer(&self) -> Option<CALayer> {
|
||||
unsafe {
|
||||
let layer: id = msg_send![self.id(), layer];
|
||||
if layer.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CALayer(layer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_layer(&self, layer: Option<CALayer>) {
|
||||
unsafe {
|
||||
let layer = match layer {
|
||||
Some(ref layer) => layer.id(),
|
||||
None => nil,
|
||||
};
|
||||
msg_send![self.id(), setLayer:layer];
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bounds(&self) -> CGRect {
|
||||
unsafe {
|
||||
msg_send![self.id(), bounds]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_bounds(&self, bounds: CGRect) {
|
||||
unsafe {
|
||||
msg_send![self.id(), setBounds:bounds]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_frame_at(&self, time: CFTimeInterval, timestamp: Option<&CVTimeStamp>) {
|
||||
unsafe {
|
||||
msg_send![self.id(), beginFrameAtTime:time timeStamp:timestamp]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn update_bounds(&self) -> CGRect {
|
||||
unsafe {
|
||||
msg_send![self.id(), updateBounds]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_update_rect(&self, rect: CGRect) {
|
||||
unsafe {
|
||||
msg_send![self.id(), addUpdateRect:rect]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn render(&self) {
|
||||
unsafe {
|
||||
msg_send![self.id(), render]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_frame_time(&self) -> CFTimeInterval {
|
||||
unsafe {
|
||||
msg_send![self.id(), nextFrameTime]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_frame(&self) {
|
||||
unsafe {
|
||||
msg_send![self.id(), endFrame]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_destination(&self, metal_texture: id) {
|
||||
msg_send![self.id(), setDestination:metal_texture]
|
||||
}
|
||||
}
|
||||
|
||||
// CATransaction.h
|
||||
|
||||
// You can't actually construct any `CATransaction` objects, so that class is
|
||||
// really just a module.
|
||||
pub mod transaction {
|
||||
use block::{Block, ConcreteBlock, IntoConcreteBlock, RcBlock};
|
||||
use core_foundation::date::CFTimeInterval;
|
||||
use core_foundation::string::CFString;
|
||||
|
||||
@@ -1442,8 +1612,27 @@ pub mod transaction {
|
||||
}
|
||||
}
|
||||
|
||||
// Omitted: `completionBlock`; depends on blocks.
|
||||
// Omitted: `setCompletionBlock:`; depends on blocks.
|
||||
#[inline]
|
||||
pub fn completion_block() -> Option<RcBlock<(), ()>> {
|
||||
unsafe {
|
||||
let completion_block: *mut Block<(), ()> =
|
||||
msg_send![class!(CATransaction), completionBlock];
|
||||
if completion_block.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(RcBlock::new(completion_block))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_completion_block<F>(block: ConcreteBlock<(), (), F>)
|
||||
where F: 'static + IntoConcreteBlock<(), Ret = ()> {
|
||||
unsafe {
|
||||
let block = block.copy();
|
||||
msg_send![class!(CATransaction), setCompletionBlock:&*block]
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value_for_key(key: &str) -> id {
|
||||
@@ -1581,6 +1770,11 @@ impl CATransform3D {
|
||||
|
||||
#[link(name = "QuartzCore", kind = "framework")]
|
||||
extern {
|
||||
static kCARendererColorSpace: CFStringRef;
|
||||
static kCARendererMetalCommandQueue: CFStringRef;
|
||||
|
||||
fn CACurrentMediaTime() -> CFTimeInterval;
|
||||
|
||||
fn CATransform3DIsIdentity(t: CATransform3D) -> bool;
|
||||
fn CATransform3DEqualToTransform(a: CATransform3D, b: CATransform3D) -> bool;
|
||||
fn CATransform3DMakeTranslation(tx: CGFloat, ty: CGFloat, tz: CGFloat) -> CATransform3D;
|
||||
@@ -1599,3 +1793,67 @@ extern {
|
||||
fn CATransform3DIsAffine(t: CATransform3D) -> bool;
|
||||
fn CATransform3DGetAffineTransform(t: CATransform3D) -> CGAffineTransform;
|
||||
}
|
||||
|
||||
// Miscellaneous structures in other frameworks.
|
||||
//
|
||||
// These should be moved elsewhere eventually.
|
||||
|
||||
// CoreVideo/CVBase.h
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CVTimeStamp {
|
||||
pub version: u32,
|
||||
pub videoTimeScale: i32,
|
||||
pub videoTime: i64,
|
||||
pub hostTime: u64,
|
||||
pub rateScalar: f64,
|
||||
pub videoRefreshPeriod: i64,
|
||||
pub smpteTime: CVSMPTETime,
|
||||
pub flags: u64,
|
||||
pub reserved: u64,
|
||||
}
|
||||
|
||||
pub type CVTimeStampFlags = u64;
|
||||
|
||||
pub const kCVTimeStampVideoTimeValid: CVTimeStampFlags = 1 << 0;
|
||||
pub const kCVTimeStampHostTimeValid: CVTimeStampFlags = 1 << 1;
|
||||
pub const kCVTimeStampSMPTETimeValid: CVTimeStampFlags = 1 << 2;
|
||||
pub const kCVTimeStampVideoRefreshPeriodValid: CVTimeStampFlags = 1 << 3;
|
||||
pub const kCVTimeStampRateScalarValid: CVTimeStampFlags = 1 << 4;
|
||||
pub const kCVTimeStampTopField: CVTimeStampFlags = 1 << 16;
|
||||
pub const kCVTimeStampBottomField: CVTimeStampFlags = 1 << 17;
|
||||
pub const kCVTimeStampVideoHostTimeValid: CVTimeStampFlags =
|
||||
kCVTimeStampVideoTimeValid | kCVTimeStampHostTimeValid;
|
||||
pub const kCVTimeStampIsInterlaced: CVTimeStampFlags =
|
||||
kCVTimeStampTopField | kCVTimeStampBottomField;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CVSMPTETime {
|
||||
pub subframes: i16,
|
||||
pub subframeDivisor: i16,
|
||||
pub counter: u32,
|
||||
pub time_type: u32,
|
||||
pub flags: u32,
|
||||
pub hours: i16,
|
||||
pub minutes: i16,
|
||||
pub seconds: i16,
|
||||
pub frames: i16,
|
||||
}
|
||||
|
||||
pub type CVSMPTETimeType = u32;
|
||||
|
||||
pub const kCVSMPTETimeType24: CVSMPTETimeType = 0;
|
||||
pub const kCVSMPTETimeType25: CVSMPTETimeType = 1;
|
||||
pub const kCVSMPTETimeType30Drop: CVSMPTETimeType = 2;
|
||||
pub const kCVSMPTETimeType30: CVSMPTETimeType = 3;
|
||||
pub const kCVSMPTETimeType2997: CVSMPTETimeType = 4;
|
||||
pub const kCVSMPTETimeType2997Drop: CVSMPTETimeType = 5;
|
||||
pub const kCVSMPTETimeType60: CVSMPTETimeType = 6;
|
||||
pub const kCVSMPTETimeType5994: CVSMPTETimeType = 7;
|
||||
|
||||
pub type CVSMPTETimeFlags = u32;
|
||||
|
||||
pub const kCVSMPTETimeValid: CVSMPTETimeFlags = 1 << 0;
|
||||
pub const kCVSMPTETimeRunning: CVSMPTETimeFlags = 1 << 1;
|
||||
|
||||
@@ -15,6 +15,7 @@ use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault};
|
||||
use std::mem;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use ConcreteCFType;
|
||||
|
||||
use base::{CFIndexConvertible, TCFType, CFRange};
|
||||
@@ -61,6 +62,17 @@ impl_CFTypeDescription!(CFArray);
|
||||
unsafe impl ConcreteCFType for CFArray<*const c_void> {}
|
||||
|
||||
impl<T> CFArray<T> {
|
||||
/// Creates a new `CFArray` with the given elements, which must implement `Copy`.
|
||||
pub fn from_copyable(elems: &[T]) -> CFArray<T> where T: Copy {
|
||||
unsafe {
|
||||
let array_ref = CFArrayCreate(kCFAllocatorDefault,
|
||||
mem::transmute(elems.as_ptr()),
|
||||
elems.len().to_CFIndex(),
|
||||
ptr::null());
|
||||
TCFType::wrap_under_create_rule(array_ref)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `CFArray` with the given elements, which must be `CFType` objects.
|
||||
pub fn from_CFTypes(elems: &[T]) -> CFArray<T> where T: TCFType {
|
||||
unsafe {
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "core-graphics"
|
||||
description = "Bindings to Core Graphics for OS X"
|
||||
homepage = "https://github.com/servo/core-graphics-rs"
|
||||
repository = "https://github.com/servo/core-foundation-rs"
|
||||
version = "0.17.2"
|
||||
version = "0.17.3"
|
||||
authors = ["The Servo Project Developers"]
|
||||
license = "MIT / Apache-2.0"
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ pub mod event_source;
|
||||
pub mod font;
|
||||
pub mod geometry;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod window;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod private;
|
||||
pub mod image;
|
||||
pub mod path;
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2018 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use core_foundation::array::{CFArray, CFArrayRef};
|
||||
use core_foundation::base::{CFType, TCFType};
|
||||
use core_foundation::dictionary::CFDictionary;
|
||||
use core_foundation::string::{CFString, CFStringRef};
|
||||
use foreign_types::ForeignType;
|
||||
|
||||
use geometry::CGRect;
|
||||
use image::CGImage;
|
||||
use sys;
|
||||
|
||||
pub type CGWindowID = u32;
|
||||
|
||||
pub type CGWindowSharingType = u32;
|
||||
pub const kCGWindowSharingNone: CGWindowSharingType = 0;
|
||||
pub const kCGWindowSharingReadOnly: CGWindowSharingType = 1;
|
||||
pub const kCGWindowSharingReadWrite: CGWindowSharingType = 1;
|
||||
|
||||
pub type CGWindowBackingType = u32;
|
||||
pub const kCGWindowBackingStoreRetained: CGWindowBackingType = 0;
|
||||
pub const kCGWindowBackingStoreNonretained: CGWindowBackingType = 1;
|
||||
pub const kCGWindowBackingStoreBuffered: CGWindowBackingType = 2;
|
||||
|
||||
pub type CGWindowListOption = u32;
|
||||
pub const kCGWindowListOptionAll: CGWindowListOption = 1 << 0;
|
||||
pub const kCGWindowListOptionOnScreenOnly: CGWindowListOption = 1 << 1;
|
||||
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 2;
|
||||
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 3;
|
||||
pub const kCGWindowListOptionIncludingWindow: CGWindowListOption = 1 << 4;
|
||||
pub const kCGWindowListOptionExcludeDesktopElements: CGWindowListOption = 1 << 5;
|
||||
|
||||
pub type CGWindowImageOption = u32;
|
||||
pub const kCGWindowImageDefault: CGWindowImageOption = 0;
|
||||
pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0;
|
||||
pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1;
|
||||
pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2;
|
||||
pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3;
|
||||
pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4;
|
||||
|
||||
pub const kCGNullWindowID: CGWindowID = 0;
|
||||
|
||||
pub fn copy_window_info(option: CGWindowListOption, relative_to_window: CGWindowID)
|
||||
-> Option<CFArray> {
|
||||
unsafe {
|
||||
let array = CGWindowListCopyWindowInfo(option, relative_to_window);
|
||||
if array.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(TCFType::wrap_under_create_rule(array))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_window_list(option: CGWindowListOption, relative_to_window: CGWindowID)
|
||||
-> Option<CFArray<CGWindowID>> {
|
||||
unsafe {
|
||||
let array = CGWindowListCreate(option, relative_to_window);
|
||||
if array.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(TCFType::wrap_under_create_rule(array))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_description_from_array(window_array: CFArray<CGWindowID>) ->
|
||||
Option<CFArray<CFDictionary<CFString, CFType>>> {
|
||||
unsafe {
|
||||
let array = CGWindowListCreateDescriptionFromArray(window_array.as_concrete_TypeRef());
|
||||
if array.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(TCFType::wrap_under_create_rule(array))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_image(screen_bounds: CGRect,
|
||||
list_option: CGWindowListOption,
|
||||
window_id: CGWindowID,
|
||||
image_option: CGWindowImageOption)
|
||||
-> Option<CGImage> {
|
||||
unsafe {
|
||||
let image = CGWindowListCreateImage(screen_bounds, list_option, window_id, image_option);
|
||||
if image.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CGImage::from_ptr(image))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_image_from_array(screen_bounds: CGRect,
|
||||
window_array: CFArray,
|
||||
image_option: CGWindowImageOption)
|
||||
-> Option<CGImage> {
|
||||
unsafe {
|
||||
let image = CGWindowListCreateImageFromArray(screen_bounds,
|
||||
window_array.as_concrete_TypeRef(),
|
||||
image_option);
|
||||
if image.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CGImage::from_ptr(image))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link(name = "CoreGraphics", kind = "framework")]
|
||||
extern {
|
||||
pub static kCGWindowNumber: CFStringRef;
|
||||
pub static kCGWindowStoreType: CFStringRef;
|
||||
pub static kCGWindowLayer: CFStringRef;
|
||||
pub static kCGWindowBounds: CFStringRef;
|
||||
pub static kCGWindowSharingState: CFStringRef;
|
||||
pub static kCGWindowAlpha: CFStringRef;
|
||||
pub static kCGWindowOwnerPID: CFStringRef;
|
||||
pub static kCGWindowMemoryUsage: CFStringRef;
|
||||
pub static kCGWindowWorkspace: CFStringRef;
|
||||
pub static kCGWindowOwnerName: CFStringRef;
|
||||
pub static kCGWindowName: CFStringRef;
|
||||
pub static kCGWindowIsOnscreen: CFStringRef;
|
||||
pub static kCGWindowBackingLocationVideoMemory: CFStringRef;
|
||||
|
||||
pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID)
|
||||
-> CFArrayRef;
|
||||
pub fn CGWindowListCreate(option: CGWindowListOption, relativeToWindow: CGWindowID)
|
||||
-> CFArrayRef;
|
||||
pub fn CGWindowListCreateDescriptionFromArray(windowArray: CFArrayRef) -> CFArrayRef;
|
||||
pub fn CGWindowListCreateImage(screenBounds: CGRect,
|
||||
listOption: CGWindowListOption,
|
||||
windowID: CGWindowID,
|
||||
imageOption: CGWindowImageOption)
|
||||
-> *mut sys::CGImage;
|
||||
pub fn CGWindowListCreateImageFromArray(screenBounds: CGRect,
|
||||
windowArray: CFArrayRef,
|
||||
imageOption: CGWindowImageOption)
|
||||
-> *mut sys::CGImage;
|
||||
}
|
||||
Reference in New Issue
Block a user