Skip to content

Commit

Permalink
move WebView2 code to WebView.[cpp|h]
Browse files Browse the repository at this point in the history
  • Loading branch information
kjk committed May 29, 2024
1 parent 1ed1418 commit 42f882f
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 281 deletions.
76 changes: 44 additions & 32 deletions src/CrashHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#include "utils/LzmaSimpleArchive.h"
#include "utils/WinUtil.h"

#include "wingui/UIModels.h"
#include "wingui/Layout.h"
#include "wingui/WinGui.h"
#include "wingui/WebView.h"

#include "Settings.h"
#include "GlobalPrefs.h"
#include "AppTools.h"
Expand Down Expand Up @@ -499,21 +504,6 @@ static void GetProcessorName(str::Str& s) {
}
}

static void GetMachineName(str::Str& s) {
char* s1 = ReadRegStrTemp(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", "SystemFamily");
char* s2 = ReadRegStrTemp(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", "SystemVersion");

if (!s1 && !s2) {
// no-op
} else if (!s1) {
s.AppendFmt("Machine: %s\n", s2);
} else if (!s2 || str::EqI(s1, s2)) {
s.AppendFmt("Machine: %s\n", s1);
} else {
s.AppendFmt("Machine: %s %s\n", s1, s2);
}
}

#define GFX_DRIVER_KEY_FMT "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\%04d"

static void GetGraphicsDriverInfo(str::Str& s) {
Expand Down Expand Up @@ -547,31 +537,53 @@ static void GetGraphicsDriverInfo(str::Str& s) {
}
}

static void GetLanguage(str::Str& s) {
char country[32] = {}, lang[32]{};
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, dimof(country) - 1);
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, dimof(lang) - 1);
s.AppendFmt("Lang: %s %s\n", lang, country);
}

static void GetSystemInfo(str::Str& s) {
SYSTEM_INFO si;
GetSystemInfo(&si);
s.AppendFmt("Number Of Processors: %d\n", si.dwNumberOfProcessors);
GetProcessorName(s);

MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
{

float physMemGB = (float)ms.ullTotalPhys / (float)(1024 * 1024 * 1024);
float totalPageGB = (float)ms.ullTotalPageFile / (float)(1024 * 1024 * 1024);
DWORD usedPerc = ms.dwMemoryLoad;
s.AppendFmt("Physical Memory: %.2f GB\nCommit Charge Limit: %.2f GB\nMemory Used: %d%%\n", physMemGB, totalPageGB,
usedPerc);
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);

GetMachineName(s);
GetLanguage(s);
float physMemGB = (float)ms.ullTotalPhys / (float)(1024 * 1024 * 1024);
float totalPageGB = (float)ms.ullTotalPageFile / (float)(1024 * 1024 * 1024);
DWORD usedPerc = ms.dwMemoryLoad;
s.AppendFmt("Physical Memory: %.2f GB\nCommit Charge Limit: %.2f GB\nMemory Used: %d%%\n", physMemGB, totalPageGB,
usedPerc);
}
{
TempStr ver = GetWebView2VersionTemp();
if (str::IsEmpty(ver)) {
ver = (TempStr)"no WebView2 installed";
}
s.AppendFmt("WebView2: %s\n", ver);
}
{
// get computer name
char* s1 = ReadRegStrTemp(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", "SystemFamily");
char* s2 = ReadRegStrTemp(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", "SystemVersion");

if (!s1 && !s2) {
// no-op
} else if (!s1) {
s.AppendFmt("Machine: %s\n", s2);
} else if (!s2 || str::EqI(s1, s2)) {
s.AppendFmt("Machine: %s\n", s1);
} else {
s.AppendFmt("Machine: %s %s\n", s1, s2);
}
}
{
// get language
char country[32] = {}, lang[32]{};
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, dimof(country) - 1);
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, dimof(lang) - 1);
s.AppendFmt("Lang: %s %s\n", lang, country);
}
GetGraphicsDriverInfo(s);

// Note: maybe more information, like:
Expand Down
1 change: 1 addition & 0 deletions src/Scratch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "wingui/UIModels.h"
#include "wingui/Layout.h"
#include "wingui/WinGui.h"
#include "wingui/WebView.h"

#include "Settings.h"
#include "DocProperties.h"
Expand Down
1 change: 1 addition & 0 deletions src/UpdateCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "wingui/Layout.h"
#include "wingui/UIModels.h"
#include "wingui/WinGui.h"
#include "wingui/WebView.h"

