Mercurial > dwindows
changeset 2974:fffb4904c90b
Mac: Initial support for dw_html_javascript_add() and DW_SIGNAL_HTML_MESSAGE
for callbacks into native code. Code for iOS next...
Then GTK3/4, Windows and Android in that order.
Also implemented simple rawhtml tests in the test programs.
C++: Added HTML class support for the message callbacks.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Fri, 24 Mar 2023 11:39:24 +0000 |
parents | ac880987a2c4 |
children | ae4d6856b983 |
files | dw.h dw.hpp dwtest.c dwtestoo.cpp mac/dw.m |
diffstat | 5 files changed, 136 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/dw.h Tue Mar 21 00:41:25 2023 +0000 +++ b/dw.h Fri Mar 24 11:39:24 2023 +0000 @@ -108,6 +108,7 @@ #define DW_SIGNAL_TREE_EXPAND "tree-expand" #define DW_SIGNAL_HTML_CHANGED "html-changed" #define DW_SIGNAL_HTML_RESULT "html-result" +#define DW_SIGNAL_HTML_MESSAGE "html-message" /* status of menu items */ #define DW_MIS_ENABLED 1 @@ -1659,6 +1660,7 @@ _DW_EVENT_COLUMN_CLICK, /* Internal message for (container) column clicked */ _DW_EVENT_HTML_RESULT, /* Internal message for HTML javascript result */ _DW_EVENT_HTML_CHANGED, /* Internal message for HTML status changed */ + _DW_EVENT_HTML_MESSAGE, /* Internal message for HTML javascript message */ _DW_EVENT_MAX } _DW_EVENTS; #endif @@ -2235,6 +2237,7 @@ int API dw_html_raw(HWND hwnd, const char *string); int API dw_html_url(HWND hwnd, const char *url); int API dw_html_javascript_run(HWND hwnd, const char *script, void *scriptdata); +int API dw_html_javascript_add(HWND hwnd, const char *name); HWND API dw_html_new(unsigned long id); char * API dw_clipboard_get_text(void); void API dw_clipboard_set_text(const char *str, int len);
--- a/dw.hpp Tue Mar 21 00:41:25 2023 +0000 +++ b/dw.hpp Fri Mar 24 11:39:24 2023 +0000 @@ -1098,24 +1098,30 @@ class HTML : public Widget { private: - bool ChangedConnected, ResultConnected; + bool ChangedConnected, ResultConnected, MessageConnected; #ifdef DW_LAMBDA std::function<int(int, std::string)> _ConnectChanged; std::function<int(int, std::string, void *)> _ConnectResult; + std::function<int(std::string, std::string)> _ConnectMessage; #endif int (*_ConnectCChangedOld)(HTML *, int status, char *url); int (*_ConnectCResultOld)(HTML *, int status, char *result, void *scriptdata); + int (*_ConnectCMessageOld)(HTML *, char *name, char *message); int (*_ConnectChangedOld)(HTML *, int status, std::string url); int (*_ConnectResultOld)(HTML *, int status, std::string result, void *scriptdata); + int (*_ConnectMessageOld)(HTML *, std::string, std::string message); void Setup() { #ifdef DW_LAMBDA _ConnectChanged = 0; _ConnectResult = 0; + _ConnectMessage = 0; #endif _ConnectCChangedOld = 0; _ConnectCResultOld = 0; + _ConnectCMessageOld = 0; _ConnectChangedOld = 0; _ConnectResultOld = 0; + _ConnectMessageOld = 0; if(IsOverridden(HTML::OnChanged, this)) { dw_signal_connect(hwnd, DW_SIGNAL_HTML_CHANGED, DW_SIGNAL_FUNC(_OnChanged), this); ChangedConnected = true; @@ -1127,7 +1133,13 @@ ResultConnected = true; } else { ResultConnected = false; - } + } + if(IsOverridden(HTML::OnMessage, this)) { + dw_signal_connect(hwnd, DW_SIGNAL_HTML_MESSAGE, DW_SIGNAL_FUNC(_OnMessage), this); + MessageConnected = true; + } else { + MessageConnected = false; + } } static int _OnChanged(HWND window, int status, char *url, void *data) { HTML *classptr = reinterpret_cast<HTML *>(data); @@ -1153,6 +1165,19 @@ else if(classptr->_ConnectResultOld) return classptr->_ConnectResultOld(classptr, status, utf8string, scriptdata); return classptr->OnResult(status, utf8string, scriptdata); } + static int _OnMessage(HWND window, char *name, char *message, void *data) { + HTML *classptr = reinterpret_cast<HTML *>(data); + std::string utf8name = name ? std::string(name) : std::string(); + std::string utf8message = message ? std::string(message) : std::string(); + #ifdef DW_LAMBDA + if(classptr->_ConnectMessage) + return classptr->_ConnectMessage(utf8name, utf8message); + #endif + if(classptr->_ConnectCMessageOld) + return classptr->_ConnectCMessageOld(classptr, name, message); + else if(classptr->_ConnectMessageOld) + return classptr->_ConnectMessageOld(classptr, utf8name, utf8message); + return classptr->OnMessage(utf8name, utf8message); } public: // Constructors HTML(unsigned long id) { SetHWND(dw_html_new(id)); Setup(); } @@ -1162,10 +1187,12 @@ void Action(int action) { dw_html_action(hwnd, action); } int JavascriptRun(const char *script, void *scriptdata) { return dw_html_javascript_run(hwnd, script, scriptdata); } int JavascriptRun(const char *script) { return dw_html_javascript_run(hwnd, script, NULL); } + int JavascriptAdd(const char *name) { return dw_html_javascript_add(hwnd, name); } int Raw(const char *buffer) { return dw_html_raw(hwnd, buffer); } int URL(const char *url) { return dw_html_url(hwnd, url); } int JavascriptRun(std::string script, void *scriptdata) { return dw_html_javascript_run(hwnd, script.c_str(), scriptdata); } int JavascriptRun(std::string script) { return dw_html_javascript_run(hwnd, script.c_str(), NULL); } + int JavascriptAdd(std::string name) { return dw_html_javascript_add(hwnd, name.c_str()); } int Raw(std::string buffer) { return dw_html_raw(hwnd, buffer.c_str()); } int URL(std::string url) { return dw_html_url(hwnd, url.c_str()); } #ifdef DW_LAMBDA @@ -1220,6 +1247,32 @@ ResultConnected = true; } } +#ifdef DW_LAMBDA + void ConnectMessage(std::function<int(std::string, std::string)> userfunc) + { + _ConnectMessage = userfunc; + if(!MessageConnected) { + dw_signal_connect(hwnd, DW_SIGNAL_HTML_MESSAGE, DW_SIGNAL_FUNC(_OnMessage), this); + MessageConnected = true; + } + } +#endif + void ConnectMessage(int (*userfunc)(HTML *, char *, char *)) + { + _ConnectCMessageOld = userfunc; + if(!MessageConnected) { + dw_signal_connect(hwnd, DW_SIGNAL_HTML_MESSAGE, DW_SIGNAL_FUNC(_OnMessage), this); + MessageConnected = true; + } + } + void ConnectMessage(int (*userfunc)(HTML *, std::string, std::string)) + { + _ConnectMessageOld = userfunc; + if(!MessageConnected) { + dw_signal_connect(hwnd, DW_SIGNAL_HTML_MESSAGE, DW_SIGNAL_FUNC(_OnMessage), this); + MessageConnected = true; + } + } protected: // Our signal handler functions to be overriden... // If they are not overridden and an event is generated, remove the unused handler @@ -1233,6 +1286,11 @@ ResultConnected = false; return FALSE; }; + virtual int OnMessage(std::string name, std::string message) { + dw_signal_disconnect_by_name(hwnd, DW_SIGNAL_HTML_MESSAGE); + MessageConnected = false; + return FALSE; + }; }; // Base class for several widgets that allow text entry
--- a/dwtest.c Tue Mar 21 00:41:25 2023 +0000 +++ b/dwtest.c Fri Mar 24 11:39:24 2023 +0000 @@ -2080,6 +2080,14 @@ return FALSE; } +/* Handle web javascript message */ +int DWSIGNAL web_html_message(HWND html, char *name, char *message, void *data) +{ + dw_messagebox("Javascript Message", DW_MB_OK | DW_MB_INFORMATION, "Name: %s Message: %s", + name, message); + return TRUE; +} + void html_add(void) { rawhtml = dw_html_new(1001); @@ -2095,7 +2103,9 @@ dw_listbox_append(javascript, "window.navigator.userAgent;"); dw_box_pack_start(notebookbox7, rawhtml, 0, 100, TRUE, FALSE, 0); - dw_html_raw(rawhtml, "<html><body><center><h1>dwtest</h1></center></body></html>"); + dw_html_javascript_add(rawhtml, "test"); + dw_signal_connect(rawhtml, DW_SIGNAL_HTML_MESSAGE, DW_SIGNAL_FUNC(web_html_message), DW_POINTER(javascript)); + dw_html_raw(rawhtml, "<html><body><center><h1><a href=\"javascript:test('This is the message');\">dwtest</a></h1></center></body></html>"); html = dw_html_new(1002); dw_box_pack_start(notebookbox7, hbox, 0, 0, TRUE, FALSE, 0);
--- a/dwtestoo.cpp Tue Mar 21 00:41:25 2023 +0000 +++ b/dwtestoo.cpp Fri Mar 24 11:39:24 2023 +0000 @@ -1616,7 +1616,14 @@ javascript->Append("window.navigator.userAgent;"); notebookbox->PackStart(rawhtml, 0, 100, TRUE, FALSE, 0); - rawhtml->Raw("<html><body><center><h1>dwtest</h1></center></body></html>"); + rawhtml->JavascriptAdd("test"); + rawhtml->ConnectMessage([this](std::string name, std::string message) -> int + { + this->app->MessageBox("Javascript Message", DW_MB_OK | DW_MB_INFORMATION, + "Name: " + name + " Message: " + message); + return TRUE; + }); + rawhtml->Raw("<html><body><center><h1><a href=\"javascript:test('This is the message');\">dwtest</a></h1></center></body></html>"); DW::HTML *html = new DW::HTML(); notebookbox->PackStart(hbox, 0, 0, TRUE, FALSE, 0); @@ -1682,7 +1689,7 @@ return FALSE; }); - html->ConnectResult([this](int status, std::string result, void *script_data) + html->ConnectResult([this](int status, std::string result, void *script_data) -> int { this->app->MessageBox("Javascript Result", DW_MB_OK | (status ? DW_MB_ERROR : DW_MB_INFORMATION), result.size() ? result : "Javascript result is not a string value");
--- a/mac/dw.m Tue Mar 21 00:41:25 2023 +0000 +++ b/mac/dw.m Fri Mar 24 11:39:24 2023 +0000 @@ -592,9 +592,7 @@ } DWSignalList; /* List of signals */ -#define SIGNALMAX 19 - -static DWSignalList DWSignalTranslate[SIGNALMAX] = { +static DWSignalList DWSignalTranslate[] = { { _DW_EVENT_CONFIGURE, DW_SIGNAL_CONFIGURE }, { _DW_EVENT_KEY_PRESS, DW_SIGNAL_KEY_PRESS }, { _DW_EVENT_BUTTON_PRESS, DW_SIGNAL_BUTTON_PRESS }, @@ -613,7 +611,8 @@ { _DW_EVENT_TREE_EXPAND, DW_SIGNAL_TREE_EXPAND }, { _DW_EVENT_COLUMN_CLICK, DW_SIGNAL_COLUMN_CLICK }, { _DW_EVENT_HTML_RESULT, DW_SIGNAL_HTML_RESULT }, - { _DW_EVENT_HTML_CHANGED, DW_SIGNAL_HTML_CHANGED } + { _DW_EVENT_HTML_CHANGED, DW_SIGNAL_HTML_CHANGED }, + { _DW_EVENT_HTML_MESSAGE, DW_SIGNAL_HTML_MESSAGE } }; int _dw_event_handler1(id object, NSEvent *event, int message) @@ -877,7 +876,8 @@ void **params = (void **)event; NSString *result = params[0]; - return htmlresultfunc(handler->window, [result length] ? DW_ERROR_NONE : DW_ERROR_UNKNOWN, [result length] ? (char *)[result UTF8String] : NULL, params[1], handler->data); + return htmlresultfunc(handler->window, [result length] ? DW_ERROR_NONE : DW_ERROR_UNKNOWN, [result length] ? + (char *)[result UTF8String] : NULL, params[1], handler->data); } /* HTML changed event */ case _DW_EVENT_HTML_CHANGED: @@ -888,6 +888,15 @@ return htmlchangedfunc(handler->window, DW_POINTER_TO_INT(params[0]), (char *)[uri UTF8String], handler->data); } + /* HTML message event */ + case _DW_EVENT_HTML_MESSAGE: + { + int (* API htmlmessagefunc)(HWND, char *, char *, void *) = handler->signalfunction; + WKScriptMessage *message = (WKScriptMessage *)event; + + return htmlmessagefunc(handler->window, (char *)[[message name] UTF8String], [[message body] isKindOfClass:[NSString class]] ? + (char *)[[message body] UTF8String] : NULL, handler->data); + } } } return -1; @@ -1447,7 +1456,7 @@ * WKWebKit on intel 64 and the old WebKit on intel 32 bit and earlier. */ #if WK_API_ENABLED -@interface DWWebView : WKWebView <WKNavigationDelegate> +@interface DWWebView : WKWebView <WKNavigationDelegate, WKScriptMessageHandler> { void *userdata; } @@ -1457,6 +1466,7 @@ -(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation; -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation; -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation; +-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message; @end @implementation DWWebView : WKWebView @@ -1482,6 +1492,10 @@ void *params[2] = { DW_INT_TO_POINTER(DW_HTML_CHANGE_REDIRECT), [[self URL] absoluteString] }; _dw_event_handler(self, (NSEvent *)params, _DW_EVENT_HTML_CHANGED); } +-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message +{ + _dw_event_handler(self, (NSEvent *)message, _DW_EVENT_HTML_MESSAGE); +} -(void)dealloc { UserData *root = userdata; _dw_remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } @end #else @@ -3695,7 +3709,7 @@ { int z; - for(z=0;z<SIGNALMAX;z++) + for(z=0;z<(_DW_EVENT_MAX-1);z++) { if(strcasecmp(signame, DWSignalTranslate[z].name) == 0) return DWSignalTranslate[z].message; @@ -9468,6 +9482,38 @@ } /* + * Install a javascript function with name that can call native code. + * Parameters: + * handle: Handle to the HTML window. + * name: Javascript function name. + * Notes: A DW_SIGNAL_HTML_MESSAGE event will be raised with scriptdata. + * Returns: + * DW_ERROR_NONE (0) on success. + */ +int API dw_html_javascript_add(HWND handle, const char *name) +{ +#if WK_API_ENABLED + DWWebView *html = handle; + WKUserContentController *controller = [[html configuration] userContentController]; + + if(controller && name) + { + DW_LOCAL_POOL_IN; + /* Script to inject that will call the handler we are adding */ + NSString *script = [NSString stringWithFormat:@"function %s(body) {window.webkit.messageHandlers.%s.postMessage(body);}", + name, name]; + [controller addScriptMessageHandler:handle name:[NSString stringWithUTF8String:name]]; + [controller addUserScript:[[WKUserScript alloc] initWithSource:script + injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]]; + DW_LOCAL_POOL_OUT; + return DW_ERROR_NONE; + } +#endif + return DW_ERROR_UNKNOWN; +} + + +/* * Create a new HTML window (widget) to be packed. * Not available under OS/2, eCS * Parameters: