Skip to content
Merged
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
1 change: 1 addition & 0 deletions examples/plugin_clack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ clack-extensions = { version = "0.1.0", features = ["gui", "clack-plugin", "raw-
baseview = { path = "../..", features = ["opengl"] }
softbuffer = "0.4.8"
raw-window-handle = "0.6.2"

50 changes: 26 additions & 24 deletions examples/plugin_clack/src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,23 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> {
}

fn create(&mut self, _configuration: GuiConfiguration) -> Result<(), PluginError> {
// Delay creation until set_parent
let options = WindowOpenOptions::new()
.with_size(PhysicalSize::new(400, 200))
.with_gl_config(GlConfig::default());

let mut host = Host::new().with_main_thread(unsafe {
MainThreadHandler { host: self.host.shared().with_arbitrary_lifetime() }
});

if let Some(gui) = self.host_gui {
host = host.with_callbacks(unsafe {
HostGuiCallbacks { ext: gui, host: self.host.with_arbitrary_lifetime() }
});
}

let window = baseview::create_window_with_host(options, OpenWindowExample::new, host)?;

self.gui = Some(ExamplePluginGui { handle: window });
Ok(())
}

Expand All @@ -51,11 +67,11 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> {
}

fn get_size(&mut self) -> Option<GuiSize> {
let Some(gui) = self.gui.as_ref() else {
// Because we delayed the window creation, this will get called without a GUI active.
// During that time, return the default UI size.
return Some(GuiSize { width: 400, height: 200 });
let Some(gui) = &self.gui else {
eprintln!("get_size called without a GUI active");
return None;
};

Some(window_size_to_gui_size(gui.handle.size()))
}

Expand Down Expand Up @@ -90,27 +106,14 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> {

#[allow(deprecated)]
fn set_parent(&mut self, window: ClapWindow) -> Result<(), PluginError> {
let Some(gui) = &self.gui else {
return Err(PluginError::Message("set_parent called without a GUI active"));
};

let parent = window.raw_window_handle()?;
let parent = unsafe { raw_window_handle::WindowHandle::borrow_raw(parent) };

let options = WindowOpenOptions::new()
.with_size(PhysicalSize::new(400, 200))
.with_gl_config(GlConfig::default())
.with_parent(&parent);

let mut host = Host::new().with_main_thread(unsafe {
MainThreadHandler { host: self.host.shared().with_arbitrary_lifetime() }
});

if let Some(gui) = self.host_gui {
host = host.with_callbacks(unsafe {
HostGuiCallbacks { ext: gui, host: self.host.with_arbitrary_lifetime() }
});
}

let window = baseview::create_window_with_host(options, OpenWindowExample::new, host)?;

self.gui = Some(ExamplePluginGui { handle: window });
gui.handle.set_parent(&parent)?;

Ok(())
}
Expand Down Expand Up @@ -163,7 +166,6 @@ struct MainThreadHandler {

impl HostMainThreadCaller for MainThreadHandler {
fn call_main_thread(&mut self) {
eprintln!("Requesting main thread");
self.host.request_callback();
}
}
Expand Down
74 changes: 50 additions & 24 deletions src/platform/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,35 @@ use std::rc::Rc;

pub enum ViewParentingType {
Parented { parent_view: Weak<NSView> },
Windowed { owned_window: Weak<NSWindow>, running_app: Weak<NSApplication> },
Windowed { owned_window: Weak<NSWindow> },
Uninitialized,
}

impl ViewParentingType {
fn setup(&self, child: &View<BaseviewView>) {
match self {
ViewParentingType::Parented { parent_view } => {
if let Some(parent_view) = parent_view.load() {
parent_view.addSubview(child);
}
}
ViewParentingType::Windowed { owned_window, .. } => {
if let Some(owned_window) = owned_window.load() {
owned_window.setContentView(Some(child));
set_delegate(&owned_window, child);
}
}
_ => {}
}
}

fn teardown(self) {
if let ViewParentingType::Windowed { owned_window: parent_window } = self {
if let Some(parent_window) = parent_window.load() {
parent_window.close();
}
}
}
}

pub(crate) struct BaseviewView {
Expand All @@ -40,7 +68,8 @@ pub(crate) struct BaseviewView {

keyboard_state: KeyboardState,

parenting: ViewParentingType,
parenting: RefCell<ViewParentingType>,
pub(crate) lifetime_tied_to_app: Cell<Option<Weak<NSApplication>>>,

host: Host,

Expand All @@ -66,28 +95,18 @@ impl BaseviewView {
frame_timer: None.into(),
window_handler: WindowHandlerContainer::new(),
notification_center_observer: None.into(),
parenting,
parenting: ViewParentingType::Uninitialized.into(),
host,
lifetime_tied_to_app: None.into(),

#[cfg(feature = "opengl")]
gl_context: std::cell::OnceCell::new(),
};

let view = View::new(view_rect, inner, |view| {
// Set up parenting before handler setup
match &view.parenting {
ViewParentingType::Parented { parent_view } => {
if let Some(parent_view) = parent_view.load() {
parent_view.addSubview(view.view);
}
}
ViewParentingType::Windowed { owned_window, .. } => {
if let Some(owned_window) = owned_window.load() {
owned_window.setContentView(Some(view.view));
set_delegate(&owned_window, view.view);
}
}
}
parenting.setup(view.view);
view.parenting.replace(parenting);

view.state.scale_factor.set(view.view.backing_scale_factor());
view.state.size.set(view.view.size());
Expand Down Expand Up @@ -142,14 +161,11 @@ impl BaseviewView {
this.frame_timer.take();
this.window_handler.destroy();

if let ViewParentingType::Windowed { owned_window: parent_window, running_app } =
&this.parenting
{
if let Some(parent_window) = parent_window.load() {
parent_window.close();
}
let parenting = this.parenting.replace(ViewParentingType::Uninitialized);
parenting.teardown();

if let Some(app) = running_app.load() {
if let Some(app) = this.lifetime_tied_to_app.take() {
if let Some(app) = app.load() {
app.stop(Some(&app));
}
}
Expand All @@ -159,6 +175,16 @@ impl BaseviewView {
}
}

pub fn set_parent(this: ViewRef<Self>, new_parent: Retained<NSView>) {
let previous_parenting = this.parenting.replace(ViewParentingType::Uninitialized);
previous_parenting.teardown();

let parenting = ViewParentingType::Parented { parent_view: Weak::from(new_parent) };
parenting.setup(this.view);

this.parenting.replace(parenting);
}

pub fn resize(this: ViewRef<Self>, size: Size, notify_host: bool) {
let size = size.to_logical::<f64>(this.view.backing_scale_factor());
// NOTE: macOS gives you a personal rave if you pass in fractional pixels here. Even
Expand All @@ -176,7 +202,7 @@ impl BaseviewView {
}

// If this is a standalone window then we'll also need to resize the window itself
if let ViewParentingType::Windowed { owned_window, .. } = &this.parenting {
if let ViewParentingType::Windowed { owned_window } = &*this.parenting.borrow() {
if let Some(owned_window) = owned_window.load() {
owned_window.setContentSize(size);
}
Expand Down
26 changes: 20 additions & 6 deletions src/platform/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::rc::Rc;
use crate::handler::WindowHandlerBuilder;
use crate::host::Host;
use crate::platform::macos::view::{BaseviewView, ViewParentingType};
use crate::platform::ParentWindowHandle;
use crate::platform::Result;
use crate::wrappers::appkit::{create_window, View};
use crate::*;
Expand Down Expand Up @@ -76,24 +77,28 @@ impl WindowHandle {
builder: WindowOpenOptions, handler: WindowHandlerBuilder, host: Host,
mtm: MainThreadMarker,
) -> Result<Self> {
let app = NSApplication::sharedApplication(mtm);
let window = create_window_with_options(&builder, mtm);

let final_size = window.contentRectForFrameRect(window.frame()).size;
let final_size = LogicalSize::new(final_size.width, final_size.height);

let parenting = ViewParentingType::Windowed {
running_app: Weak::from_retained(&app),
owned_window: Weak::from_retained(&window),
};
let parenting = ViewParentingType::Windowed { owned_window: Weak::from_retained(&window) };

let (view, state) = BaseviewView::new(builder, handler, parenting, host, final_size, mtm)?;

Ok(Self { mtm, state, view: Weak::from_retained(&view), _window: Some(window) })
}

pub fn run_until_closed(self) -> Result<()> {
NSApplication::sharedApplication(self.mtm).run();
let Some(view) = self.view.load() else { return Ok(()) };
let Some(view) = view.inner_ref() else { return Ok(()) };

let app = NSApplication::sharedApplication(self.mtm);

view.lifetime_tied_to_app.set(Some(Weak::from_retained(&app)));
app.run();
view.lifetime_tied_to_app.set(None);

Ok(())
}

Expand Down Expand Up @@ -123,6 +128,15 @@ impl WindowHandle {
// This does not do anything on macOS: all coordinates are already logical
Ok(())
}

pub fn set_parent(&self, new_parent: ParentWindowHandle) -> Result<()> {
let Some(view) = self.view.load() else { return Ok(()) };
let Some(view) = view.inner_ref() else { return Ok(()) };

BaseviewView::set_parent(view, new_parent.view);

Ok(())
}
}

fn create_window_with_options(
Expand Down
2 changes: 1 addition & 1 deletion src/platform/win/gl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn find_wgl_pixel_format(
Ok(None) => {}
};

eprintln!("Warning: sRGB framebuffer not supported, falling back to non-sRGB");
crate::warn!("Warning: sRGB framebuffer not supported, falling back to non-sRGB");
format_attribs.set_without_srgb_ext();

match extra.choose_pixel_format_from_attribs(&format_attribs, dc) {
Expand Down
17 changes: 16 additions & 1 deletion src/platform/win/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ impl WindowHandle {
}
}

pub fn set_parent(&self, new_parent: ParentWindowHandle) -> Result<()> {
let Some(hwnd) = self.hwnd.get() else { return Ok(()) };

hwnd.set_parent(&new_parent.handle)?;

if !self.state.parented.get() {
self.state.parented.set(true);

hwnd.set_style(WindowStyle::parented())?;
}

Ok(())
}

#[inline]
pub fn handle_main_thread_callback(&self) {
// No-op
Expand Down Expand Up @@ -545,7 +559,8 @@ impl WindowHandle {
WindowStyle::embedded()
};
let dpi_ctx = DpiAwarenessContext::new(&extended_user_32)?;
let shared_state = WindowSharedState::new(window_size, extended_user_32.clone());
let shared_state =
WindowSharedState::new(window_size, extended_user_32.clone(), options.parent.is_some());

let initializer = {
let extended_user_32 = extended_user_32.clone();
Expand Down
6 changes: 5 additions & 1 deletion src/platform/win/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ impl WindowState {
}

pub struct WindowSharedState {
pub parented: Cell<bool>,
pub is_alive: Cell<bool>,
pub current_size: Cell<PhysicalSize<u32>>,
pub current_dpi: Cell<Option<Dpi>>, // None if Win32 HiDPI isn't supported
Expand All @@ -153,8 +154,11 @@ pub struct WindowSharedState {
}

impl WindowSharedState {
pub fn new(current_size: PhysicalSize<u32>, user32: ExtendedUser32) -> Rc<Self> {
pub fn new(
current_size: PhysicalSize<u32>, user32: ExtendedUser32, parented: bool,
) -> Rc<Self> {
Self {
parented: parented.into(),
is_alive: true.into(),
current_dpi: None.into(),
current_size: current_size.into(),
Expand Down
9 changes: 7 additions & 2 deletions src/platform/x11/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::result::Result;
use crate::host::HostMainThreadCaller;
use crate::platform::x11::error::FatalError;
use crate::platform::x11::window_thread::{
HostCallback, WindowThreadRequest, WindowThreadResponse, WindowThreadResponseMessage,
HostCallback, WindowThreadRequest, WindowThreadResponseMessage,
};
use crate::warn;
use crate::wrappers::xkbcommon::XkbcommonState;
Expand Down Expand Up @@ -156,7 +156,7 @@ impl EventLoop {
self.stop_now();
}
calloop::channel::Event::Msg(req) => match self.handle_request(req) {
Ok(()) => self.send_response(Ok(WindowThreadResponse::Ok)),
Ok(()) => self.send_response(Ok(())),
Err(e) => self.send_response(Err(e.to_string())),
},
}
Expand Down Expand Up @@ -199,6 +199,11 @@ impl EventLoop {

self.window.resize_immediately(new_physical_size, &*self.handler)?;

Ok(())
}
WindowThreadRequest::SetParent(new_parent) => {
self.window.xcb_window.reparent(Some(new_parent.window_id))?;

Ok(())
}
}
Expand Down
Loading