Created
May 22, 2021 11:32
-
-
Save kayabaNerve/607992beb81f918d9362d8a470fdbddf to your computer and use it in GitHub Desktop.
Linux-only mc_wry which allows handling the display server being accessible.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate libc; | |
use std::{ | |
ptr, | |
mem, | |
os::raw::c_char, | |
ffi::{CStr, CString} | |
}; | |
use serde_json; | |
use gtk; | |
use wry::{ | |
application::{ | |
event::Event, | |
event_loop::{ControlFlow, EventLoop}, | |
window::{WindowBuilder, Window}, | |
}, | |
webview::{self, WebViewBuilder, WebView} | |
}; | |
pub struct Bundle { | |
event_loop: EventLoop<()>, | |
// Stored so the Window doesn't close immediately; allows closing later via dropping this | |
#[allow(dead_code)] | |
webview: WebView | |
} | |
#[repr(C)] | |
pub struct BundleOuter { | |
valid: bool, | |
bundle: Box<Bundle> | |
} | |
#[repr(C)] | |
pub struct RpcRequest { | |
rpc_method: *const c_char, | |
params: *const c_char | |
} | |
fn create_bundle<F: Fn(&Window, webview::RpcRequest) -> Option<webview::RpcResponse> + 'static>( | |
title: &str, | |
url: &str, | |
handler: F | |
) -> wry::Result<Bundle> { | |
//Make sure WebView is available. | |
webview::webview_version()?; | |
match gtk::init() { | |
Err(e) => Err(wry::Error::GlibBoolError(e)), | |
Ok(_) => { | |
let event_loop: EventLoop<()> = EventLoop::new(); | |
let window: Window = WindowBuilder::new() | |
.with_title(title) | |
.build(&event_loop)?; | |
let webview: WebView = WebViewBuilder::new(window)? | |
.with_file_drop_handler(|_, _| true) | |
.with_rpc_handler(handler) | |
.with_url(url)? | |
.build()?; | |
Ok( | |
Bundle { | |
event_loop, | |
webview | |
} | |
) | |
} | |
} | |
} | |
#[no_mangle] | |
pub unsafe extern "C" fn new_webview( | |
title: *const c_char, | |
url: *const c_char, | |
handler: extern "C" fn( | |
request: RpcRequest | |
) -> *const c_char | |
) -> BundleOuter { | |
match create_bundle( | |
CStr::from_ptr(title).to_str().unwrap(), | |
CStr::from_ptr(url).to_str().unwrap(), | |
move |_, request| { | |
let method: CString = CString::new(request.method.as_str()).unwrap(); | |
let params: CString = CString::new(request.params.unwrap().to_string()).unwrap(); | |
Some( | |
webview::RpcResponse::new_result( | |
request.id, | |
Some( | |
serde_json::from_str( | |
CStr::from_ptr( | |
handler( | |
RpcRequest { | |
rpc_method: method.as_ptr(), | |
params: params.as_ptr() | |
} | |
) | |
).to_str().unwrap() | |
).unwrap() | |
) | |
) | |
) | |
} | |
) { | |
Ok(bundle) => BundleOuter { | |
valid: true, | |
bundle: Box::new(bundle) | |
}, | |
Err(_) => BundleOuter { | |
valid: false, | |
bundle: Box::<Bundle>::from_raw(1 as *mut Bundle) | |
} | |
} | |
} | |
fn run( | |
event_loop: EventLoop<()> | |
) -> ! { | |
event_loop.run(move |event, _, control_flow| { | |
*control_flow = ControlFlow::Wait; | |
match event { | |
Event::UserEvent(_) => *control_flow = ControlFlow::Exit, | |
_ => {} | |
} | |
}) | |
} | |
#[no_mangle] | |
pub unsafe extern "C" fn webview_run( | |
bundle: BundleOuter | |
) { | |
run(bundle.bundle.event_loop); | |
} | |
/* | |
fn terminate( | |
proxy: EventLoopProxy<()> | |
) -> ! { | |
// This SHOULD properly close the event loop and that will call exit on its own | |
// That said, Rust panics when we do this, claiming it hit unreachable code | |
// A pure Rust version of this model (foreign thread sent event to trigger quit) worked without issue though | |
// So there's some FFI issue. Because of that, terminate solely closes the window (see below), leaving the event loop running | |
proxy.send_event(()).unwrap(); | |
} | |
*/ | |
#[no_mangle] | |
pub unsafe extern "C" fn webview_terminate( | |
bundle: BundleOuter | |
) { | |
mem::drop(bundle.bundle); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment