diff --git a/minigui_addons/webview.d b/minigui_addons/webview.d index a1b3c27..f74a3f7 100644 --- a/minigui_addons/webview.d +++ b/minigui_addons/webview.d @@ -138,149 +138,158 @@ class WebViewWidget_WV2 : WebViewWidgetBase { private bool initialized; - this(string url, void delegate(scope OpenNewWindowParams) openNewWindow, BrowserSettings settings, Widget parent) { - // FIXME: openNewWindow and openUrlInNewWindow - super(parent); - // that ctor sets containerWindow + private HRESULT initializeWithController(ICoreWebView2Controller controller_raw) { - Wv2App.useEnvironment((env) { - env.CreateCoreWebView2Controller(containerWindow.impl.hwnd, - callback!(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler)(delegate(error, controller_raw) { - if(error || controller_raw is null) - return error; + // need to keep this beyond the callback or we're doomed. + this.controller = RC!ICoreWebView2Controller(controller_raw); - // need to keep this beyond the callback or we're doomed. - controller = RC!ICoreWebView2Controller(controller_raw); + this.webview_window = controller.CoreWebView2; - webview_window = controller.CoreWebView2; + this.webview_window_ext_1 = this.webview_window.queryInterface!(ICoreWebView2_16); - webview_window_ext_1 = webview_window.queryInterface!(ICoreWebView2_16); + bool enableStatusBar = true; - bool enableStatusBar = true; + if(this.webview_window_ext_1) { + enableStatusBar = false; + this.webview_window_ext_1.add_StatusBarTextChanged!(typeof(this))((sender, args, this_) { + this_.status = toGC(&this_.webview_window_ext_1.raw.get_StatusBarText); + return S_OK; + }, this); - if(webview_window_ext_1) { - enableStatusBar = false; - webview_window_ext_1.add_StatusBarTextChanged((sender, args) { - this.status = toGC(&webview_window_ext_1.raw.get_StatusBarText); - return S_OK; - }); + webview_window_ext_1.add_FaviconChanged!(typeof(this))((sender, args, this_) { + this_.webview_window_ext_1.GetFavicon( + COREWEBVIEW2_FAVICON_IMAGE_FORMAT_PNG, + callback!(ICoreWebView2GetFaviconCompletedHandler, typeof(this_))(function(error, streamPtrConst, ctx2) { - webview_window_ext_1.add_FaviconChanged((sender, args) { - webview_window_ext_1.GetFavicon( - COREWEBVIEW2_FAVICON_IMAGE_FORMAT_PNG, - callback!(ICoreWebView2GetFaviconCompletedHandler)(delegate(error, streamPtrConst) { + auto streamPtr = cast(IStream) streamPtrConst; - auto streamPtr = cast(IStream) streamPtrConst; + ubyte[] buffer = new ubyte[](640); // most favicons are pretty small + enum growth_size = 1024; // and we'll grow linearly by the kilobyte + size_t at; - ubyte[] buffer = new ubyte[](640); // most favicons are pretty small - enum growth_size = 1024; // and we'll grow linearly by the kilobyte - size_t at; + more: + ULONG actuallyRead; + auto ret = streamPtr.Read(buffer.ptr + at, cast(UINT) (buffer.length - at), &actuallyRead); + if(ret == S_OK) { + // read completed, possibly more data pending + auto moreData = actuallyRead >= (buffer.length - at); - more: - ULONG actuallyRead; - auto ret = streamPtr.Read(buffer.ptr + at, cast(UINT) (buffer.length - at), &actuallyRead); - if(ret == S_OK) { - // read completed, possibly more data pending - auto moreData = actuallyRead >= (buffer.length - at); + at += actuallyRead; + if(moreData && (buffer.length - at < growth_size)) + buffer.length += growth_size; + goto more; + } else if(ret == S_FALSE) { + // end of file reached + at += actuallyRead; + buffer = buffer[0 .. at]; - at += actuallyRead; - if(moreData && (buffer.length - at < growth_size)) - buffer.length += growth_size; - goto more; - } else if(ret == S_FALSE) { - // end of file reached - at += actuallyRead; - buffer = buffer[0 .. at]; - - import arsd.png; - this.favicon = readPngFromBytes(buffer); - } else { - // other error - throw new ComException(ret); - } - - return S_OK; - }) - ); - - return S_OK; - }); - } - - webview_window.add_DocumentTitleChanged((sender, args) { - this.title = toGC(&sender.get_DocumentTitle); - return S_OK; - }); - - webview_window.add_NewWindowRequested((sender, args) { - // args.get_Uri - // args.get_IsUserInitiated - // args.put_NewWindow(); - - string url = toGC(&args.get_Uri); - int ret; - - WebViewWidget_WV2 widget; - - runInGuiThread({ - ret = 0; - - scope WebViewWidget delegate(Widget, BrowserSettings) accept = (parent, passed_settings) { - ret = 1; - if(parent !is null) { - auto widget = new WebViewWidget_WV2(url, openNewWindow, passed_settings, parent); - - return widget; - } - return null; - }; - openNewWindow(OpenNewWindowParams(url, accept)); - return; - }); - - if(ret) { - args.put_Handled(true); - // args.put_NewWindow(widget.webview_window.returnable); + import arsd.png; + ctx2.favicon = readPngFromBytes(buffer); + } else { + // other error + throw new ComException(ret); } return S_OK; + }, this_) + ); - }); + return S_OK; + }, this); + } - // add_HistoryChanged - // that's where CanGoBack and CanGoForward can be rechecked. + webview_window.add_DocumentTitleChanged!(typeof(this))((sender, args, this_) { + this_.title = toGC(&sender.get_DocumentTitle); + return S_OK; + }, this); - RC!ICoreWebView2Settings Settings = webview_window.Settings; - Settings.IsScriptEnabled = TRUE; - Settings.AreDefaultScriptDialogsEnabled = TRUE; - Settings.IsWebMessageEnabled = TRUE; - Settings.IsStatusBarEnabled = enableStatusBar; + webview_window.add_NewWindowRequested!(typeof(this))((sender, args, this_) { + // args.get_Uri + // args.get_IsUserInitiated + // args.put_NewWindow(); - auto ert = webview_window.add_NavigationStarting( - delegate (sender, args) { - this.url = toGC(&args.get_Uri); - return S_OK; - }); + string url = toGC(&args.get_Uri); + int ret; - RECT bounds; - GetClientRect(containerWindow.impl.hwnd, &bounds); - controller.Bounds = bounds; - //error = webview_window.Navigate("http://arsdnet.net/test.html"w.ptr); - //error = webview_window.NavigateToString("Hello"w.ptr); - //error = webview_window.Navigate("http://192.168.1.10/"w.ptr); + WebViewWidget_WV2 widget; - if(url !is null) { - WCharzBuffer bfr = WCharzBuffer(url); - webview_window.Navigate(bfr.ptr); + runInGuiThread({ + ret = 0; + + scope WebViewWidget delegate(Widget, BrowserSettings) accept = (parent, passed_settings) { + ret = 1; + if(parent !is null) { + auto widget = new WebViewWidget_WV2(url, this_.openNewWindow, passed_settings, parent); + + return widget; } - - controller.IsVisible = true; - - initialized = true; - - return S_OK; - })); + return null; + }; + this_.openNewWindow(OpenNewWindowParams(url, accept)); + return; }); + + if(ret) { + args.put_Handled(true); + // args.put_NewWindow(widget.webview_window.returnable); + } + + return S_OK; + + }, this); + + // add_HistoryChanged + // that's where CanGoBack and CanGoForward can be rechecked. + + RC!ICoreWebView2Settings Settings = this.webview_window.Settings; + Settings.IsScriptEnabled = TRUE; + Settings.AreDefaultScriptDialogsEnabled = TRUE; + Settings.IsWebMessageEnabled = TRUE; + Settings.IsStatusBarEnabled = enableStatusBar; + + auto ert = this.webview_window.add_NavigationStarting!(typeof(this))( + function (sender, args, this_) { + this_.url = toGC(&args.get_Uri); + return S_OK; + }, this); + + RECT bounds; + GetClientRect(this.containerWindow.impl.hwnd, &bounds); + controller.Bounds = bounds; + //error = webview_window.Navigate("http://arsdnet.net/test.html"w.ptr); + //error = webview_window.NavigateToString("Hello"w.ptr); + //error = webview_window.Navigate("http://192.168.1.10/"w.ptr); + + if(url !is null) { + WCharzBuffer bfr = WCharzBuffer(url); + this.webview_window.Navigate(bfr.ptr); + } + + controller.IsVisible = true; + + this.initialized = true; + + return S_OK; + } + + private void delegate(scope OpenNewWindowParams) openNewWindow; + + this(string url, void delegate(scope OpenNewWindowParams) openNewWindow, BrowserSettings settings, Widget parent) { + this.openNewWindow = openNewWindow; + super(parent); + // that ctor sets containerWindow + + this.url = url; + + Wv2App.useEnvironment((env) { + env.CreateCoreWebView2Controller(containerWindow.impl.hwnd, + callback!(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler, typeof(this))(function(error, controller_raw, ctx) { + if(error || controller_raw is null) + return error; + + return ctx.initializeWithController(controller_raw); + }, this)); + }); } override void registerMovementAdditionalWork() { diff --git a/webview.d b/webview.d index f9f1b36..503ace4 100644 --- a/webview.d +++ b/webview.d @@ -63,17 +63,31 @@ import core.atomic; //import std.stdio; -T callback(T)(typeof(&T.init.Invoke) dg) { - return new class T { +private template InvokerArgFor(T, Context) { + alias invoker = typeof(&T.init.Invoke); + static if(is(invoker fntype == delegate)) + static if(is(fntype Params == __parameters)) + alias InvokerArgFor = HRESULT function(Params, Context); + else + static assert(0); +} + +T callback(T, Context)(InvokerArgFor!(T, Context) dg, Context ctx) { + return new class(dg, ctx) T { extern(Windows): static if(is(typeof(T.init.Invoke) R == return)) static if(is(typeof(T.init.Invoke) P == __parameters)) override R Invoke(P _args_) { - return dg(_args_); + return dgMember(_args_, ctxMember); } - this() { + InvokerArgFor!(T, Context) dgMember; + Context ctxMember; + + this(typeof(dgMember) dg_, Context ctx_) { + this.dgMember = dg_; + this.ctxMember = ctx_; AddRef(); } @@ -238,10 +252,9 @@ mixin template ForwardMethod(string methodName) { static if(methodName.length > 4 && methodName[0 .. 4] == "add_") { static if(is(typeof(__traits(getMember, T, memberName)) Params == function)) alias Handler = Params[0]; - alias HandlerDg = typeof(&Handler.init.Invoke); - mixin(q{ EventRegistrationToken } ~ memberName ~ q{ (HandlerDg handler) { + mixin(q{ EventRegistrationToken } ~ memberName ~ q{ (Context)(InvokerArgFor!(Handler, Context) handler, Context ctx) { EventRegistrationToken token; - __traits(getMember, object, memberName)(callback!Handler(handler), &token); + __traits(getMember, object, memberName)(callback!(Handler, Context)(handler, ctx), &token); return token; }}); } else @@ -296,26 +309,26 @@ struct Wv2App { throw new Exception("CreateCoreWebView2EnvironmentWithOptions failed from WebView2Loader..."); auto result = func(null, null, null, - callback!(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler)( - delegate(error, env) { - initialized = true; - code = error; + callback!(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler, Wv2App*)( + function(error, env, this_) { + this_.initialized = true; + this_.code = error; if(error) return error; - webview_env = env; + this_.webview_env = env; auto len = pending.length; - foreach(item; pending) { - item(webview_env); + foreach(item; this_.pending) { + item(this_.webview_env); } - pending = pending[len .. $]; + this_.pending = this_.pending[len .. $]; return S_OK; } - ) + , &this) ); if(result != S_OK) {