Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace core-foundation and core-graphics #35

Open
wants to merge 3 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ rustdoc-args = ["--cfg", "docsrs"]
bitmask-enum = "2.2.1"
objc = { version = "=0.3.0-beta.2", package = "objc2" }
block = { version = "=0.2.0-alpha.6", package = "block2" }
# Temporary: Patched versions that implement `Encode` for common types
# Branch: `objc2`
core-foundation = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" }
core-graphics = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" }
dispatch = "0.2.0"
infer = { version = "0.15", optional = true }
lazy_static = "1.4.0"
Expand All @@ -36,9 +32,11 @@ uuid = { version = "1.1", features = ["v4"], optional = true }

[dev-dependencies]
eval = "0.4"
core-graphics = "0.23"
foreign-types = "0.5"

[features]
appkit = ["core-foundation/mac_os_10_8_features"]
appkit = []
uikit = []
autolayout = []
default = ["appkit", "autolayout"]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ The following are a list of [Cargo features][cargo-features] that can be enabled
[cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

## General Notes
**Why not extend the existing cocoa-rs crate?**
A good question. At the end of the day, that crate (I believe, and someone can correct me if I'm wrong) is somewhat tied to Servo, and I wanted to experiment with what the best approach for representing the Cocoa UI model in Rust was. This crate doesn't ignore their work entirely, either - `core_foundation` and `core_graphics` are used internally and re-exported for general use.
**Why not extend the existing cocoa-rs crate?**
A good question. At the end of the day, that crate (I believe, and someone can correct me if I'm wrong) is somewhat tied to Servo, and I wanted to experiment with what the best approach for representing the Cocoa UI model in Rust was.

**Why should I write in Rust, rather than X language?**
In _my_ case, I want to be able to write native applications for my devices (and the platform I like to build products for) without being locked in to writing in Apple-specific languages... and without writing in C/C++ or JavaScript (note: the _toolchain_, not the language - ES6/Typescript are fine). I want to do this because I'm tired of hitting a mountain of work when I want to port my applications to other ecosystems. I think that Rust offers a (growing, but significant) viable model for sharing code across platforms and ecosystems without sacrificing performance.
Expand Down
10 changes: 9 additions & 1 deletion examples/custom_image_drawing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! This example showcases how to do custom drawing on an ImageView
//! with CoreGraphics. Feel free to modify it and play around!

use core_graphics::context::CGContextRef;
use foreign_types::ForeignTypeRef;

use cacao::appkit::menu::{Menu, MenuItem};
use cacao::appkit::window::Window;
use cacao::appkit::{App, AppDelegate};
Expand Down Expand Up @@ -30,7 +33,12 @@ impl Default for BasicApp {
window: Window::default(),
content_view: View::new(),
image_view: ImageView::new(),
image: Image::draw(config, |_cg_rect, context| {
image: Image::draw(config, |resized_frame, source, context| {
let context = unsafe { CGContextRef::from_ptr(context.cast()) };

context.translate(resized_frame.top, resized_frame.left);
context.scale(resized_frame.width / source.0, resized_frame.height / source.1);

context.move_to_point(11.25, 8.19);
context.add_line_to_point(11.25, 5.);
context.add_line_to_point(6.56, 5.);
Expand Down
3 changes: 2 additions & 1 deletion src/appkit/event/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use bitmask_enum::bitmask;
use block::ConcreteBlock;

use objc::foundation::NSPoint;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id, sel};

use crate::events::EventType;
use crate::foundation::{id, nil, NSInteger, NSPoint, NSString};
use crate::foundation::{id, nil, NSInteger, NSString};

/// An EventMask describes the type of event.
#[bitmask(u64)]
Expand Down
2 changes: 1 addition & 1 deletion src/appkit/segmentedcontrol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl SegmentedControl {
#[cfg(feature = "appkit")]
self.objc.with_mut(move |obj| unsafe {
let text: id = msg_send![obj, attributedTitle];
let len: isize = msg_send![text, length];
let len: usize = msg_send![text, length];

let mut attr_str = AttributedString::wrap(text);
attr_str.set_text_color(color.as_ref(), 0..len);
Expand Down
6 changes: 3 additions & 3 deletions src/appkit/toolbar/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
//!
//! UNFORTUNATELY, this is a very old and janky API. So... yeah.

use core_graphics::geometry::CGSize;
use std::fmt;

use objc::foundation::NSSize;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id, sel};
Expand Down Expand Up @@ -89,15 +89,15 @@ impl ToolbarItem {
/// Sets the minimum size for this button.
pub fn set_min_size(&mut self, width: f64, height: f64) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setMinSize: size];
}
}

/// Sets the maximum size for this button.
pub fn set_max_size(&mut self, width: f64, height: f64) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setMaxSize: size];
}
}
Expand Down
23 changes: 8 additions & 15 deletions src/appkit/window/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@

use std::sync::Once;

use core_graphics::base::CGFloat;

use objc::declare::ClassDecl;
use objc::foundation::{CGFloat, NSSize};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, sel};

use crate::appkit::window::{WindowDelegate, WINDOW_DELEGATE_PTR};
use crate::foundation::{id, load_or_register_class, NSUInteger};
use crate::utils::{load, CGSize};
use crate::utils::load;

/// Called when an `NSWindowDelegate` receives a `windowWillClose:` event.
/// Good place to clean up memory and what not.
Expand Down Expand Up @@ -53,14 +52,11 @@ extern "C" fn did_change_screen_profile<T: WindowDelegate>(this: &Object, _: Sel
}

/// Called when an `NSWindowDelegate` receives a `windowDidChangeScreen:` event.
extern "C" fn will_resize<T: WindowDelegate>(this: &Object, _: Sel, _: id, size: CGSize) -> CGSize {
extern "C" fn will_resize<T: WindowDelegate>(this: &Object, _: Sel, _: id, size: NSSize) -> NSSize {
let window = load::<T>(this, WINDOW_DELEGATE_PTR);
let s = window.will_resize(size.width as f64, size.height as f64);
let s = window.will_resize(size.width() as f64, size.height() as f64);

CGSize {
width: s.0 as CGFloat,
height: s.1 as CGFloat
}
NSSize::new(s.0 as CGFloat, s.1 as CGFloat)
}

/// Called when an `NSWindowDelegate` receives a `windowDidChangeScreen:` event.
Expand Down Expand Up @@ -112,15 +108,12 @@ extern "C" fn did_enter_full_screen<T: WindowDelegate>(this: &Object, _: Sel, _:
}

/// Called when an `NSWindowDelegate` receives a `windowDidChangeScreenProfile:` event.
extern "C" fn content_size_for_full_screen<T: WindowDelegate>(this: &Object, _: Sel, _: id, size: CGSize) -> CGSize {
extern "C" fn content_size_for_full_screen<T: WindowDelegate>(this: &Object, _: Sel, _: id, size: NSSize) -> NSSize {
let window = load::<T>(this, WINDOW_DELEGATE_PTR);

let (width, height) = window.content_size_for_full_screen(size.width as f64, size.height as f64);
let (width, height) = window.content_size_for_full_screen(size.width() as f64, size.height() as f64);

CGSize {
width: width as CGFloat,
height: height as CGFloat
}
NSSize::new(width as CGFloat, height as CGFloat)
}

/// Called when an `NSWindowDelegate` receives a `windowDidChangeScreenProfile:` event.
Expand Down
16 changes: 7 additions & 9 deletions src/appkit/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@

use block::ConcreteBlock;

use core_graphics::base::CGFloat;
use core_graphics::geometry::{CGRect, CGSize};

use objc::foundation::{CGFloat, NSRect, NSSize};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id, sel};
Expand Down Expand Up @@ -75,7 +73,7 @@ impl Window {
// Other types of backing (Retained/NonRetained) are archaic, dating back to the
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into();
let dimensions: NSRect = config.initial_dimensions.into();
let window: Id<_, _> = msg_send_id![
msg_send_id![class!(NSWindow), alloc],
initWithContentRect: dimensions,
Expand Down Expand Up @@ -140,7 +138,7 @@ where
// Other types of backing (Retained/NonRetained) are archaic, dating back to the
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into();
let dimensions: NSRect = config.initial_dimensions.into();
let mut window: Id<Object, Owned> = msg_send_id![
msg_send_id![class, alloc],
initWithContentRect: dimensions,
Expand Down Expand Up @@ -255,31 +253,31 @@ impl<T> Window<T> {
/// Sets the content size for this window.
pub fn set_content_size<F: Into<f64>>(&self, width: F, height: F) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setContentSize: size];
}
}

/// Sets the minimum size this window can shrink to.
pub fn set_minimum_content_size<F: Into<f64>>(&self, width: F, height: F) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setContentMinSize: size];
}
}

/// Sets the maximum size this window can shrink to.
pub fn set_maximum_content_size<F: Into<f64>>(&self, width: F, height: F) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setContentMaxSize: size];
}
}

