Wrap an external app to send messages to it
Opened this issue · 0 comments
Is it possible for an extension to an external app to control windows attached to an external window received from such app (so there is no cacao-created App
, and the main Window
is created from an external pointer)?
"Architecture":
- external app with lua extensions (outside of my control)
- lua extension
- Rust library using your framework that attaches its own modal
Window
chiled to the main app'sWindow
parent
I'd like to show some modal windows driven by the extension, there is a Swift tutorial on how to do that, but that tutorial relies on the fact that the main window parent is available to the extension-generated view, so there is a simple way to close the modal
private func closeWindow() {
guard let sheetWindow = view.window else { return }
sheetWindow.sheetParent?.endSheet(sheetWindow)
}
However, your library doesn't have this OO relationship and instead of references uses message passing, which are driven from the top-level App
. But I don't have access to the app.
So what would be the best way to be able to close a modal attached to the main Window?
- Add some extra method to the the external app that I could call to pass messages to the main Window? (is it possible?)
- Try to somehow overcome the circular reference and store a reference to the
Window
in the modal so thatWinDelegate
on_cancel
event can ask the main window to close the sheet? - create a new channel passing messages?
- something much simpler and obvious I've missed?
- so far I'm using a static thread-local window manager which can then be used inside modals
thread_local! {pub static WM:LazyCell<WinMgr> = LazyCell::new(|| {WinMgr::default()});}
#[derive(Default)] pub struct WinMgr {
pub appxt:RwLock<Option<Window>>,
pub modal:RwLock<Option<Window<MyModalWin>>>,}
A bit more detailed description of what I'm currently doing:
The app allows the lua extension to send a pointer to the Window to the Rust library:
LightUserData, equivalent to an unmanaged raw pointer
The Swift way to convert it to a window object is
nswin = Unmanaged<NSWindow>.fromOpaque(nsWindowPtr).takeUnretainedValue();
In Rust I get *mut c_void
and convert it to cacao's Window
like so:
- Convert pointer to ShareId
fn get_win_id_objc(nswin_lua:&LuaLightUserData) -> Result<ShareId<Object>> {
let ptr_r:*mut c_void = nswin_lua.0;
if ptr_r.is_null() {return Err(anyhow!("err"))}
let ptr_objc:id = ptr_r.cast(); //type id = *mut Object;
let win_id_objc:ShareId<Object> = unsafe{ ShareId::from_ptr(ptr_objc) };
Ok(win_id_objc)
}
let win_id_objc:ShareId<Object> = get_win_id_objc(&nswin_lua)?; //nswin_lua comes from the app API
- Create cacao's Window
let win_marta:Window = Window {objc:win_id_objc, delegate:None};
So far so good (unless there is some unsound pointer conversion), I can now use this Window
to open a modal begin_sheet
But I can't close it :( since there is no message passing mechanism due to the fact that I don't create an App
, and since the modal is the child of Window
, I can't really get a reference to it either due to cyclical depndency