Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ build
.vs
out
example/*/dist
temp.log
2 changes: 2 additions & 0 deletions example/hello_world/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_PREFIX_PATH "C:\\Users\\agniv\\Documents\\sourcemeta\\native\\build\\dist")

find_package(Native REQUIRED)

native_add_app(
Expand Down
20 changes: 19 additions & 1 deletion example/hello_world/hello_world.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
////////////// temporary block -- for logging purpose ///////////////////
#include <fstream>
#include <iostream>

// Open a log file in append mode
static std::ofstream log_file("temp.log", std::ios::app);

// Helper struct to redirect std::cout and std::cerr
struct LogRedirector {
LogRedirector() {
std::cout.rdbuf(log_file.rdbuf());
std::cerr.rdbuf(log_file.rdbuf());
}
};
// Create a static instance so redirection happens at startup.
static LogRedirector logRedirector;
////////////// temporary block -- for logging purpose ///////////////////

#include <sourcemeta/native/application.h>
#include <sourcemeta/native/webview.h>
#include <sourcemeta/native/window.h>
Expand All @@ -19,7 +37,7 @@ class App : public sourcemeta::native::Application {
// webview.load_url("https://sourcemeta.com");
window.add(webview);

this->exit();
// this->exit();
}

auto on_error(std::exception_ptr) noexcept -> void override {}
Expand Down
17 changes: 17 additions & 0 deletions example/hello_world/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@
<body>
<h1>Welcome to Native</h1>
<p>This is a simple example to demonstrate loading HTML with CSS styling.</p>

<p id="h5">Waiting for message...</p>


<!-- <textarea >"{\"channel\":\"second_channel\",\"message\":\"This is a second message\"}"</textarea> -->
<textarea >{"channel":"second_channel","message":"This is a second message"}"</textarea>
<button onclick="handleClick()">Send</button>
<script>
window.chrome.webview.addEventListener('message', event => {
console.log("Received message: ", event.data);
document.getElementById('h5').textContent = `Received message: ${event.data}`;
});

const handleClick = () => {
chrome.webview.postMessage(document.querySelector('textarea').value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Hey 👋🏼

There is a way to have custom thing? Like native.postmessage ?

}
</script>
</body>

</html>
5 changes: 2 additions & 3 deletions src/ui/webview/include/sourcemeta/native/webview.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ class WebView {
auto load_html(const std::string &html_path) -> void;

// IPC messaging
// auto send_message(const std::string& channel, const std::string& message)
// -> void; auto on_message(const std::string& channel, void (*callback)(const
// std::string&)) -> void;
auto send_message(const std::string& channel, const std::string& message) -> void;
auto on_message(const std::string& channel, void (*callback)(const std::string&)) -> void;

// Size control
auto resize() -> void;
Expand Down
62 changes: 62 additions & 0 deletions src/ui/webview/win32/webview_win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class WebView::Internal {
std::optional<std::string> url;
std::optional<std::string> html_filename;

std::unordered_map<std::string, std::function<void(const std::string &)>> message_callbacks;
bool message_handler_registered{false};

// Idealy, we would prefer to have a generic type as parent as in the future
// WebView could be the child of a Container class, mixed with others UI
// classes.
Expand Down Expand Up @@ -83,6 +86,12 @@ class WebView::Internal {
// Set internals to ready
this->ready = true;

// The following setting steps is redundant since the values are the default settings
ComPtr<ICoreWebView2Settings> settings;
this->webview->get_Settings(&settings);
// settings->put_IsScriptEnabled(TRUE);
// settings->put_AreDefaultScriptDialogsEnabled(TRUE);
settings->put_IsWebMessageEnabled(TRUE);
callback();
return S_OK;
})
Expand All @@ -104,6 +113,52 @@ class WebView::Internal {
.Get());
}

// Registers the WebMessageReceived event handler
auto register_message_handler() -> void {
if (message_handler_registered) return;
message_handler_registered = true;
this->webview->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>(
[](ICoreWebView2 *sender, ICoreWebView2WebMessageReceivedEventArgs *args) -> HRESULT {
LPWSTR message_raw;

args->TryGetWebMessageAsString(&message_raw);
std::wstring w_message(message_raw);

std::string message_str(w_message.begin(), w_message.end());
std::cout << "Value of message_str: " << message_str << std::endl;

try {
// Parse message_str here
} catch (std::exception &e) {
std::cerr << "IPC JSON parse error: " << e.what() << std::endl;
}
sender->PostWebMessageAsString(w_message.c_str());
return S_OK;
}).Get(), nullptr);
}

auto send_message(const std::string &channel, const std::string &message) -> void {
if (!this->webview) {
std::cout << "webview is not ready yet!" << std::endl;
return;
}
std::wstring w_channel(channel.begin(), channel.end());
std::wstring w_message(message.begin(), message.end());
std::wstring json_data = L"{\"channel\": \"" + w_channel + L"\", \"message\": \"" + w_message + L"\"}";

this->webview->PostWebMessageAsString(json_data.c_str());
}

auto on_message(const std::string &channel, void (*callback)(const std::string &)) -> void {
message_callbacks[channel] = callback;

if (!this->webview) {
std::cout << "webview is not ready yet!" << std::endl;
return;
}
register_message_handler();
}

private:
HWND *parent_;
};
Expand Down Expand Up @@ -154,6 +209,13 @@ auto WebView::attach_to(sourcemeta::native::Window &window) -> void {
} else if (internal->html_filename.has_value()) {
internal->navigate_to_html();
}
std::cout << "internally calling send_message" << std::endl;
internal->send_message("test_channel", "this is data from native code");

std::cout << "internally calling on_message" << std::endl;
internal->on_message("test_channel", [](const std::string& msg){
std::cout << "inside on_message" << std::endl;
});
});
}

Expand Down