Skip to content
Merged
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
10 changes: 7 additions & 3 deletions src/InfiniFrame.Native/InfiniFrame.Native.proj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!-- Cross-platform Visual Studio placeholder for CMake -->
Expand All @@ -19,6 +19,10 @@
<!-- Fallback -->
<CMakeArch Condition="'$(CMakeArch)'==''">x64</CMakeArch>

<!-- macOS arch mapping -->
<CMakeOSXArch Condition="'$(CMakeArch)'=='x64'">x86_64</CMakeOSXArch>
<CMakeOSXArch Condition="'$(CMakeArch)'=='arm64'">arm64</CMakeOSXArch>

<CMakeBuildDir>build/$(CMakeArch)/$(Configuration)</CMakeBuildDir>
<CMakeOSDir Condition="'$(IsWindows)'=='true'">windows</CMakeOSDir>
<CMakeOSDir Condition="'$(IsLinux)'=='true'">linux</CMakeOSDir>
Expand Down Expand Up @@ -53,11 +57,11 @@
<Exec Condition="$(IsWindows)" Command="cmake --build $(CMakeBuildDir) --config $(Configuration) --parallel"/>

<!-- Linux -->
<Exec Condition="$(IsLinux)" Command="cmake -B $(CMakeBuildDir) -S . -DCMAKE_OSX_ARCHITECTURES=$(CMakeArch)"/>
<Exec Condition="$(IsLinux)" Command="cmake -B $(CMakeBuildDir) -S ."/>
<Exec Condition="$(IsLinux)" Command="cmake --build $(CMakeBuildDir) --config $(Configuration) --parallel"/>

<!-- macOS -->
<Exec Condition="$(IsMac)" Command="cmake -B $(CMakeBuildDir) -S ."/>
<Exec Condition="$(IsMac)" Command="cmake -B $(CMakeBuildDir) -S . -DCMAKE_OSX_ARCHITECTURES=$(CMakeOSXArch)"/>
<Exec Condition="$(IsMac)" Command="cmake --build $(CMakeBuildDir) --config $(Configuration) --parallel"/>

<!-- Copy native binaries -->
Expand Down
7 changes: 4 additions & 3 deletions src/InfiniFrame.Native/Platform/Linux/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@
gint windowWidth, windowHeight;
gtk_window_get_size(GTK_WINDOW(m_impl->_window), &windowWidth, &windowHeight);

GdkRectangle screen = {0};

Check warning on line 466 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (c-cpp on ubuntu-latest)

missing initializer for member ‘_cairo_rectangle_int::y’

Check warning on line 466 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (c-cpp on ubuntu-latest)

missing initializer for member ‘_cairo_rectangle_int::y’

Check warning on line 466 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp on ubuntu-latest)

missing initializer for member ‘_cairo_rectangle_int::height’

Check warning on line 466 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp on ubuntu-latest)

missing initializer for member ‘_cairo_rectangle_int::height’

GdkDisplay* d = gdk_display_get_default();
if (d == nullptr) {
Expand Down Expand Up @@ -537,7 +537,7 @@
}

AutoString InfiniFrameWindow::GetUserAgent() const {
return const_cast<AutoString>(m_impl->_userAgent.c_str());
return AllocateStringCopy(m_impl->_userAgent);
}

void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const {
Expand Down Expand Up @@ -616,7 +616,8 @@
}

AutoString InfiniFrameWindow::GetTitle() const {
return const_cast<AutoString>(gtk_window_get_title(GTK_WINDOW(m_impl->_window)));
const char* title = gtk_window_get_title(GTK_WINDOW(m_impl->_window));
return g_strdup(title ? title : "");
}

void InfiniFrameWindow::GetTopmost(bool* topmost) const {
Expand All @@ -636,7 +637,7 @@
}

AutoString InfiniFrameWindow::GetIconFileName() const {
return const_cast<AutoString>(m_impl->_iconFileName.c_str());
return AllocateStringCopy(m_impl->_iconFileName);
}

// ---------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -1081,8 +1082,8 @@
gboolean on_webview_context_menu(
WebKitWebView* web_view,
GtkWidget* default_menu,
WebKitHitTestResult* hit_test_result,

Check warning on line 1085 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp on ubuntu-latest)

unused parameter ‘hit_test_result’

Check warning on line 1085 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp on ubuntu-latest)

unused parameter ‘hit_test_result’
gboolean triggered_with_keyboard,

Check warning on line 1086 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (c-cpp on ubuntu-latest)

unused parameter ‘triggered_with_keyboard’

Check warning on line 1086 in src/InfiniFrame.Native/Platform/Linux/Window.cpp

View workflow job for this annotation

GitHub Actions / Analyze (c-cpp on ubuntu-latest)

