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
9 changes: 4 additions & 5 deletions examples/open_parented/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use baseview::dpi::LogicalSize;
use baseview::{
Event, EventStatus, Window, WindowContext, WindowHandle, WindowHandler, WindowOpenOptions,
WindowSize,
Event, EventStatus, WindowContext, WindowHandle, WindowHandler, WindowOpenOptions, WindowSize,
};
use std::cell::{Cell, RefCell};
use std::num::NonZeroU32;
Expand All @@ -24,10 +23,10 @@ impl ParentWindowHandler {

let window_open_options = WindowOpenOptions::new()
.with_size(LogicalSize::new(256, 256))
.with_parent(&window)
.with_title("baseview child");

let child_window =
Window::open_parented(&window, window_open_options, ChildWindowHandler::new);
let child_window = baseview::create_window(window_open_options, ChildWindowHandler::new);

Self { surface: surface.into(), damaged: true.into(), _child_window: Some(child_window) }
}
Expand Down Expand Up @@ -122,5 +121,5 @@ impl WindowHandler for ChildWindowHandler {
fn main() {
let window_open_options = WindowOpenOptions::new().with_size(LogicalSize::new(512.0, 512.0));

Window::open_blocking(window_open_options, ParentWindowHandler::new);
baseview::create_window(window_open_options, ParentWindowHandler::new).run_until_closed();
}
8 changes: 4 additions & 4 deletions examples/open_window/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use rtrb::{Consumer, RingBuffer};
use baseview::copy_to_clipboard;
use baseview::dpi::{LogicalSize, PhysicalPosition};
use baseview::{
Event, EventStatus, MouseEvent, Window, WindowContext, WindowHandler, WindowOpenOptions,
WindowSize,
Event, EventStatus, MouseEvent, WindowContext, WindowHandler, WindowOpenOptions, WindowSize,
};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -148,7 +147,7 @@ fn main() {
}
});

Window::open_blocking(window_open_options, |window| {
baseview::create_window(window_open_options, |window| {
let ctx = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&ctx, window.clone()).unwrap();
let size = window.size().physical;
Expand All @@ -164,7 +163,8 @@ fn main() {
is_cursor_inside: false.into(),
damaged: true.into(),
}
});
})
.run_until_closed();
}

