Skip to content
This repository was archived by the owner on Jun 5, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/WebWindow.Native/Exports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,9 @@ extern "C"
{
instance->SetIconFile(filename);
}

EXPORTED void WebWindow_SetUriChangeCallback(WebWindow* instance, UriChangeCallback callback)
{
instance->SetUriChangeCallback(callback);
}
}
16 changes: 16 additions & 0 deletions src/WebWindow.Native/WebWindow.Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ void HandleWebMessage(WebKitUserContentManager* contentManager, WebKitJavascript
webkit_javascript_result_unref(jsResult);
}

void HandleUriChange(GObject* object, WebKitLoadEvent event, gpointer user_data)
{
WebKitWebView *web_view;

const gchar *uri;

if (event == WEBKIT_LOAD_FINISHED) {
web_view = WEBKIT_WEB_VIEW(object);
uri = webkit_web_view_get_uri(web_view);

UriChangeCallback callback = (UriChangeCallback)user_data;
callback(AutoString(uri));
}
}

void WebWindow::Show()
{
if (!_webview)
Expand All @@ -99,6 +114,7 @@ void WebWindow::Show()

g_signal_connect(contentManager, "script-message-received::webwindowinterop",
G_CALLBACK(HandleWebMessage), (void*)_webMessageReceivedCallback);
g_signal_connect(_webview, "load-changed", G_CALLBACK(HandleUriChange), (void*)_uriChangeCallback);
webkit_user_content_manager_register_script_message_handler(contentManager, "webwindowinterop");
}

Expand Down
13 changes: 13 additions & 0 deletions src/WebWindow.Native/WebWindow.Mac.NavigationDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#include "WebWindow.h"

typedef void (*UriChangedCallback) (char* message);

@interface MyNavigationDelegate : NSObject <WKNavigationDelegate> {
@public
NSWindow * window;
WebWindow * webWindow;
UriChangedCallback uriChangedCallback;
}
@end
26 changes: 26 additions & 0 deletions src/WebWindow.Native/WebWindow.Mac.NavigationDelegate.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#import "WebWindow.Mac.NavigationDelegate.h"