unused parameter ‘triggered_with_keyboard’
const gpointer self
) {
auto* instance = reinterpret_cast<InfiniFrameWindow*>(self);
Expand Down
6 changes: 3 additions & 3 deletions src/InfiniFrame.Native/Platform/Mac/Window.mm
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@

AutoString InfiniFrameWindow::GetUserAgent() const
{
return const_cast<AutoString>(m_impl->_userAgent.c_str());
return AllocateStringCopy(m_impl->_userAgent);
}

void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const
Expand Down Expand Up @@ -549,7 +549,7 @@

AutoString InfiniFrameWindow::GetTitle() const
{
return const_cast<AutoString>(m_impl->_windowTitle.c_str());
return AllocateStringCopy(m_impl->_windowTitle);
}

void InfiniFrameWindow::GetTopmost(bool* topmost) const
Expand All @@ -566,7 +566,7 @@

AutoString InfiniFrameWindow::GetIconFileName() const
{
return const_cast<AutoString>(m_impl->_iconFileName.c_str());
return AllocateStringCopy(m_impl->_iconFileName);
}

// ---------------------------------------------------------------------------------------------------------------------
Expand Down
8 changes: 6 additions & 2 deletions src/InfiniFrame.Native/Platform/Windows/DarkMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,14 @@ bool IsColorSchemeChange(const LPARAM l_param) noexcept {
-1,
TRUE
) == CSTR_EQUAL) {
RefreshImmersiveColorPolicyState();
if (RefreshImmersiveColorPolicyState != nullptr) {
RefreshImmersiveColorPolicyState();
}
return_value = true;
}

GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
if (GetIsImmersiveColorUsingHighContrast != nullptr) {
GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
}
return return_value;
}
43 changes: 27 additions & 16 deletions src/InfiniFrame.Native/Platform/Windows/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,14 +453,16 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara
}
case WM_ACTIVATE: {
InfiniFrameWindow * instance = hwndToInfiniFrame[hwnd];
if (LOWORD(wParam) == WA_INACTIVE) {
instance->InvokeFocusOut();
}
else {
instance->FocusWebView2();
instance->InvokeFocusIn();
if (instance) {
if (LOWORD(wParam) == WA_INACTIVE) {
instance->InvokeFocusOut();
}
else {
instance->FocusWebView2();
instance->InvokeFocusIn();

return 0;
return 0;
}
}
break;
}
Expand Down Expand Up @@ -610,8 +612,11 @@ void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const {
return;
}
wil::com_ptr<ICoreWebView2Settings> settings;
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings)
settings->get_AreDefaultContextMenusEnabled(reinterpret_cast<BOOL*>(enabled));
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) {
BOOL boolValue = FALSE;
settings->get_AreDefaultContextMenusEnabled(&boolValue);
*enabled = (boolValue != FALSE);
}
}

void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const {
Expand All @@ -620,8 +625,11 @@ void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const {
return;
}
wil::com_ptr<ICoreWebView2Settings> settings;
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings)
settings->get_IsZoomControlEnabled(reinterpret_cast<BOOL*>(enabled));
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) {
BOOL boolValue = FALSE;
settings->get_IsZoomControlEnabled(&boolValue);
*enabled = (boolValue != FALSE);
}
}

void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const {
Expand All @@ -630,8 +638,11 @@ void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const {
return;
}
wil::com_ptr<ICoreWebView2Settings> settings;
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings)
settings->get_AreDevToolsEnabled(reinterpret_cast<BOOL*>(enabled));
if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) {
BOOL boolValue = FALSE;
settings->get_AreDevToolsEnabled(&boolValue);
*enabled = (boolValue != FALSE);
}
}

