Skip to content

Commit d54105b

Browse files
committed
Fix problems with navigation events that aren't generated by GtkWebKit.
(used lib: libwebkit2gtk-4.1-0 on linux Mint). The WebKit engine to apparently doesn't catch the navigations and does not produce navigation events, when something like "webui_bind(_webui_win, "", webui_event_handler);" is called. Although this should be expected behaviour. By implementing a handler for the GtkWebKit decision signal, this navigation event can still be generated. Signed-off-by: Hans Dijkema <hans@dijkewijk.nl>
1 parent 80f8976 commit d54105b

2 files changed

Lines changed: 142 additions & 2 deletions

File tree

include/webui.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,31 @@ WEBUI_EXPORT void webui_set_browser_folder(const char* path);
523523
*/
524524
WEBUI_EXPORT bool webui_set_default_root_folder(const char* path);
525525

526+
/**
527+
* @brief Set a callback function on the given window to allow navigations.
528+
* Must return false if navigation is not allowed, true, otherwise.
529+
*
530+
* A 'NULL' navigation handler will remove the current navigation_handler.
531+
*
532+
* NB. This currently works only for GtkWebKit WebView implementations.
533+
* Because GtkWebKit allways navigates, i.e. doesnt react to
534+
* webui_bind(_webui_win, "", webui_event_handler) which is supposed to
535+
* catch navigation requests.
536+
*
537+
* Also, although bind(win, "", evt_handler) does not work for GtkWebKit,
538+
* this implementation will always fire an event on navigation, unless
539+
* mayNavigate() returns true (which is the default, when the callback is not set).
540+
*
541+
* @example
542+
* bool mayNavigate(size_t window)
543+
* {
544+
* if (_just_called_show_with_url) { return true; }
545+
* else { return false; } // expect a navigation event to be handled
546+
* }
547+
*/
548+
WEBUI_EXPORT void webui_set_navigation_handler(size_t window, bool (*may_navigate_handler)(size_t window));
549+
550+
526551
/**
527552
* @brief Set a callback to catch the close event of the WebView window.
528553
* Must return `false` to prevent the close event, `true` otherwise.

src/webui.c

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
Canada.
99
*/
1010

11+
#define webui_log_debug printf
12+
1113
// 64Mb max dynamic memory allocation
1214
#define WEBUI_MAX_BUF (64000000)
1315