#include "Settings.h"
#include "GlobalPrefs.h"
Expand Down
229 changes: 229 additions & 0 deletions src/wingui/WebView.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/* Copyright 2024 the SumatraPDF project authors (see AUTHORS file).
License: Simplified BSD (see COPYING.BSD) */

#include "utils/BaseUtil.h"
#include "utils/ScopedWin.h"
#include "utils/BitManip.h"
#include "utils/WinUtil.h"
#include "utils/Dpi.h"
#include "utils/WinDynCalls.h"

#include "wingui/UIModels.h"

#include "wingui/Layout.h"
#include "wingui/WinGui.h"

//#include "Theme.h"

#include "webview2.h"
#include "wingui/WebView.h"

#include "utils/Log.h"

Kind kindWebView = "webView";

TempStr GetWebView2VersionTemp() {
WCHAR* ver = nullptr;
HRESULT hr = GetAvailableCoreWebView2BrowserVersionString(nullptr, &ver);
if (FAILED(hr) || (ver == nullptr)) {
return nullptr;
}
TempStr res = ToUtf8Temp(ver);
return res;
}

class webview2_com_handler : public ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler,
public ICoreWebView2CreateCoreWebView2ControllerCompletedHandler,
public ICoreWebView2WebMessageReceivedEventHandler,
public ICoreWebView2PermissionRequestedEventHandler {
using webview2_com_handler_cb_t = std::function<void(ICoreWebView2Controller*)>;

public:
webview2_com_handler(HWND hwnd, WebViewMsgCb msgCb, webview2_com_handler_cb_t cb)
: m_window(hwnd), msgCb(msgCb), m_cb(cb) {
}
ULONG STDMETHODCALLTYPE AddRef() {
return 1;
}

ULONG STDMETHODCALLTYPE Release() {
return 1;
}

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppv) {
return S_OK;
}

HRESULT STDMETHODCALLTYPE Invoke(HRESULT res, ICoreWebView2Environment* env) {
env->CreateCoreWebView2Controller(m_window, this);
return S_OK;
}

HRESULT STDMETHODCALLTYPE Invoke(HRESULT res, ICoreWebView2Controller* controller) {
controller->AddRef();

ICoreWebView2* webview;
::EventRegistrationToken token;
controller->get_CoreWebView2(&webview);
webview->add_WebMessageReceived(this, &token);
webview->add_PermissionRequested(this, &token);

m_cb(controller);
return S_OK;
}

HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) {
WCHAR* message = nullptr;
args->TryGetWebMessageAsString(&message);
if (!message) {
return S_OK;
}
char* s = ToUtf8Temp(message);
msgCb(s);
sender->PostWebMessageAsString(message);
CoTaskMemFree(message);
return S_OK;
}

HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) {
COREWEBVIEW2_PERMISSION_KIND kind;
args->get_PermissionKind(&kind);
if (kind == COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ) {
args->put_State(COREWEBVIEW2_PERMISSION_STATE_ALLOW);
}
return S_OK;
}

private:
HWND m_window;
WebViewMsgCb msgCb;
webview2_com_handler_cb_t m_cb;
};

Webview2Wnd::Webview2Wnd() {
kind = kindWebView;
}

void Webview2Wnd::UpdateWebviewSize() {
if (controller == nullptr) {
return;
}
RECT bounds = ClientRECT(hwnd);
controller->put_Bounds(bounds);
}

void Webview2Wnd::Eval(const char* js) {
TempWStr ws = ToWStrTemp(js);
webview->ExecuteScript(ws, nullptr);
}

void Webview2Wnd::SetHtml(const char* html) {
#if 0
std::string s = "data:text/html,";
s += url_encode(html);
WCHAR* html2 = ToWStrTemp(s.c_str());
m_webview->Navigate(html2);
#else
WCHAR* html2 = ToWStrTemp(html);
webview->NavigateToString(html2);
#endif
}

void Webview2Wnd::Init(const char* js) {
TempWStr ws = ToWStrTemp(js);
webview->AddScriptToExecuteOnDocumentCreated(ws, nullptr);
}

void Webview2Wnd::Navigate(const char* url) {
TempWStr ws = ToWStrTemp(url);
webview->Navigate(ws);
}