fn log_event(event: &Event) {
Expand Down
5 changes: 2 additions & 3 deletions examples/render_femtovg/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use baseview::dpi::{LogicalSize, PhysicalPosition};
use baseview::gl::{GlConfig, GlContext};
use baseview::{
Event, EventStatus, MouseEvent, Window, WindowContext, WindowHandler, WindowOpenOptions,
WindowSize,
Event, EventStatus, MouseEvent, WindowContext, WindowHandler, WindowOpenOptions, WindowSize,
};
use femtovg::renderer::OpenGl;
use femtovg::{Canvas, Color};
Expand Down Expand Up @@ -117,7 +116,7 @@ fn main() {
.with_size(LogicalSize::new(512, 512))
.with_gl_config(GlConfig { alpha_bits: 8, ..GlConfig::default() });

Window::open_blocking(window_open_options, FemtovgExample::new);
baseview::create_window(window_open_options, FemtovgExample::new).run_until_closed();
}

fn log_event(event: &Event) {
Expand Down
7 changes: 3 additions & 4 deletions examples/render_wgpu/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use baseview::dpi::{LogicalSize, PhysicalSize};
use baseview::{
Event, EventStatus, Window, WindowContext, WindowHandler, WindowOpenOptions, WindowSize,
};
use baseview::{Event, EventStatus, WindowContext, WindowHandler, WindowOpenOptions, WindowSize};

use log::LevelFilter;
use std::cell::RefCell;
Expand Down Expand Up @@ -210,7 +208,8 @@ fn main() {
.with_title("WGPU on Baseview")
.with_size(LogicalSize::new(512, 512));

Window::open_blocking(window_open_options, |c| pollster::block_on(WgpuExample::new(c)));
baseview::create_window(window_open_options, |c| pollster::block_on(WgpuExample::new(c)))
.run_until_closed();
}

fn log_event(event: &Event) {
Expand Down
19 changes: 18 additions & 1 deletion src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
use crate::{Event, EventStatus, WindowSize};
use super::*;

pub trait WindowHandler: 'static {
fn on_frame(&self);
fn resized(&self, new_size: WindowSize);
fn on_event(&self, event: Event) -> EventStatus;
}

#[allow(unused)]
pub struct WindowHandlerBuilder {
inner: Box<dyn FnOnce(WindowContext) -> Box<dyn WindowHandler> + Send + 'static>,
}

impl WindowHandlerBuilder {
pub fn new<H: WindowHandler>(
f: impl FnOnce(WindowContext) -> H + Send + 'static,
) -> WindowHandlerBuilder {
Self { inner: Box::new(|c| Box::new(f(c))) }
}

pub fn build(self, ctx: WindowContext) -> Box<dyn WindowHandler> {
(self.inner)(ctx)
}
}
17 changes: 15 additions & 2 deletions src/platform/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ mod view;
mod window;

use crate::platform::macos::view::BaseviewView;
use crate::wrappers::appkit::View;
use crate::wrappers::appkit::{extract_raw_window_handle, View};
pub use context::WindowContext;
use dispatch2::MainThreadBound;
use objc2::__framework_prelude::Retained;
use objc2::rc::Weak;
use objc2::MainThreadMarker;
use raw_window_handle::DisplayHandle;
use objc2_app_kit::NSView;
use raw_window_handle::{DisplayHandle, HasWindowHandle};
use std::fmt;
use std::fmt::Formatter;
pub use window::*;
Expand Down Expand Up @@ -63,3 +65,14 @@ impl fmt::Debug for PlatformHandle {
f.debug_struct("PlatformHandle (AppKit)").field("ns_view", &PtrFmt(self)).finish()
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ParentWindowHandle {
view: Retained<NSView>,
}

impl ParentWindowHandle {
pub fn extract(window: &impl HasWindowHandle) -> Self {
Self { view: extract_raw_window_handle(window.window_handle().unwrap()).unwrap() }
}
}
10 changes: 5 additions & 5 deletions src/platform/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use super::keyboard::{make_modifiers, KeyboardState};
use super::window::WindowSharedState;
use crate::handler::WindowHandlerBuilder;
use crate::platform::macos::context::WindowContext;
use crate::wrappers::appkit::*;
use crate::MouseEvent::{ButtonPressed, ButtonReleased};
Expand Down Expand Up @@ -44,10 +45,9 @@ pub(crate) struct BaseviewView {
}

impl BaseviewView {
pub fn new<H: WindowHandler + 'static>(
_options: WindowOpenOptions,
builder: impl FnOnce(crate::WindowContext) -> H + Send + 'static,
parenting: ViewParentingType, final_size: LogicalSize<f64>, mtm: MainThreadMarker,
pub fn new(
_options: WindowOpenOptions, builder: WindowHandlerBuilder, parenting: ViewParentingType,
final_size: LogicalSize<f64>, mtm: MainThreadMarker,
) -> (Retained<View<Self>>, Rc<WindowSharedState>) {
let view_rect =
NSRect::new(NSPoint::ZERO, NSSize::new(final_size.width, final_size.height));
Expand Down Expand Up @@ -92,7 +92,7 @@ impl BaseviewView {
}

let context = WindowContext::new(view);
let handler = Box::new(builder(crate::WindowContext::new(context)));
let handler = builder.build(crate::WindowContext::new(context));

// Initialize handler
let Ok(()) = view.window_handler.set(handler) else { unreachable!() };
Expand Down
145 changes: 76 additions & 69 deletions src/platform/macos/window.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,110 @@
use dpi::LogicalSize;
use objc2::rc::{autoreleasepool, Weak};
use objc2::rc::{autoreleasepool, Retained, Weak};
use objc2::MainThreadMarker;
use objc2_app_kit::{
NSApplication, NSApplicationActivationPolicy, NSPasteboard, NSPasteboardTypeString,
};
use objc2_app_kit::{NSApplication, NSPasteboard, NSPasteboardTypeString, NSView, NSWindow};
use objc2_foundation::{NSSize, NSString};
use raw_window_handle::HasWindowHandle;
use std::cell::{Cell, RefCell};
use std::cell::Cell;
use std::rc::Rc;

use crate::handler::WindowHandlerBuilder;
use crate::platform::macos::view::{BaseviewView, ViewParentingType};
use crate::wrappers::appkit::{create_window, extract_raw_window_handle, View};
use crate::{WindowContext, WindowHandler, WindowOpenOptions};
use crate::wrappers::appkit::{create_window, View};
use crate::*;

pub struct WindowHandle {
view: RefCell<Option<Weak<View<BaseviewView>>>>,
mtm: MainThreadMarker,
view: Weak<View<BaseviewView>>,
_window: Option<Retained<NSWindow>>,
state: Rc<WindowSharedState>,
}

impl WindowHandle {
pub fn close(&self) {
let Some(view) = self.view.take().and_then(|w| w.load()) else {
return;
};
pub fn create_window(mut options: WindowOpenOptions, handler: WindowHandlerBuilder) -> Self {
autoreleasepool(|_| {
let Some(mtm) = MainThreadMarker::new() else {
panic!("macOS: Windows can only be created on the main thread!")
};

BaseviewView::close(view.inner_ref());
}
// Creates the global NSApplication instance, if it doesn't exist yet
let _ = NSApplication::sharedApplication(mtm);

pub fn is_open(&self) -> bool {
self.state.closed.get()
if let Some(parent) = options.parent.take() {
return Self::create_window_parented(options, handler, parent.view, mtm);
}

Self::create_window_standalone(options, handler, mtm)
})
}
}

pub struct Window;
pub fn create_window_parented(
builder: WindowOpenOptions, handler: WindowHandlerBuilder, parent_view: Retained<NSView>,
mtm: MainThreadMarker,
) -> Self {
let parenting =
ViewParentingType::Parented { parent_view: Weak::from_retained(&parent_view) };

impl Window {
pub fn open_parented<H: WindowHandler>(
parent: &impl HasWindowHandle, options: WindowOpenOptions,
build: impl FnOnce(WindowContext) -> H + Send + 'static,
) -> WindowHandle {
autoreleasepool(|_| {
let Some(parent_view) = extract_raw_window_handle(parent.window_handle().unwrap())
else {
panic!("Invalid window handle: ns_view is NULL");
};
let backing_scale_factor =
parent_view.window().map(|w| w.backingScaleFactor()).unwrap_or(1.0);
let final_size = builder.size.to_logical(backing_scale_factor);

let Some(mtm) = MainThreadMarker::new() else {
panic!("macOS: open_blocking can only be called on the main thread!")
};

let parenting =
ViewParentingType::Parented { parent_view: Weak::from_retained(&parent_view) };
let (ns_view, state) = BaseviewView::new(builder, handler, parenting, final_size, mtm);

let backing_scale_factor =
parent_view.window().map(|w| w.backingScaleFactor()).unwrap_or(1.0);
let final_size = options.size.to_logical(backing_scale_factor);
Self { mtm, state, _window: None, view: Weak::from_retained(&ns_view) }
}

let (ns_view, state) = BaseviewView::new(options, build, parenting, final_size, mtm);
pub fn create_window_standalone(
builder: WindowOpenOptions, handler: WindowHandlerBuilder, mtm: MainThreadMarker,
) -> Self {
let app = NSApplication::sharedApplication(mtm);
let window = create_window_with_options(&builder, mtm);

WindowHandle { view: Some(Weak::from_retained(&ns_view)).into(), state }
})
}
let final_size = window.contentRectForFrameRect(window.frame()).size;
let final_size = LogicalSize::new(final_size.width, final_size.height);

pub fn open_blocking<H: WindowHandler>(
options: WindowOpenOptions, build: impl FnOnce(WindowContext) -> H + Send + 'static,
) {
autoreleasepool(|_| {
let Some(mtm) = MainThreadMarker::new() else {
panic!("macOS: open_blocking can only be called on the main thread!")
};
let parenting = ViewParentingType::Windowed {
running_app: Weak::from_retained(&app),
owned_window: Weak::from_retained(&window),
};

// Creates the global NSApplication instance, if it doesn't exist yet
let app = NSApplication::sharedApplication(mtm);
let (view, state) = BaseviewView::new(builder, handler, parenting, final_size, mtm);

let _ = app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
Self { mtm, state, view: Weak::from_retained(&view), _window: Some(window) }
}

let initial_size = options.size.to_logical(1.0);
let window = create_window(initial_size, mtm);
window.center();
pub fn run_until_closed(self) {
NSApplication::sharedApplication(self.mtm).run();
}

let final_size = options.size.to_logical(window.backingScaleFactor());
if final_size != initial_size {
window.setContentSize(NSSize::new(final_size.width, final_size.height));
}
pub fn close(&self) {
let Some(view) = self.view.load() else {
return;
};

let title = NSString::from_str(&options.title);
window.setTitle(&title);
window.makeKeyAndOrderFront(None);
BaseviewView::close(view.inner_ref());
}

let parenting = ViewParentingType::Windowed {
running_app: Weak::from_retained(&app),
owned_window: Weak::from_retained(&window),
};
pub fn is_open(&self) -> bool {
self.state.closed.get()
}
}

let _ = BaseviewView::new(options, build, parenting, final_size, mtm);
fn create_window_with_options(
options: &WindowOpenOptions, mtm: MainThreadMarker,
) -> Retained<NSWindow> {
let initial_size = options.size.to_logical(1.0);
let window = create_window(initial_size, mtm);
window.center();

app.run();
})
let final_size = options.size.to_logical(window.backingScaleFactor());
if final_size != initial_size {
window.setContentSize(NSSize::new(final_size.width, final_size.height));
}

let title = NSString::from_str(&options.title);
window.setTitle(&title);

window.makeKeyAndOrderFront(None);
window
}

pub(crate) struct WindowSharedState {
Expand Down
19 changes: 18 additions & 1 deletion src/platform/win/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ mod window;
mod window_state;

use crate::wrappers::win32::h_instance::HInstance;
use raw_window_handle::{DisplayHandle, Win32WindowHandle};
use crate::wrappers::win32::window::HWnd;
use raw_window_handle::{DisplayHandle, HasWindowHandle, RawWindowHandle, Win32WindowHandle};
use std::fmt::Debug;
use std::num::NonZeroIsize;
use std::rc::Rc;
Expand Down Expand Up @@ -42,3 +43,19 @@ impl Debug for PlatformHandle {
.finish()
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ParentWindowHandle {
handle: HWnd,
}

impl ParentWindowHandle {
pub fn extract(parent: &impl HasWindowHandle) -> Self {
let parent = match parent.window_handle().unwrap().as_raw() {
RawWindowHandle::Win32(h) => h.hwnd,
h => panic!("unsupported parent handle {:?}", h),
};

Self { handle: unsafe { HWnd::from_raw(parent.get() as _) } }
}
}
Loading
Loading