@@ -247,10 +249,18 @@ typedef struct webui_event_inf_t {
247249
typedef void *(*webkit_web_view_new_func)(void);
248250
typedef void (*webkit_web_view_load_uri_func)(void *, const char *);
249251
typedef const char *(*webkit_web_view_get_title_func)(void *);
252+
typedef void (*webkit_1ptr_arg_func)(void *);
253+
typedef int (*webkit_1ptr_arg_2int_func)(void *);
254+
typedef void *(*webkit_1ptr_arg_2ptr_func)(void *);
255+
typedef const char *(*webkit_1ptr_arg_2str_func)(void *);
250256
static webkit_web_view_new_func webkit_web_view_new = NULL;
251257
static webkit_web_view_load_uri_func webkit_web_view_load_uri = NULL;
252258
static webkit_web_view_get_title_func webkit_web_view_get_title = NULL;
253-
259+
static webkit_1ptr_arg_func webkit_policy_decision_ignore = NULL;
260+
static webkit_1ptr_arg_2int_func webkit_navigation_policy_decision_get_navigation_type = NULL;
261+
static webkit_1ptr_arg_2ptr_func webkit_navigation_policy_decision_get_request = NULL;
262+
static webkit_1ptr_arg_2str_func webkit_uri_request_get_uri = NULL;
263+
254264
typedef struct _webui_wv_linux_t {
255265
// Linux WebView
256266
void* gtk_win;
@@ -355,6 +365,7 @@ typedef struct _webui_window_t {
355365
int x;
356366
int y;
357367
bool position_set;
368+
bool (*may_navigate_handler)(size_t window);
358369
bool (*close_handler_wv)(size_t window);
359370
const void*(*files_handler)(const char* filename, int* length);
360371
const void*(*files_handler_window)(size_t window, const char* filename, int* length);
@@ -759,6 +770,21 @@ void webui_run(size_t window, const char* script) {
759770
_webui_send_all(win, 0, WEBUI_CMD_JS_QUICK, script, js_len);
760771
}
761772

773+
void webui_set_navigation_handler(size_t window, bool (*may_navigate_handler)(size_t window)) {
774+
#ifdef WEBUI_LOG
775+
webui_log_debug("[User]webui_set_navigation_handler(%zu, %p)", window, may_navigate_handler);
776+
#endif
777+
778+
// Dereference
779+
if (_webui_mutex_app_is_exit_now(WEBUI_MUTEX_GET_STATUS) || _webui.wins[window] == NULL)
780+
return;
781+
782+
_webui_window_t* win = _webui.wins[window];
783+
784+
// Set the navigation handler
785+
win->may_navigate_handler = may_navigate_handler;
786+
}
787+
762788
void webui_set_close_handler_wv(size_t window, bool(*close_handler)(size_t window)) {
763789

764790
// Initialization
@@ -11763,6 +11789,84 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1176311789
}
1176411790
}
1176511791

11792+
// Decision Event
11793+
#define WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION 0
11794+
#define WEBKIT_NAVIGATION_TYPE_LINK_CLICKED 0
11795+
#define WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED 1
11796+
#define WEBKIT_NAVIGATION_TYPE_BACK_FORWARD 2
11797+
#define WEBKIT_NAVIGATION_TYPE_RELOAD 3
11798+
#define WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED 4
11799+
#define WEBKIT_NAVIGATION_TYPE_OTHER 5
11800+
11801+
static bool _webui_wv_event_decision(void *widget, void *decision, int decision_type, void *user_data) {
11802+
switch(decision_type) {
11803+
case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
11804+
11805+
int navigation_type = webkit_navigation_policy_decision_get_navigation_type(decision);
11806+
bool intercept_navigation = false;
11807+
11808+
_webui_window_t* win = _webui_dereference_win_ptr(user_data);
11809+
if (win->may_navigate_handler) {
11810+
intercept_navigation = !(win->may_navigate_handler(win->num));
11811+
}
11812+
11813+
if (intercept_navigation) {
11814+
webkit_policy_decision_ignore(decision);
11815+
11816+
void *uri_request = webkit_navigation_policy_decision_get_request(decision);
11817+
const char *webkit_uri = webkit_uri_request_get_uri(uri_request);
11818+
11819+
size_t s = strlen(webkit_uri) + 1;
11820+
char *uri = (char *) _webui_malloc(s);
11821+
strncpy(uri, webkit_uri, s - 1);
11822+
uri[s] = '\0';
11823+
11824+
char buf[20];
11825+
snprintf(buf, 20, "%d", navigation_type);
11826+
size_t nt_s = strlen(buf) + 1;
11827+
char *type = (char *) _webui_malloc(nt_s);
11828+
strncpy(uri, buf, nt_s - 1);
11829+
uri[nt_s] = '\0';
11830+
11831+
webui_event_inf_t* event_inf = NULL;
11832+
size_t event_num = _webui_new_event_inf(win, &event_inf);
11833+
11834+
// TODO: Not sure how this works and if the right connection_id is taken.
11835+
int connection_id = 0;
11836+
// TODO: Not sure if this is the way to get the client.
11837+
struct mg_connection* client = win->single_client;
11838+
11839+
event_inf->client = client;
11840+
event_inf->connection_id = connection_id;
11841+
11842+
// Event Info Extras
11843+
event_inf->event_data[0] = uri;
11844+
event_inf->event_size[0] = strlen(uri);
11845+
event_inf->event_data[1] = type;
11846+
event_inf->event_size[1] = strlen(type);
11847+
11848+
_webui_window_event(
11849+
win, // Event -> Window
11850+
connection_id, // Event -> Client Unique ID
11851+
WEBUI_EVENT_NAVIGATION, // Event -> Type of this event
11852+
"", // Event -> HTML Element
11853+
event_num, // Event -> Event Number
11854+
_webui_client_get_id(win, client), // Event -> Client ID
11855+
_webui_get_cookies_full(client) // Event -> Full cookies
11856+
);
11857+
11858+
// Free event
11859+
_webui_free_event_inf(win, event_num);
11860+
11861+
// Return that this event is handled.
11862+
return true;
11863+
}
11864+
}
11865+
break;
11866+
}
11867+
return false;
11868+
}
11869+
1176611870
// Close Event
1176711871
static void _webui_wv_event_closed(void *widget, void *arg) {
1176811872
#ifdef WEBUI_LOG
@@ -12095,6 +12199,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1209512199
libwebkit, "webkit_web_view_load_uri");
1209612200
webkit_web_view_get_title = (webkit_web_view_get_title_func)dlsym(
1209712201
libwebkit, "webkit_web_view_get_title");
12202+
webkit_policy_decision_ignore = (webkit_1ptr_arg_func)dlsym(
12203+
libwebkit, "webkit_policy_decision_ignore");
12204+
webkit_navigation_policy_decision_get_navigation_type = (webkit_1ptr_arg_2int_func)dlsym(
12205+
libwebkit, "webkit_navigation_policy_decision_get_navigation_type");
12206+
webkit_navigation_policy_decision_get_request = (webkit_1ptr_arg_2ptr_func)dlsym(
12207+
libwebkit, "webkit_navigation_policy_decision_get_request");
12208+
webkit_uri_request_get_uri = (webkit_1ptr_arg_2str_func)dlsym(
12209+
libwebkit, "webkit_uri_request_get_uri");
1209812210

1209912211
// Check GTK
1210012212
if (
@@ -12119,7 +12231,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1211912231
}
1212012232

1212112233
// Check WebView
12122-
if (!webkit_web_view_new || !webkit_web_view_load_uri || !webkit_web_view_get_title) {
12234+
if (!webkit_web_view_new || !webkit_web_view_load_uri || !webkit_web_view_get_title ||
12235+
!webkit_policy_decision_ignore || !webkit_navigation_policy_decision_get_navigation_type ||
12236+
!webkit_navigation_policy_decision_get_request || !webkit_uri_request_get_uri
12237+
) {
1212312238
#ifdef WEBUI_LOG
1212412239
printf("[Core]\t\t_webui_load_gtk_and_webkit() -> WebKit symbol addresses failed\n");
1212512240
#endif

0 commit comments

Comments
 (0)