Skip to content
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
32 changes: 26 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ authors = [
"Robbert van der Helm <mail@robbertvanderhelm.nl>",
"Adrien Prokopowicz <prokopylmc@gmail.com>"
]
edition = "2018"
edition = "2021"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for doing this in the same change as migrating to objc2?

license = "MIT OR Apache-2.0"
description = "Low-level windowing system geared towards making audio plugin UIs."
keywords = ["windowing", "audio", "plugin"]
Expand All @@ -23,7 +23,14 @@ exclude = [".github"]

[features]
default = []
opengl = ["uuid", "x11/glx"]
opengl = [
"uuid",
"x11/glx",
"objc2-core-foundation/CFBundle",
"objc2-app-kit/NSOpenGL",
"objc2-app-kit/NSOpenGLView",
"objc2-app-kit/objc2-open-gl"
]

[dependencies]
keyboard-types = { version = "0.6.1", default-features = false }
Expand All @@ -39,10 +46,23 @@ winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "
uuid = { version = "0.8", features = ["v4"], optional = true }

[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.24.0"
core-foundation = "0.9.1"
objc = "0.2.7"
uuid = { version = "0.8", features = ["v4"] }
uuid = { version = "1.23.1", features = ["v4"] }
objc2 = "0.6.4"
objc2-core-foundation = { version = "0.3.2", default-features = false, features = ["std", "CFString"] }
objc2-foundation = { version = "0.3.2", default-features = false, features = ["std", "NSEnumerator"] }
objc2-app-kit = { version = "0.3.2", default-features = false, features = [
"NSApplication",
"NSDragging",
"NSEvent",
"NSGraphics",
"NSPasteboard",
"NSResponder",
"NSRunningApplication",
"NSTrackingArea",
"NSView",
"NSWindow",
"objc2-core-foundation"
] }

[dev-dependencies]
rtrb = "0.2"
Expand Down
113 changes: 46 additions & 67 deletions src/gl/macos.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
use std::ffi::c_void;
use std::str::FromStr;

use raw_window_handle::RawWindowHandle;
#![allow(deprecated)] // OpenGL is deprecated on macOS

use cocoa::appkit::{
use super::{GlConfig, GlError, Profile};
use objc2::rc::Retained;
use objc2::AllocAnyThread;
use objc2::{MainThreadMarker, MainThreadOnly};
use objc2_app_kit::{
NSOpenGLContext, NSOpenGLContextParameter, NSOpenGLPFAAccelerated, NSOpenGLPFAAlphaSize,
NSOpenGLPFAColorSize, NSOpenGLPFADepthSize, NSOpenGLPFADoubleBuffer, NSOpenGLPFAMultisample,
NSOpenGLPFAOpenGLProfile, NSOpenGLPFASampleBuffers, NSOpenGLPFASamples, NSOpenGLPFAStencilSize,
NSOpenGLPixelFormat, NSOpenGLProfileVersion3_2Core, NSOpenGLProfileVersion4_1Core,
NSOpenGLProfileVersionLegacy, NSOpenGLView, NSView,
};
use cocoa::base::{id, nil, YES};
use cocoa::foundation::NSSize;

use core_foundation::base::TCFType;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
use core_foundation::string::CFString;

use objc::{msg_send, sel, sel_impl};

use super::{GlConfig, GlError, Profile};
use objc2_core_foundation::{CFBundle, CFString};
use objc2_foundation::NSSize;
use raw_window_handle::RawWindowHandle;
use std::ffi::c_void;
use std::ptr::NonNull;

pub type CreationFailedError = ();
pub struct GlContext {
view: id,
context: id,
view: Retained<NSOpenGLView>,
context: Retained<NSOpenGLContext>,
}

impl GlContext {
Expand All @@ -35,11 +31,10 @@ impl GlContext {
return Err(GlError::InvalidWindowHandle);
};

if handle.ns_view.is_null() {
let parent_view = handle.ns_view.cast::<NSView>();
let Some(parent_view) = parent_view.as_ref() else {
return Err(GlError::InvalidWindowHandle);
}

let parent_view = handle.ns_view as id;
};

let version = if config.version < (3, 2) && config.profile == Profile::Compatibility {
NSOpenGLProfileVersionLegacy
Expand Down Expand Up @@ -76,33 +71,29 @@ impl GlContext {

attrs.push(0);

let pixel_format = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attrs);

if pixel_format == nil {
return Err(GlError::CreationFailed(()));
}

let view =
NSOpenGLView::alloc(nil).initWithFrame_pixelFormat_(parent_view.frame(), pixel_format);
let pixel_format = NSOpenGLPixelFormat::initWithAttributes(
NSOpenGLPixelFormat::alloc(),
NonNull::new(attrs.as_mut_ptr()).unwrap(),
)
.ok_or(GlError::CreationFailed(()))?;

if view == nil {
return Err(GlError::CreationFailed(()));
}
let view = NSOpenGLView::initWithFrame_pixelFormat(
NSOpenGLView::alloc(MainThreadMarker::new().unwrap()),
parent_view.frame(),
Some(&pixel_format),
)
.ok_or(GlError::CreationFailed(()))?;

view.setWantsBestResolutionOpenGLSurface_(YES);
view.setWantsBestResolutionOpenGLSurface(true);

NSOpenGLView::display_(view);
parent_view.addSubview_(view);
view.display();
parent_view.addSubview(&view);

let context: id = msg_send![view, openGLContext];
let () = msg_send![context, retain];
let context = view.openGLContext().ok_or(GlError::CreationFailed(()))?;

context.setValues_forParameter_(
&(config.vsync as i32),
NSOpenGLContextParameter::NSOpenGLCPSwapInterval,
);
let value = config.vsync as i32;

let () = msg_send![pixel_format, release];
context.setValues_forParameter((&value).into(), NSOpenGLContextParameter::SwapInterval);

Ok(GlContext { view, context })
}
Expand All @@ -112,47 +103,35 @@ impl GlContext {
}

pub unsafe fn make_not_current(&self) {
NSOpenGLContext::clearCurrentContext(self.context);
if Some(&self.context) == NSOpenGLContext::currentContext().as_ref() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this changes the logic from how it was before, just wanted to confirm that you've specifically tested that this still works (that the equality check does what you'd expect).

NSOpenGLContext::clearCurrentContext();
}
}

pub fn get_proc_address(&self, symbol: &str) -> *const c_void {
let symbol_name = CFString::from_str(symbol).unwrap();
let framework_name = CFString::from_str("com.apple.opengl").unwrap();
let framework =
unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
let symbol_name = CFString::from_str(symbol);
let framework_name = CFString::from_static_str("com.apple.opengl");
let framework = CFBundle::bundle_with_identifier(Some(&framework_name)).unwrap();

unsafe { CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef()) }
CFBundle::function_pointer_for_name(&framework, Some(&symbol_name))
}