@implementation MyNavigationDelegate : NSObject

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
{
[self callUriChangedCallback:webView.URL.absoluteString];
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;
{
[self callUriChangedCallback:webView.URL.absoluteString];
}

- (void)webView:(WKWebView *)webView
didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
{
[self callUriChangedCallback:webView.URL.absoluteString];
}

- (void) callUriChangedCallback: (NSString *) uri;
{
char* writableUri = (char*)[uri UTF8String];
uriChangedCallback(writableUri);
}
@end
11 changes: 9 additions & 2 deletions src/WebWindow.Native/WebWindow.Mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import "WebWindow.Mac.AppDelegate.h"
#import "WebWindow.Mac.UiDelegate.h"
#import "WebWindow.Mac.UrlSchemeHandler.h"
#import "WebWindow.Mac.NavigationDelegate.h"
#include <cstdio>
#include <map>
#import <Cocoa/Cocoa.h>
Expand Down Expand Up @@ -69,6 +70,8 @@
MyUiDelegate *uiDelegate = [[[MyUiDelegate alloc] init] autorelease];
uiDelegate->webWindow = this;

MyNavigationDelegate *navDelegate = [[[MyNavigationDelegate alloc] init] autorelease];

NSString *initScriptSource = @"window.__receiveMessageCallbacks = [];"
"window.__dispatchMessageCallback = function(message) {"
" window.__receiveMessageCallbacks.forEach(function(callback) { callback(message); });"
Expand All @@ -92,13 +95,17 @@
[webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[window.contentView addSubview:webView];
[window.contentView setAutoresizesSubviews:YES];

uiDelegate->window = window;
webView.UIDelegate = uiDelegate;

uiDelegate->webMessageReceivedCallback = _webMessageReceivedCallback;
[userContentController addScriptMessageHandler:uiDelegate name:@"webwindowinterop"];

navDelegate->window = window;
navDelegate->webWindow = this;
navDelegate->uriChangedCallback = _uriChangeCallback;

webView.navigationDelegate = navDelegate;

// TODO: Remove these observers when the window is closed
[[NSNotificationCenter defaultCenter] addObserver:uiDelegate selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:uiDelegate selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
Expand Down
4 changes: 4 additions & 0 deletions src/WebWindow.Native/WebWindow.Native.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,14 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="WebWindow.h" />
<ClInclude Include="WebWindow.Mac.NavigationDelegate.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="WebWindow.Mac.NavigationDelegate.mm" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Web.WebView2.0.8.270\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\packages\Microsoft.Web.WebView2.0.8.270\build\native\Microsoft.Web.WebView2.targets')" />
Expand Down
14 changes: 13 additions & 1 deletion src/WebWindow.Native/WebWindow.Windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,19 @@ void WebWindow::AttachWebView()
Settings->put_IsScriptEnabled(TRUE);
Settings->put_AreDefaultScriptDialogsEnabled(TRUE);
Settings->put_IsWebMessageEnabled(TRUE);

// Add a navigation change event handler
EventRegistrationToken token;
_webviewWindow->add_NavigationStarting(Callback<IWebView2NavigationStartingEventHandler>(
[this](IWebView2WebView* webview, IWebView2NavigationStartingEventArgs * args) -> HRESULT
{
PWSTR uri;
args->get_Uri(&uri);
_uriChangeCallback(uri);
CoTaskMemFree(uri);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CoTaskMemFree comes from https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/gettingstarted#step-4---navigation-events

Direction needed on whether it should be removed or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using wil::unique_cotaskmem_string? It is just like unique_ptr and CoTaskMemFree will be called automatically.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

return S_OK;
}
).Get(), &token);

// Register interop APIs
EventRegistrationToken webMessageToken;
_webviewWindow->AddScriptToExecuteOnDocumentCreated(L"window.external = { sendMessage: function(message) { window.chrome.webview.postMessage(message); }, receiveMessage: function(callback) { window.chrome.webview.addEventListener(\'message\', function(e) { callback(e.data); }); } };", nullptr);
Expand Down
4 changes: 4 additions & 0 deletions src/WebWindow.Native/WebWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ typedef void* (*WebResourceRequestedCallback)(AutoString url, int* outNumBytes,
typedef int (*GetAllMonitorsCallback)(const Monitor* monitor);
typedef void (*ResizedCallback)(int width, int height);
typedef void (*MovedCallback)(int x, int y);
typedef void (*UriChangeCallback)(AutoString url);

class WebWindow
{
private:
WebMessageReceivedCallback _webMessageReceivedCallback;
MovedCallback _movedCallback;
ResizedCallback _resizedCallback;
UriChangeCallback _uriChangeCallback;
#ifdef _WIN32
static HINSTANCE _hInstance;
HWND _hWnd;
Expand Down Expand Up @@ -87,6 +89,8 @@ class WebWindow
void SetPosition(int x, int y);
void SetMovedCallback(MovedCallback callback) { _movedCallback = callback; }
void InvokeMoved(int x, int y) { if (_movedCallback) _movedCallback(x, y); }
void SetUriChangeCallback(UriChangeCallback callback) { _uriChangeCallback = callback; }
void InvokeUriChange(AutoString uri) { if (_uriChangeCallback) _uriChangeCallback(uri); }
void SetTopmost(bool topmost);
void SetIconFile(AutoString filename);
};
Expand Down
11 changes: 10 additions & 1 deletion src/WebWindow/WebWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class WebWindow
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate int GetAllMonitorsCallback(in NativeMonitor monitor);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void ResizedCallback(int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void MovedCallback(int x, int y);

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)] delegate void UriChangeCallback(string uri);
const string DllName = "WebWindow.Native";
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] static extern IntPtr WebWindow_register_win32(IntPtr hInstance);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] static extern IntPtr WebWindow_register_mac();
Expand All @@ -82,6 +82,7 @@ public class WebWindow
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] static extern void WebWindow_SetMovedCallback(IntPtr instance, MovedCallback callback);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] static extern void WebWindow_SetTopmost(IntPtr instance, int topmost);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] static extern void WebWindow_SetIconFile(IntPtr instance, string filename);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] static extern void WebWindow_SetUriChangeCallback(IntPtr instance, UriChangeCallback callback);

