mirror of
https://github.com/tauri-apps/web-view.git
synced 2026-02-04 02:11:18 +01:00
Allow for graceful Exit (#107)
* First pass at graceful exit * Working macos unified exit * fix example html to work with IE * terminate > exit * unified edge, I think * update gtk c impl * tag terminate as depricated * fix old fn name * remove OleUninitialize from edge * remove queue_close * remove terminate * fix typo in edge cpp file * inspect return value of graceful exit example * actually create the variable inspected * make example run a little faster * Adjust cocoa webveiw_exit * add back missing method on edge * lots of pinting * fix printf arg * better even debug printing * clean up debugging stuff * remove some unneeded changes * slow down example * fix view title * add comment about posting the event to the application on close Closes #105 Fixes #52
This commit is contained in:
committed by
Richard Hozák
parent
d3ba96f03e
commit
b664974c1b
@@ -27,7 +27,7 @@ fn main() -> WVResult {
|
||||
.warning("Warning", "You didn't choose a file."),
|
||||
}?,
|
||||
"exit" => {
|
||||
webview.terminate();
|
||||
webview.exit();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
32
examples/graceful_exit.rs
Normal file
32
examples/graceful_exit.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
extern crate web_view;
|
||||
|
||||
use web_view::*;
|
||||
|
||||
fn main() {
|
||||
let res = web_view::builder()
|
||||
.title("Graceful Exit Example")
|
||||
.content(Content::Html(include_str!("graceful_exit/index.html")))
|
||||
.size(800, 600)
|
||||
.resizable(true)
|
||||
.debug(true)
|
||||
.user_data(0)
|
||||
.invoke_handler(invoke_handler)
|
||||
.run()
|
||||
.unwrap();
|
||||
println!("res: {:?}", res)
|
||||
}
|
||||
|
||||
fn invoke_handler(wv: &mut WebView<usize>, arg: &str) -> WVResult {
|
||||
if arg == "init" {
|
||||
wv.eval("init()")?;
|
||||
} else if arg == "update" {
|
||||
*wv.user_data_mut() += 1;
|
||||
let js = format!("setCurrentCount({})", wv.user_data());
|
||||
wv.eval(&js)?;
|
||||
} else if arg == "exit" {
|
||||
println!("exiting!");
|
||||
wv.exit();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
43
examples/graceful_exit/index.html
Normal file
43
examples/graceful_exit/index.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<style>
|
||||
#counter-message.preload {
|
||||
display: none;
|
||||
}
|
||||
#counter-message {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="counter-message" class="preload"></h1>
|
||||
<script>
|
||||
var t;
|
||||
function init() {
|
||||
var h1 = document.getElementById('counter-message');
|
||||
h1.setAttribute('class', '');
|
||||
setCurrentCount(0);
|
||||
t = setTimeout(tick, 500);
|
||||
}
|
||||
|
||||
function tick() {
|
||||
window.external.invoke('update');
|
||||
t = setTimeout(tick, 500);
|
||||
}
|
||||
|
||||
function setCurrentCount(count) {
|
||||
if (count > 10) {
|
||||
return window.external.invoke('exit');
|
||||
}
|
||||
var h1 = document.getElementById('counter-message');
|
||||
var rem = 11 - count;
|
||||
var suffix = rem < 2 ? ' second' : ' seconds';
|
||||
h1.innerText = 'Exiting in ' + rem + suffix;
|
||||
document.body.appendChild(h1);
|
||||
}
|
||||
external.invoke('init');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,7 +29,7 @@ fn main() {
|
||||
render(webview, *counter)?;
|
||||
}
|
||||
"exit" => {
|
||||
webview.terminate();
|
||||
webview.exit();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
10
src/lib.rs
10
src/lib.rs
@@ -29,6 +29,7 @@ mod color;
|
||||
mod dialog;
|
||||
mod error;
|
||||
mod escape;
|
||||
|
||||
pub use color::Color;
|
||||
pub use dialog::DialogBuilder;
|
||||
pub use error::{CustomError, Error, WVResult};
|
||||
@@ -347,9 +348,14 @@ impl<'a, T> WebView<'a, T> {
|
||||
&mut self.user_data_wrapper_mut().inner
|
||||
}
|
||||
|
||||
/// Forces the `WebView` instance to end, without dropping.
|
||||
#[deprecated(note = "Please use exit instead")]
|
||||
pub fn terminate(&mut self) {
|
||||
unsafe { webview_terminate(self.inner) }
|
||||
self.exit();
|
||||
}
|
||||
|
||||
/// Gracefully exits the webview
|
||||
pub fn exit(&mut self) {
|
||||
unsafe { webview_exit(self.inner) }
|
||||
}
|
||||
|
||||
/// Executes the provided string as JavaScript code within the `WebView` instance.
|
||||
|
||||
@@ -37,7 +37,6 @@ extern {
|
||||
pub fn webview_free(this: *mut CWebView);
|
||||
pub fn webview_new(title: *const c_char, url: *const c_char, width: c_int, height: c_int, resizable: c_int, debug: c_int, external_invoke_cb: Option<ErasedExternalInvokeFn>, userdata: *mut c_void) -> *mut CWebView;
|
||||
pub fn webview_loop(this: *mut CWebView, blocking: c_int) -> c_int;
|
||||
pub fn webview_terminate(this: *mut CWebView);
|
||||
pub fn webview_exit(this: *mut CWebView);
|
||||
pub fn webview_get_user_data(this: *mut CWebView) -> *mut c_void;
|
||||
pub fn webview_dispatch(this: *mut CWebView, f: Option<ErasedDispatchFn>, arg: *mut c_void);
|
||||
|
||||
@@ -40,7 +40,6 @@ WEBVIEW_API void webview_dialog(webview_t w,
|
||||
char *result, size_t resultsz);
|
||||
WEBVIEW_API void webview_dispatch(webview_t w, webview_dispatch_fn fn,
|
||||
void *arg);
|
||||
WEBVIEW_API void webview_terminate(webview_t w);
|
||||
WEBVIEW_API void webview_exit(webview_t w);
|
||||
WEBVIEW_API void webview_debug(const char *format, ...);
|
||||
WEBVIEW_API void webview_print_log(const char *s);
|
||||
|
||||
@@ -71,6 +71,7 @@ WEBVIEW_API webview_t webview_new(const char* title, const char* url, int width,
|
||||
#define WKNavigationResponsePolicyAllow 1
|
||||
#define WKUserScriptInjectionTimeAtDocumentStart 0
|
||||
#define NSApplicationActivationPolicyRegular 0
|
||||
#define NSApplicationDefinedEvent 15
|
||||
|
||||
static id get_nsstring(const char *c_str) {
|
||||
return objc_msgSend((id)objc_getClass("NSString"),
|
||||
@@ -88,9 +89,39 @@ static id create_menu_item(id title, const char *action, const char *key) {
|
||||
}
|
||||
|
||||
static void webview_window_will_close(id self, SEL cmd, id notification) {
|
||||
struct cocoa_webview *w =
|
||||
struct cocoa_webview *wv =
|
||||
(struct cocoa_webview *)objc_getAssociatedObject(self, "webview");
|
||||
webview_terminate(w);
|
||||
wv->priv.should_exit = 1;
|
||||
/***
|
||||
Since by default for `webview_loop` is set to be blocking
|
||||
we need to somehow signal the application that our
|
||||
state has changed. The activity in the `invoke_handler` does
|
||||
not interact with the `webview_loop` at all. This means that
|
||||
the `exit` wouldn't be recognized by the application until
|
||||
another event occurs like mouse movement or a key press.
|
||||
To enable the invoke_handler to notify the application
|
||||
correctly we need to send a custom event to the application.
|
||||
We are going to first create an event with the type
|
||||
NSApplicationDefined, and zero for all the other properties.
|
||||
***/
|
||||
id event = objc_msgSend((id)objc_getClass("NSEvent"),
|
||||
sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
|
||||
NSApplicationDefinedEvent,
|
||||
(id)objc_getClass("NSZeroPoint"),
|
||||
0, 0.0, 0, NULL, 0, 0, 0);
|
||||
id app = objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication"));
|
||||
/***
|
||||
With a custom event crated and a pointer to the sharedApplication
|
||||
we can now send the event. We need to make sure it get's queued as
|
||||
early as possible, so we will set the argument atStart to
|
||||
the NSDate distantPast constructor. This will trigger a noop
|
||||
event on the application allowing the `webview_loop` to continue
|
||||
its current iteration.
|
||||
***/
|
||||
objc_msgSend(app, sel_registerName("postEvent:atStart:"), event,
|
||||
objc_msgSend((id)objc_getClass("NSDate"),
|
||||
sel_registerName("distantPast")));
|
||||
}
|
||||
|
||||
static void webview_external_invoke(id self, SEL cmd, id contentController,
|
||||
@@ -373,7 +404,7 @@ WEBVIEW_API int webview_init(webview_t w) {
|
||||
objc_msgSend(wv->priv.webview, sel_registerName("setUIDelegate:"), uiDel);
|
||||
objc_msgSend(wv->priv.webview, sel_registerName("setNavigationDelegate:"),
|
||||
navDel);
|
||||
|
||||
|
||||
id nsURL = objc_msgSend((id)objc_getClass("NSURL"),
|
||||
sel_registerName("URLWithString:"),
|
||||
get_nsstring(webview_check_url(wv->url)));
|
||||
@@ -463,10 +494,10 @@ WEBVIEW_API int webview_loop(webview_t w, int blocking) {
|
||||
sel_registerName("distantFuture"))
|
||||
: objc_msgSend((id)objc_getClass("NSDate"),
|
||||
sel_registerName("distantPast")));
|
||||
|
||||
id app = objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication"));
|
||||
id event = objc_msgSend(
|
||||
objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
app,
|
||||
sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
||||
ULONG_MAX, until,
|
||||
objc_msgSend((id)objc_getClass("NSString"),
|
||||
@@ -479,7 +510,6 @@ WEBVIEW_API int webview_loop(webview_t w, int blocking) {
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("sendEvent:"), event);
|
||||
}
|
||||
|
||||
return wv->priv.should_exit;
|
||||
}
|
||||
|
||||
@@ -635,16 +665,10 @@ WEBVIEW_API void webview_dispatch(webview_t w, webview_dispatch_fn fn,
|
||||
dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_terminate(webview_t w) {
|
||||
struct cocoa_webview* wv = (struct cocoa_webview*)w;
|
||||
wv->priv.should_exit = 1;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_exit(webview_t w) {
|
||||
struct cocoa_webview* wv = (struct cocoa_webview*)w;
|
||||
id app = objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication"));
|
||||
objc_msgSend(app, sel_registerName("terminate:"), app);
|
||||
wv->external_invoke_cb = NULL;
|
||||
objc_msgSend(wv->priv.window, sel_registerName("close"));
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_print_log(const char *s) { printf("%s\n", s); }
|
||||
WEBVIEW_API void webview_print_log(const char *s) { printf("%s\n", s); }
|
||||
|
||||
@@ -146,8 +146,7 @@ public:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void terminate() { PostQuitMessage(0); }
|
||||
void exit() { PostQuitMessage(0); }
|
||||
void dispatch(dispatch_fn_t f)
|
||||
{
|
||||
PostThreadMessage(m_main_thread, WM_APP, 0, (LPARAM) new dispatch_fn_t(f));
|
||||
@@ -242,7 +241,7 @@ LRESULT CALLBACK WebviewWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
w->terminate();
|
||||
w->exit();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wp, lp);
|
||||
@@ -312,8 +311,7 @@ public:
|
||||
L"eval", single_threaded_vector<hstring>({ winrt::to_hstring(js) }));
|
||||
}
|
||||
|
||||
void terminate() {
|
||||
browser_window::terminate();
|
||||
void exit() {
|
||||
m_webview.Close();
|
||||
}
|
||||
|
||||
@@ -584,14 +582,10 @@ WEBVIEW_API void webview_dispatch(webview_t w, webview_dispatch_fn fn,
|
||||
static_cast<webview::webview*>(w)->dispatch([=]() { fn(w, arg); });
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_terminate(webview_t w)
|
||||
{
|
||||
static_cast<webview::webview*>(w)->terminate();
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_exit(webview_t w)
|
||||
{
|
||||
webview_terminate(w);
|
||||
webview::webview* wv = static_cast<webview::webview*>(w);
|
||||
DestroyWindow(wv->m_window);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_debug(const char *format, ...)
|
||||
|
||||
@@ -83,7 +83,7 @@ static void webview_load_changed_cb(WebKitWebView *webview,
|
||||
|
||||
static void webview_destroy_cb(GtkWidget *widget, gpointer arg) {
|
||||
(void)widget;
|
||||
webview_terminate((webview_t)arg);
|
||||
webview_exit((webview_t)arg);
|
||||
}
|
||||
|
||||
static gboolean webview_context_menu_cb(WebKitWebView *webview,
|
||||
@@ -298,12 +298,10 @@ WEBVIEW_API void webview_dispatch(webview_t w, webview_dispatch_fn fn,
|
||||
g_async_queue_unlock(wv->priv.queue);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_terminate(webview_t w) {
|
||||
WEBVIEW_API void webview_exit(webview_t w) {
|
||||
struct gtk_webview *wv = (struct webview *)w;
|
||||
wv->priv.should_exit = 1;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_exit(webview_t w) { (void)w; }
|
||||
WEBVIEW_API void webview_print_log(const char *s) {
|
||||
fprintf(stderr, "%s\n", s);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user