void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const {
Expand All @@ -644,7 +655,7 @@ void InfiniFrameWindow::GetGrantBrowserPermissions(bool* grant) const {
}

AutoString InfiniFrameWindow::GetUserAgent() const {
return const_cast<AutoString>(m_impl->_userAgent.c_str());
return AllocateStringCopy(m_impl->_userAgent);
}

void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const {
Expand Down Expand Up @@ -684,7 +695,7 @@ void InfiniFrameWindow::GetNotificationsEnabled(bool* enabled) const {
}

AutoString InfiniFrameWindow::GetIconFileName() const {
return const_cast<AutoString>(m_impl->_iconFileName.c_str());
return AllocateStringCopy(m_impl->_iconFileName);
}

void InfiniFrameWindow::GetMaximized(bool* isMaximized) const {
Expand Down Expand Up @@ -739,7 +750,7 @@ void InfiniFrameWindow::GetMinSize(int* width, int* height) const {
}

AutoString InfiniFrameWindow::GetTitle() const {
return const_cast<AutoString>(m_impl->_windowTitle.c_str());
return AllocateStringCopy(m_impl->_windowTitle);
}

void InfiniFrameWindow::GetTopmost(bool* topmost) const {
Expand Down
31 changes: 31 additions & 0 deletions src/InfiniFrame.Native/Utils/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <optional>
#include <algorithm>
#include <system_error>
#include <cstring>

#ifdef _WIN32
#include <windows.h>
Expand Down Expand Up @@ -152,4 +153,34 @@ template <typename T>
return std::clamp(value, minVal, maxVal);
}

#ifdef _WIN32
inline wchar_t* AllocateStringCopy(const std::wstring& str) {
const size_t len = str.length();
wchar_t* copy = new wchar_t[len + 1];
std::memcpy(copy, str.c_str(), (len + 1) * sizeof(wchar_t));
return copy;
}

#elif __linux__
inline char* AllocateStringCopy(const std::string& str) {
return g_strdup(str.c_str());
}

#elif __APPLE__
inline char* AllocateStringCopy(const std::string& str) {
const size_t len = str.length();
char* copy = static_cast<char*>(malloc(len + 1));
std::memcpy(copy, str.c_str(), len + 1);
return copy;
}

#else
inline char* AllocateStringCopy(const std::string& str) {
const size_t len = str.length();
char* copy = static_cast<char*>(malloc(len + 1));
std::memcpy(copy, str.c_str(), len + 1);
return copy;
}
#endif

#endif // INFINIFRAME_COMMON_H
2 changes: 1 addition & 1 deletion src/InfiniFrame.Native/Utils/Event.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Event {
private:
mutable std::shared_mutex m_mutex;
std::map<Token, Handler> m_handlers;
Token m_nextToken = 0;
Token m_nextToken = 1;
};

// ---------------------------------------------------------------------------------------------------------------------
Expand Down
52 changes: 48 additions & 4 deletions src/InfiniFrame/InfiniFrameWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,13 @@ public void Close() {
if (InstanceHandle == IntPtr.Zero) return;

Interlocked.Exchange(ref _shutdownRequested, 1);
Invoke(() => InfiniFrameNative.Close(InstanceHandle));
Invoke(() => {
if (InstanceHandle == IntPtr.Zero) {
Logger.LogDebug("Window already closed");
return;
}
InfiniFrameNative.Close(InstanceHandle);
});
}

/// <summary>
Expand All @@ -471,7 +477,13 @@ public void SendWebMessage(string message) {
}

Logger.LogDebug(".SendWebMessage({Message})", message);
Invoke(() => InfiniFrameNative.SendWebMessage(InstanceHandle, message));
Invoke(() => {
if (Volatile.Read(ref _shutdownStarted) != 0 || InstanceHandle == IntPtr.Zero) {
Logger.LogDebug("Window closed before SendWebMessage could execute");
return;
}
InfiniFrameNative.SendWebMessage(InstanceHandle, message);
});
}

public Task SendWebMessageAsync(string message, CancellationToken ct = default) {
Expand Down Expand Up @@ -503,8 +515,19 @@ internal byte OnWindowClosing() {
/// <param name="title">The title of the notification</param>
/// <param name="body">The text of the notification</param>
public void SendNotification(string title, string body) {
if (Volatile.Read(ref _shutdownStarted) != 0 || InstanceHandle == IntPtr.Zero) {
Logger.LogDebug("Skipping SendNotification during shutdown");
return;
}

Logger.LogDebug(".SendNotification({Title}, {Body})", title, body);
Invoke(() => InfiniFrameNative.ShowNotification(InstanceHandle, title, body));
Invoke(() => {
if (Volatile.Read(ref _shutdownStarted) != 0 || InstanceHandle == IntPtr.Zero) {
Logger.LogDebug("Window closed before SendNotification could execute");
return;
}
InfiniFrameNative.ShowNotification(InstanceHandle, title, body);
});
}

/// <summary>
Expand Down Expand Up @@ -712,8 +735,12 @@ out string? resolvedIconFilePath
Invoke(InfiniFrameNative.RegisterMac);

Invoke(() => InstanceHandle = InfiniFrameNative.Constructor(in StartupParameters));

FreeCustomSchemeNames();
}
catch (Exception ex) when (IsNonFatalException(ex)) {
FreeCustomSchemeNames();

int lastError = 0;
if (OperatingSystem.IsWindows())
lastError = Marshal.GetLastWin32Error();
Expand All @@ -726,7 +753,24 @@ out string? resolvedIconFilePath
}

/// <summary>
/// Show a native open dialog.
/// Frees unmanaged memory allocated for custom scheme names
/// </summary>
/// <remarks>
/// This method should be called after the native constructor has copied the scheme names.
/// The native side makes its own copies, so the managed side can safely free the memory
/// </remarks>
private void FreeCustomSchemeNames() {
if (StartupParameters.CustomSchemeNames == null) return;

foreach (IntPtr ptr in StartupParameters.CustomSchemeNames) {
if (ptr != IntPtr.Zero) {
Marshal.FreeHGlobal(ptr);
}
}
Comment thread
AnnaSasDev marked this conversation as resolved.
Dismissed
}

/// <summary>
/// Show a native open dialog
/// </summary>
/// <param name="foldersOnly">Whether files are hidden</param>
/// <param name="title">Title of the dialog</param>
Expand Down
Loading