private readonly List<GCHandle> _gcHandlesToFree = new List<GCHandle>();
private readonly List<IntPtr> _hGlobalToFree = new List<IntPtr>();
Expand Down Expand Up @@ -145,6 +146,10 @@ public WebWindow(string title, Action<WebWindowOptions> configure)
_gcHandlesToFree.Add(GCHandle.Alloc(onMovedDelegate));
WebWindow_SetMovedCallback(_nativeWebWindow, onMovedDelegate);

var onUriChangeDelegate = (UriChangeCallback)UriChanged;
_gcHandlesToFree.Add(GCHandle.Alloc(onUriChangeDelegate));
WebWindow_SetUriChangeCallback(_nativeWebWindow, onUriChangeDelegate);

// Auto-show to simplify the API, but more importantly because you can't
// do things like navigate until it has been shown
Show();
Expand Down Expand Up @@ -237,6 +242,10 @@ public void SendMessage(string message)
}

public event EventHandler<string> OnWebMessageReceived;

private void UriChanged(string uri) => OnUriChange?.Invoke(this, uri);

public event EventHandler<string> OnUriChange;

private void WriteTitleField(string value)
{
Expand Down
2 changes: 1 addition & 1 deletion src/WebWindow/WebWindow.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<MakeDir Directories="..\WebWindow.Native\x64\$(Configuration)" />
<Exec Condition="'$(IsMacOS)' == 'true'"
WorkingDirectory="..\WebWindow.Native"
Command="gcc -shared -lstdc++ -DOS_MAC -framework Cocoa -framework WebKit WebWindow.Mac.mm Exports.cpp WebWindow.Mac.AppDelegate.mm WebWindow.Mac.UiDelegate.mm WebWindow.Mac.UrlSchemeHandler.m -o x64/$(Configuration)/WebWindow.Native.dylib" />
Command="gcc -shared -lstdc++ -DOS_MAC -framework Cocoa -framework WebKit WebWindow.Mac.mm Exports.cpp WebWindow.Mac.AppDelegate.mm WebWindow.Mac.UiDelegate.mm WebWindow.Mac.UrlSchemeHandler.m WebWindow.Mac.NavigationDelegate.mm -o x64/$(Configuration)/WebWindow.Native.dylib" />
<Exec Condition="'$(IsMacOS)' != 'true'"
WorkingDirectory="..\WebWindow.Native"
Command="gcc -std=c++11 -shared -DOS_LINUX Exports.cpp WebWindow.Linux.cpp -o x64/$(Configuration)/WebWindow.Native.so `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0` -fPIC" />
Expand Down
5 changes: 4 additions & 1 deletion testassets/HelloWorldApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ static void Main(string[] args)
{
window.SendMessage("Got message: " + message);
};

window.OnUriChange += (sender, uri) =>
{
Console.WriteLine($"New URI: {uri}");
};
window.NavigateToLocalFile("wwwroot/index.html");
window.WaitForExit();
}
Expand Down
4 changes: 4 additions & 0 deletions testassets/HelloWorldApp/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ <h1>Hello</h1>
<p>
<button onclick="callDotNet()">Call .NET</button>
</p>

<p>
<a href="http://www.example.com">Link to example.com</a>
</p>

<script src="app://something.js"></script>

Expand Down