/// Sets the minimum size this window can shrink to.
pub fn set_minimum_size<F: Into<f64>>(&self, width: F, height: F) {
unsafe {
let size = CGSize::new(width.into(), height.into());
let size = NSSize::new(width.into(), height.into());
let _: () = msg_send![&*self.objc, setMinSize: size];
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl Button {
#[cfg(feature = "appkit")]
self.objc.with_mut(move |obj| unsafe {
let text: id = msg_send![obj, attributedTitle];
let len: isize = msg_send![text, length];
let len: usize = msg_send![text, length];

let mut attr_str = AttributedString::wrap(text);
attr_str.set_text_color(color.as_ref(), 0..len);
Expand Down
2 changes: 1 addition & 1 deletion src/color/appkit_dynamic_color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! that enables this functionality, we want to be able to provide this with some level of
//! backwards compatibility for Mojave, as that's still a supported OS.

use core_graphics::base::CGFloat;
use objc::foundation::CGFloat;
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel};

Expand Down
29 changes: 14 additions & 15 deletions src/color/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@
//! we expose some platform-specific methods for creating and working with these.
//!
//! We attempt to provide fallbacks for older versions of macOS/iOS, but this is not exhaustive,
/// as the cross-section of people building for older platforms in Rust is likely very low. If you
/// need these fallbacks to be better and/or correct, you're welcome to improve and pull-request
/// this.
///
/// The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
/// an important piece. It's not on the framework to make your app look good, though. To enable
/// fallbacks, specify the `color_fallbacks` target_os in your `Cargo.toml`.
///
/// @TODO: bundle iOS/tvOS support.
//! as the cross-section of people building for older platforms in Rust is likely very low. If you
//! need these fallbacks to be better and/or correct, you're welcome to improve and pull-request
//! this.
//!
//! The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
//! an important piece. It's not on the framework to make your app look good, though. To enable
//! fallbacks, specify the `color_fallbacks` target_os in your `Cargo.toml`.
//!
//! @TODO: bundle iOS/tvOS support.
use std::ffi::c_void;
use std::sync::{Arc, RwLock};

use core_foundation::base::TCFType;
use core_graphics::base::CGFloat;
use core_graphics::color::CGColor;

use objc::foundation::CGFloat;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id, sel};
Expand Down Expand Up @@ -392,10 +390,11 @@ impl Color {
/// objects. If you're painting in a context that requires dark mode support, make sure
/// you're not using a cached version of this unless you explicitly want the _same_ color
/// in every context it's used in.
pub fn cg_color(&self) -> CGColor {
pub fn cg_color(&self) -> *mut c_void {
// TODO: Better return type
unsafe {
let objc: id = self.into();
CGColor::wrap_under_get_rule(msg_send![objc, CGColor])
msg_send![objc, CGColor]
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/foundation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,3 @@ pub type NSInteger = libc::c_long;
/// Platform-specific.
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = libc::c_ulong;

pub type NSPoint = core_graphics::geometry::CGPoint;
17 changes: 9 additions & 8 deletions src/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Wrapper methods for various geometry types (rects, sizes, ec).

use core_graphics::geometry::{CGPoint, CGRect, CGSize};
use objc::foundation::{NSPoint, NSRect, NSSize};

/// A struct that represents a box - top, left, width and height. You might use this for, say,
/// setting the initial frame of a view.
Expand Down Expand Up @@ -49,19 +49,20 @@ pub enum Edge {
MaxX = 2,
MaxY = 3
}
impl From<Rect> for CGRect {
fn from(rect: Rect) -> CGRect {
CGRect::new(&CGPoint::new(rect.left, rect.top), &CGSize::new(rect.width, rect.height))

impl From<Rect> for NSRect {
fn from(rect: Rect) -> NSRect {
NSRect::new(NSPoint::new(rect.left, rect.top), NSSize::new(rect.width, rect.height))
}
}

impl From<CGRect> for Rect {
fn from(rect: CGRect) -> Rect {
impl From<NSRect> for Rect {
fn from(rect: NSRect) -> Rect {
Rect {
top: rect.origin.y as f64,
left: rect.origin.x as f64,
width: rect.size.width as f64,
height: rect.size.height as f64
width: rect.size.width() as f64,
height: rect.size.height() as f64
}
}
}
26 changes: 26 additions & 0 deletions src/image/graphics_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::ffi::c_void;

use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id};

#[derive(Debug)]
pub(crate) struct GraphicsContext(pub Id<Object, Shared>);

impl GraphicsContext {
pub(crate) fn current() -> Self {
Self(unsafe { msg_send_id![class!(NSGraphicsContext), currentContext] })
}

pub(crate) fn save(&self) {
unsafe { msg_send![&self.0, saveGraphicsState] }
}

pub(crate) fn restore(&self) {
unsafe { msg_send![&self.0, restoreGraphicsState] }
}

pub(crate) fn cg_context(&self) -> *mut c_void {
unsafe { msg_send![&self.0, CGContext] }
}
}
Loading
Loading