/*
Settings:
put_IsWebMessageEnabled(BOOL isWebMessageEnabled)
put_AreDefaultScriptDialogsEnabled(BOOL areDefaultScriptDialogsEnabled)
put_IsStatusBarEnabled(BOOL isStatusBarEnabled)
put_AreDevToolsEnabled(BOOL areDevToolsEnabled)
put_AreDefaultContextMenusEnabled(BOOL enabled)
put_AreHostObjectsAllowed(BOOL allowed)
put_IsZoomControlEnabled(BOOL enabled)
put_IsBuiltInErrorPageEnabled(BOOL enabled)
*/

bool Webview2Wnd::Embed(WebViewMsgCb cb) {
// TODO: not sure if flag needs to be atomic i.e. is CreateCoreWebView2EnvironmentWithOptions()
// called on a different thread?
volatile LONG flag = 0;
// InterlockedCompareExchange()
WCHAR* userDataFolder = ToWStrTemp(dataDir);
HRESULT hr = CreateCoreWebView2EnvironmentWithOptions(
nullptr, userDataFolder, nullptr, new webview2_com_handler(hwnd, cb, [&](ICoreWebView2Controller* ctrl) {
controller = ctrl;
controller->get_CoreWebView2(&webview);
webview->AddRef();
InterlockedAdd(&flag, 1);
}));
if (hr != S_OK) {
return false;
}
MSG msg = {};
while ((InterlockedAdd(&flag, 0) == 0) && GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// remove window frame and decorations
auto style = GetWindowLong(hwnd, GWL_STYLE);
style &= ~(WS_OVERLAPPEDWINDOW);
SetWindowLong(hwnd, GWL_STYLE, style);

ICoreWebView2Settings* settings = nullptr;
hr = webview->get_Settings(&settings);
if (hr == S_OK) {
settings->put_AreDefaultContextMenusEnabled(FALSE);
settings->put_AreDevToolsEnabled(FALSE);
settings->put_IsStatusBarEnabled(FALSE);
}

Init("window.external={invoke:s=>window.chrome.webview.postMessage(s)}");
return true;
}

void Webview2Wnd::OnBrowserMessage(const char* msg) {
/*
auto seq = json_parse(msg, "id", 0);
auto name = json_parse(msg, "method", 0);
auto args = json_parse(msg, "params", 0);
if (bindings.find(name) == bindings.end()) {
return;
}
auto fn = bindings[name];
(*fn->first)(seq, args, fn->second);
*/
log(msg);
}

HWND Webview2Wnd::Create(const CreateCustomArgs& args) {
ReportIf(!dataDir);
CreateCustom(args);
if (!hwnd) {
return nullptr;
}

auto cb = std::bind(&Webview2Wnd::OnBrowserMessage, this, std::placeholders::_1);
Embed(cb);
UpdateWebviewSize();
return hwnd;
}

LRESULT Webview2Wnd::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if (msg == WM_SIZE) {
UpdateWebviewSize();
}
return WndProcDefault(hwnd, msg, wparam, lparam);
}

Webview2Wnd::~Webview2Wnd() {
str::Free(dataDir);
}
39 changes: 39 additions & 0 deletions src/wingui/WebView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright 2024 the SumatraPDF project authors (see AUTHORS file).
License: Simplified BSD (see COPYING.BSD) */

TempStr GetWebView2VersionTemp();

// TODO: maybe hide those inside a private struct
typedef interface ICoreWebView2 ICoreWebView2;
typedef interface ICoreWebView2Controller ICoreWebView2Controller;

using WebViewMsgCb = std::function<void(const char*)>;
// using dispatch_fn_t = std::function<void()>;

struct Webview2Wnd : Wnd {
Webview2Wnd();
~Webview2Wnd() override;

HWND Create(const CreateCustomArgs&);

void Eval(const char* js);
void SetHtml(const char* html);
void Init(const char* js);
void Navigate(const char* url);
bool Embed(WebViewMsgCb cb);

virtual void OnBrowserMessage(const char* msg);

LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override;

void UpdateWebviewSize();

// this is where the webview2 control stores data
// must be set before we call create
// TODO: make Webview2CreateCustomArgs
// with dataDir
char* dataDir = nullptr;
// DWORD m_main_thread = GetCurrentThreadId();
ICoreWebView2* webview = nullptr;
ICoreWebView2Controller* controller = nullptr;
};
Loading

0 comments on commit 42f882f

Please sign in to comment.