pub fn swap_buffers(&self) {
unsafe {
self.context.flushBuffer();
let () = msg_send![self.view, setNeedsDisplay: YES];
}
self.context.flushBuffer();
self.view.setNeedsDisplay(true);
}

/// On macOS the `NSOpenGLView` needs to be resized separtely from our main view.
pub(crate) fn resize(&self, size: NSSize) {
unsafe { NSView::setFrameSize(self.view, size) };
unsafe {
let _: () = msg_send![self.view, setNeedsDisplay: YES];
}
self.view.setFrameSize(size);
self.view.setNeedsDisplay(true);
}

/// Pointer to the `NSOpenGLView` this context renders into. Used by
/// the parent `NSView`'s `hitTest:` override to collapse hits on the
/// render subview to the parent, so AppKit routes `mouseDown:` on
/// first click in non-key windows.
pub(crate) fn ns_view(&self) -> id {
self.view
}
}

impl Drop for GlContext {
fn drop(&mut self) {
unsafe {
let () = msg_send![self.context, release];
let () = msg_send![self.view, release];
}
pub(crate) fn ns_view(&self) -> &NSOpenGLView {
&self.view
}
}
4 changes: 2 additions & 2 deletions src/gl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl GlContext {

/// On macOS the `NSOpenGLView` needs to be resized separtely from our main view.
#[cfg(target_os = "macos")]
pub(crate) fn resize(&self, size: cocoa::foundation::NSSize) {
pub(crate) fn resize(&self, size: objc2_foundation::NSSize) {
self.context.resize(size);
}

Expand All @@ -118,7 +118,7 @@ impl GlContext {
/// render subview to the parent, so AppKit routes `mouseDown:` on
/// first click in non-key windows.
#[cfg(target_os = "macos")]
pub(crate) fn ns_view(&self) -> cocoa::base::id {
pub(crate) fn ns_view(&self) -> &objc2_app_kit::NSView {
self.context.ns_view()
}
}
4 changes: 0 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// This is required because the objc crate is causing a lot of warnings: https://github.com/SSheldon/rust-objc/issues/125
// Eventually we should migrate to the objc2 crate and remove this.
#![allow(unexpected_cfgs)]

#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
Expand Down
Loading
Loading