mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-01 03:02:28 +03:00
245 lines
8.6 KiB
C
245 lines
8.6 KiB
C
#include "tauri-gtk-webview.h"
|
|
#include "tauri.h"
|
|
|
|
static void external_message_received_cb(WebKitUserContentManager *m,
|
|
WebKitJavascriptResult *r,
|
|
gpointer arg) {
|
|
(void)m;
|
|
struct webview *w = (struct webview *)arg;
|
|
if (w->external_invoke_cb == NULL) {
|
|
return;
|
|
}
|
|
JSGlobalContextRef context = webkit_javascript_result_get_global_context(r);
|
|
JSValueRef value = webkit_javascript_result_get_value(r);
|
|
JSStringRef js = JSValueToStringCopy(context, value, NULL);
|
|
size_t n = JSStringGetMaximumUTF8CStringSize(js);
|
|
char *s = g_new(char, n);
|
|
JSStringGetUTF8CString(js, s, n);
|
|
w->external_invoke_cb(w, s);
|
|
JSStringRelease(js);
|
|
g_free(s);
|
|
}
|
|
|
|
static void webview_load_changed_cb(WebKitWebView *webview,
|
|
WebKitLoadEvent event, gpointer arg) {
|
|
(void)webview;
|
|
struct webview *w = (struct webview *)arg;
|
|
if (event == WEBKIT_LOAD_FINISHED) {
|
|
w->priv.ready = 1;
|
|
}
|
|
}
|
|
|
|
static void webview_destroy_cb(GtkWidget *widget, gpointer arg) {
|
|
(void)widget;
|
|
struct webview *w = (struct webview *)arg;
|
|
webview_terminate(w);
|
|
}
|
|
|
|
static gboolean webview_context_menu_cb(WebKitWebView *webview,
|
|
GtkWidget *default_menu,
|
|
WebKitHitTestResult *hit_test_result,
|
|
gboolean triggered_with_keyboard,
|
|
gpointer userdata) {
|
|
(void)webview;
|
|
(void)default_menu;
|
|
(void)hit_test_result;
|
|
(void)triggered_with_keyboard;
|
|
(void)userdata;
|
|
return TRUE;
|
|
}
|
|
|
|
WEBVIEW_API int webview_init(struct webview *w) {
|
|
if (gtk_init_check(0, NULL) == FALSE) {
|
|
return -1;
|
|
}
|
|
|
|
w->priv.ready = 0;
|
|
w->priv.should_exit = 0;
|
|
w->priv.queue = g_async_queue_new();
|
|
w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
|
|
|
|
if (w->resizable) {
|
|
gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width,
|
|
w->height);
|
|
} else {
|
|
gtk_widget_set_size_request(w->priv.window, w->width, w->height);
|
|
}
|
|
gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable);
|
|
gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER);
|
|
|
|
w->priv.scroller = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller);
|
|
|
|
WebKitUserContentManager *m = webkit_user_content_manager_new();
|
|
webkit_user_content_manager_register_script_message_handler(m, "external");
|
|
g_signal_connect(m, "script-message-received::external",
|
|
G_CALLBACK(external_message_received_cb), w);
|
|
|
|
w->priv.webview = webkit_web_view_new_with_user_content_manager(m);
|
|
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview),
|
|
webview_check_url(w->url));
|
|
g_signal_connect(G_OBJECT(w->priv.webview), "load-changed",
|
|
G_CALLBACK(webview_load_changed_cb), w);
|
|
gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview);
|
|
|
|
if (w->debug) {
|
|
WebKitSettings *settings =
|
|
webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview));
|
|
webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
|
|
webkit_settings_set_enable_developer_extras(settings, true);
|
|
} else {
|
|
g_signal_connect(G_OBJECT(w->priv.webview), "context-menu",
|
|
G_CALLBACK(webview_context_menu_cb), w);
|
|
}
|
|
|
|
gtk_widget_show_all(w->priv.window);
|
|
|
|
webkit_web_view_run_javascript(
|
|
WEBKIT_WEB_VIEW(w->priv.webview),
|
|
"window.external={invoke:function(x){"
|
|
"window.webkit.messageHandlers.external.postMessage(x);}}",
|
|
NULL, NULL, NULL);
|
|
|
|
g_signal_connect(G_OBJECT(w->priv.window), "destroy",
|
|
G_CALLBACK(webview_destroy_cb), w);
|
|
return 0;
|
|
}
|
|
|
|
WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
|
|
gtk_main_iteration_do(blocking);
|
|
return w->priv.should_exit;
|
|
}
|
|
|
|
WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
|
|
gtk_window_set_title(GTK_WINDOW(w->priv.window), title);
|
|
}
|
|
|
|
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
|
|
if (fullscreen) {
|
|
gtk_window_fullscreen(GTK_WINDOW(w->priv.window));
|
|
} else {
|
|
gtk_window_unfullscreen(GTK_WINDOW(w->priv.window));
|
|
}
|
|
}
|
|
|
|
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
|
|
uint8_t b, uint8_t a) {
|
|
GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0};
|
|
webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview),
|
|
&color);
|
|
}
|
|
|
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
|
enum webview_dialog_type dlgtype, int flags,
|
|
const char *title, const char *arg,
|
|
char *result, size_t resultsz) {
|
|
GtkWidget *dlg;
|
|
if (result != NULL) {
|
|
result[0] = '\0';
|
|
}
|
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
|
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
|
|
dlg = gtk_file_chooser_dialog_new(
|
|
title, GTK_WINDOW(w->priv.window),
|
|
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN
|
|
? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY
|
|
? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
|
|
: GTK_FILE_CHOOSER_ACTION_OPEN)
|
|
: GTK_FILE_CHOOSER_ACTION_SAVE),
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
|
GTK_RESPONSE_ACCEPT, NULL);
|
|
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
|
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
|
|
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
|
|
gint response = gtk_dialog_run(GTK_DIALOG(dlg));
|
|
if (response == GTK_RESPONSE_ACCEPT) {
|
|
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
|
|
g_strlcpy(result, filename, resultsz);
|
|
g_free(filename);
|
|
}
|
|
gtk_widget_destroy(dlg);
|
|
} else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
|
|
GtkMessageType type = GTK_MESSAGE_OTHER;
|
|
switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
|
|
case WEBVIEW_DIALOG_FLAG_INFO:
|
|
type = GTK_MESSAGE_INFO;
|
|
break;
|
|
case WEBVIEW_DIALOG_FLAG_WARNING:
|
|
type = GTK_MESSAGE_WARNING;
|
|
break;
|
|
case WEBVIEW_DIALOG_FLAG_ERROR:
|
|
type = GTK_MESSAGE_ERROR;
|
|
break;
|
|
}
|
|
dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL,
|
|
type, GTK_BUTTONS_OK, "%s", title);
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s",
|
|
arg);
|
|
gtk_dialog_run(GTK_DIALOG(dlg));
|
|
gtk_widget_destroy(dlg);
|
|
}
|
|
}
|
|
|
|
static void webview_eval_finished(GObject *object, GAsyncResult *result,
|
|
gpointer userdata) {
|
|
(void)object;
|
|
(void)result;
|
|
struct webview *w = (struct webview *)userdata;
|
|
w->priv.js_busy = 0;
|
|
}
|
|
|
|
WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
|
|
while (w->priv.ready == 0) {
|
|
g_main_context_iteration(NULL, TRUE);
|
|
}
|
|
w->priv.js_busy = 1;
|
|
webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL,
|
|
webview_eval_finished, w);
|
|
while (w->priv.js_busy) {
|
|
g_main_context_iteration(NULL, TRUE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static gboolean webview_dispatch_wrapper(gpointer userdata) {
|
|
struct webview *w = (struct webview *)userdata;
|
|
for (;;) {
|
|
struct webview_dispatch_arg *arg =
|
|
(struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue);
|
|
if (arg == NULL) {
|
|
break;
|
|
}
|
|
(arg->fn)(w, arg->arg);
|
|
g_free(arg);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
|
void *arg) {
|
|
struct webview_dispatch_arg *context =
|
|
(struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg, 1);
|
|
context->w = w;
|
|
context->arg = arg;
|
|
context->fn = fn;
|
|
g_async_queue_lock(w->priv.queue);
|
|
g_async_queue_push_unlocked(w->priv.queue, context);
|
|
if (g_async_queue_length_unlocked(w->priv.queue) == 1) {
|
|
gdk_threads_add_idle(webview_dispatch_wrapper, w);
|
|
}
|
|
g_async_queue_unlock(w->priv.queue);
|
|
}
|
|
|
|
WEBVIEW_API void webview_terminate(struct webview *w) {
|
|
w->priv.should_exit = 1;
|
|
}
|
|
|
|
WEBVIEW_API void webview_exit(struct webview *w) { (void)w; }
|
|
WEBVIEW_API void webview_print_log(const char *s) {
|
|
fprintf(stderr, "%s\n", s);
|
|
}
|