Skip to content

Overhaul of InfiniFrame.Native C++ backend & comprehensive documentation#98

Open
freakdaniel wants to merge 44 commits intoInfiniLore:corefrom
freakdaniel:bugfix
Open

Overhaul of InfiniFrame.Native C++ backend & comprehensive documentation#98
freakdaniel wants to merge 44 commits intoInfiniLore:corefrom
freakdaniel:bugfix

Conversation

@freakdaniel
Copy link
Contributor

@freakdaniel freakdaniel commented Mar 13, 2026

Description

Introducing: reorganization of the source tree into platform subdirectories, a complete Pimpl architecture migration, critical bug fixes for concurrent window usage, ABI/interop correctness fixes, modernization of the codebase to C++23, and comprehensive user-facing documentation for all InfiniFrame NuGet packages

Development System

  • OS: Windows 10 (x64)
  • Version: 22H2 (19045.6456)

Type of Change

  • Bug fix (non-breaking change fixing an issue)
  • New feature (non-breaking change adding functionality)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no API changes)
  • Documentation update

Changes Made

Native source reorganization

  • Split monolithic platform files (InfiniFrame.Windows.cpp, InfiniFrame.Linux.cpp, InfiniFrame.Mac.mm) into Platform/Windows/, Platform/Linux/, and Platform/Mac/ subdirectories. Also renamed entry points to Window.cpp / Window.mm for consistency
  • Extracted all shared headers into specialized directories: Core/, Types/, Utils/
  • Remove Dependencies/json.hpp (nlohmann) and replace with simdjson (ondemand API)
  • Added simdutf for correct UTF-8 to UTF-16 conversions

Pimpl & architecture

  • Introduced InfiniFrameWindowImpl.h as a shared base struct for all platform Impl definitions
  • Completed Pimpl migration for Linux/Windows/macOS
  • Deleted MessageLoopState.cs (per-window message loops no longer share a global lock)

Bug fixes

  • BugReport | InfiniFrameWindowMessageHandlers.RegisterMessageHandler should have non breaking behaviour on duplicate message id #84 RegisterMessageHandler now silently overwrites duplicate message IDs instead of throwing on collision
  • DevStory | Support MultiThreaded Message Loop #94 WaitForClose no longer acquires a global MessageLoopState lock. Independent per-thread message loops are now supported on all three platforms
  • DevStory | Native Monitor Aware fullscreen #29 SetFullScreen is now monitor-aware on all three platforms:
    • Windows saves and restores the previous window rect on exit
    • macOS migrated from the deprecated enterFullScreenMode:[NSScreen mainScreen] contentView API to toggleFullScreen: with NSWindowCollectionBehaviorFullScreenPrimary, which is monitor-aware and handles geometry restore natively
    • Linux was already correct via GTK
  • photino.native #163 Fixed non-ASCII path corruption: StartUrl / StartString now go through ToUTF16String on Windows, and SetWebView2RuntimePath uses Utf8ToWide instead of raw wcsncpy_s
  • photino.native #141 WaitForClose no longer acquires a global MessageLoopState lock. Independent per-thread message loops are now supported on all three platforms
  • Fixed StartUrl / StartString not being converted via ToUTF16String on Windows (silent breakage for non-ASCII URLs)
  • Fixed SetWebView2RuntimePath using raw wcsncpy_s instead of Utf8ToWide
  • Fixed macOS deadlock by replacing dispatch_sync with dispatch_async
  • Fixed Linux custom-scheme handler calling delete[] on a malloc-allocated contentType (UB)
  • Added null-guards in Mac/UrlSchemeHandler.mm for null contentType and empty .NET response (crash on 404)

Build & tooling

  • Bumped C++ standard to C++23
  • Added simdutf and simdjson, via FetchContent
  • Enabled ASan/UBSan/LeakSan in Debug builds

Interop (.NET)

  • Removed dead callback-setter P/Invoke exports superseded by init params
  • Added missing InfiniFrame_Restore P/Invoke binding in InfiniFrameNative.cs
  • Replaced Marshal.PtrToStringAuto with InfiniFrameNative.PtrToNativeString for platform-correct string reading

Documentation

  • Rewrote root README.md with package table, quick-start snippets for all three integration paths, architecture diagram, and links to the full docs
  • Added docs/GettingStarted.md — prerequisites, platform requirements, and a complete first-app walkthrough for each integration model
  • Added docs/Guides/CoreWindow.md — builder pattern, window configuration, browser features, runtime control, events, messaging, dialogs, custom schemes, monitor info, and DI integration
  • Added docs/Guides/Blazor.md — project setup, DI, file providers, HttpClient, lifecycle, and error handling for InfiniLore.InfiniFrame.BlazorWebView
  • Added docs/Guides/WebServer.md — builder API, URL resolution, DI access, graceful shutdown, thread model, and Blazor Server example for InfiniLore.InfiniFrame.WebServer
  • Added docs/Guides/CustomChrome.md — chromeless setup, Blazor chrome components, full layout example, and CSS tips
  • Added docs/Guides/JsInterop.md — web messaging, IInfiniFrameJs pointer capture, built-in message handlers, and structured JSON patterns
  • Added docs/Reference/WindowApi.md, BuilderApi.md, Events.md, Types.md — full API reference for all public surfaces
  • Added per-package README.md to each src/ library for NuGet consumers
  • Added examples/README.md — index of all five examples with integration type, description, and links to relevant guides
  • Added per-example README.md to each examples/ project describing what it demonstrates, key code, and links back to the relevant docs
  • Added example links to docs/Guides/ (Blazor, WebServer, JsInterop, CoreWindow) — each guide now points to the runnable examples that correspond to it
  • Added docs/BreakingChanges.md — Photino vs InfiniFrame reference updates
  • Added examples table to root README.md

Related Issues

Closes #84
Closes #94
Closes #90
Closes #89
Closes #29

Checklist

  • My code follows the project's coding standards
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings
  • All tests pass locally
  • I have added tests that prove my fix/feature works
  • New and existing unit tests pass locally
  • Any dependent changes have been merged and published

…ract models, and fix issues InfiniLore#84 and InfiniLore#94

- Reorganized InfiniFrame.Native source tree into platform subdirectories:
  Windows/, Linux/, Mac/ for platform-specific implementations
  Models/ for shared data model headers
- Renamed platform entry files to Window.cpp / Window.mm for consistency
- Extracted all data models into Models/: InfiniFrame.h, InfiniFrameDialog.h,
  Types.h, Monitor.h, Callbacks.h, InitParams.h, DialogEnums.h
- Added CMAKE_SOURCE_DIR to include paths so all files use root-relative includes
- Updated all #include directives across Windows, Linux, Mac, and Exports files
  to reference Models/InfiniFrame.h and Models/InfiniFrameDialog.h
- Fix InfiniLore#84: RegisterMessageHandler now silently overwrites duplicate message IDs
  instead of throwing on collision (ConcurrentDictionary indexer instead of TryAdd)
- Fix InfiniLore#94: WaitForClose no longer acquires a global MessageLoopState lock,
  enabling independent per-thread message loops; deleted MessageLoopState.cs
- Fix InfiniLore#94 Windows: added thread_local messageLoopRootWindowHandle and mutex-
  protected hwndToInfiniFrame map for safe concurrent window registration
- Fix InfiniLore#94 Linux: moved gtk_main_quit() signal connection from constructor into
  WaitForExit() so each nested gtk_main() level is exited by its own window's
  destroy signal
- Fix InfiniLore#94 macOS: WaitForExit() checks [NSApp isRunning] so first caller uses
  [NSApp run], subsequent callers spin NSRunLoop until NSWindowWillCloseNotification
  fires for their specific window, working around Apple's restriction on recursive
  NSApp run calls
… Windows backend

InitParams.h: fix callback fields declared as pointer-to-function-pointer (ClosingCallback*)
instead of the correct function pointer type (ClosingCallback), removing unintended double
indirection — updates Linux and macOS constructor assignments accordingly

Windows/Window.cpp:
- fix StartUrl and StartString not being converted via ToUTF16String in the constructor, causing double-reinterpretation in AttachWebView that silently broke non-ASCII URLs
- fix AttachWebView to call WebView2 Navigate/NavigateToString directly with already-converted wstrings instead of going through NavigateToUrl/NavigateToString again
- fix SetWebView2RuntimePath to convert UTF-8 input via Utf8ToWide instead of raw wcsncpy_s
- replace C-style casts with reinterpret_cast in WM_USER_INVOKE handler
- remove dead WM_MOVING case, commented-out calls in WM_MOVE and NotifyWebView2WindowMove, debug swprintf block in Center(), TODO comment in Invoke()

Exports.cpp:
- remove 5 dead callback setter exports (SetClosingCallback, SetFocusInCallback, SetFocusOutCallback, SetMovedCallback, SetResizedCallback) superseded by init params
- remove default parameter from InfiniFrame_ShowSaveFile — not valid at ABI boundaries

NativeDll.cs / InfiniFrameNative.cs: add missing InfiniFrame_Restore P/Invoke binding

Linux/Window.cpp:
- fix custom scheme handler to use free() instead of delete[] for contentType
- pass free as GDestroyNotify to g_memory_input_stream_new_from_data for correct lifetime

Mac/UrlSchemeHandler.mm:
- guard against null contentType before constructing NSString (crash on 404 responses)
- guard against null/empty dotNetResponse before passing data to urlSchemeTask

CMakeLists.txt: add simdutf.cpp and simdutf.h to build sources; bump C++ standard to cxx_std_23

InfiniWindowExtensions.cs: replace Marshal.PtrToStringAuto with InfiniFrameNative.PtrToNativeString for platform-correct UTF-16/UTF-8 string reading

InfiniFrameWindow.cs: explicitly pass null for defaultFileName in ShowSaveFile call after removing the default parameter from the native export signature
Major restructuring:
- Reorganized Models directory into specialized directories (Core, Types, Interop, Utils, Platform)
- Renamed InfiniFrame class to InfiniFrameWindow to match filename
- Added alias using InfiniFrame = InfiniFrameWindow for backward compatibility
- Moved all types into InfiniFrame namespace
- Updated CMakeLists.txt with new file paths and FetchContent dependencies (fmt, simdjson v4.3.1)

Critical fixes:
- Fixed macOS deadlock by replacing dispatch_sync with dispatch_async
- Removed blocking g_main_context_iteration loop on Linux
- Added RAII for GDI objects (HBRUSH) to prevent resource leaks
- Replaced raw new/delete with std::make_unique in Exports.cpp

Code quality improvements:
- Added comprehensive XML documentation to all Exports.cpp functions (70+ methods)
- Standardized comment style (Sentence case instead of UPPERCASE)
- Removed redundant C++23 mentions in comments
- Cleaned up excessive inline comments
- Simplified Exports.cpp using directives (single using namespace InfiniFrame)

Modern C++23 features:
- std::expected for error handling
- RAII wrappers for native resources
- Smart pointers throughout codebase
fmt library for type-safe formatting
simdjson for high-performance - JSON parsing

Build improvements:
- Enabled sanitizers for Debug builds (ASan, UBSan, LeakSan)
- Added precompiled headers for faster compilation
- Fixed platform-specific include paths

All changes maintain C API backward compatibility with existing .NET interop layer
… clean up dead code

Architecture
- Introduce InfiniFrameWindowImpl.h as shared base struct for all platform Impl definitions
- Add InfiniFrame.h umbrella header used by Exports.cpp instead of individual includes
- Complete Pimpl migration for Linux and macOS (Windows was already done)
- Add platform-guarded private helpers to InfiniFrameWindow.h: EnsureWebViewIsInstalled/InstallWebView2 (Win32), OnConfigureEvent/OnWindowStateEvent (Linux), WindowProc friend declaration (Win32)

Namespace removal
- Remove namespace InfiniFrame from Dialog.h and InitParams.h
- Remove using InfiniFrame = InfiniFrameWindow alias from InitParams.h and InfiniFrameWindow.h
- Update Exports.cpp to reference InfiniFrameWindow directly throughout

Dead code removal
- Delete Dependencies/json.hpp (25k lines, nlohmann)
- Replace json.hpp usage in Linux set_webkit_customsettings with simdjson ondemand
- Remove json.hpp include from Mac Window.mm
- Remove WideStringDeleter, CStringDeleter, ToNativeString from Basic.h
- Remove naive ASCII-only Utf8ToWide/WideToUtf8 from Common.h

Style
- Strip alignment spacing from all Impl field declarations across Windows, Linux, and Mac
- Rename WindowImplBase to InfiniFrameWindowImpl (file, struct name, all usages)

Misc
- Remove unused wwwroot placeholder files from examples and tests
…itParams, and remove unused resources

- Fix headers names
- Update #include 's
- Remove unused headers from CMakeLists
- Linux: Replace `.error() == simdjson::SUCCESS` with `== simdjson::SUCCESS` to match simdjson v4.4.0 API where get<T>() returns error_code directly
- Linux: Move OnConfigureEvent/OnWindowStateEvent from private to public so GTK signal handlers can call them
- macOS: Fix unknown type 'InfiniFrame' -> 'InfiniFrameWindow' in WindowDelegate.h and NavigationDelegate.h
- macOS: #import "Models/InfiniFrameDialog.h" -> "Core/InfiniFrameDialog.h" (Models/ directory does not exist; header lives in Core/)
- Linux: add #include <gtk/gtk.h> so GTK types and functions are declared (Dialog.cpp uses GTK directly without webkit2 to pull it in transitively)
- Add _temporaryFilesPath to macOS Impl struct (was only in Linux Impl)
- Replace field.key().value().data() with field.unescaped_key().value()
- Remove .error() from value.get<T>() calls because get<T>() returns error_code directly
@freakdaniel freakdaniel changed the title [WIP] Overhaul of the InfiniFrame.Native C++ backend Overhaul of the InfiniFrame.Native C++ backend Mar 14, 2026
@freakdaniel freakdaniel marked this pull request as ready for review March 14, 2026 17:02
@freakdaniel
Copy link
Contributor Author

@freakdaniel freakdaniel changed the title Overhaul of the InfiniFrame.Native C++ backend Overhaul of InfiniFrame.Native C++ backend & comprehensive documentation Mar 14, 2026
- Added _hasSavedRect and _savedRect for restoring window on current monitor of window
- Use new style for macOS with collectionBehavior which also stores window screen
@freakdaniel
Copy link
Contributor Author

Re-running tests bcs of the last commit

@freakdaniel
Copy link
Contributor Author

@freakdaniel
Copy link
Contributor Author

@AnnaSasDev seems i am done at this point. Other things which i want to implement are going out from the current scope of the PR

@AnnaSasDev
Copy link
Member

There seems to be some form of regression that is made clear during testing.
When tests are ran, there seems to be a issue where spawning windows is taking a lot longer than before.

Where tests completed in a few minutes, is now taking several tens of minutes.
This regression was noticed on my local Windows machine as well as on the GitHub Actions

- Included `docs/` folder with Guides, Reference, and Getting Started documentation in the solution file.
@AnnaSasDev
Copy link
Member

Also there are more build warnings now during the building of InfiniFrame.Native. Please resolve these as we strive for no warning builds.

0>Exports.cpp(53,76): Warning C4100 : 'instance': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Exports.cpp')
  
0>wintoastlib.cpp(1091,17): Warning C4456 : declaration of 'hr' hides previous local declaration [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Dependencies/wintoastlib.cpp')
      C:\Dev\InfiniFrame\src\InfiniFrame.Native\Dependencies\wintoastlib.cpp(1088,13):
      see declaration of 'hr'
  
0>wintoastlib.cpp(304,80): Warning C4100 : 'notify': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Dependencies/wintoastlib.cpp')
      C:\Dev\InfiniFrame\src\InfiniFrame.Native\Dependencies\wintoastlib.cpp(304,80):
      the template instantiation context (the oldest one first) is
          C:\Dev\InfiniFrame\src\InfiniFrame.Native\Dependencies\wintoastlib.cpp(815,48):
          see reference to function template instantiation 'HRESULT Util::setEventHandlers<WinToastLib::WinToast::showToast::<lambda_1>>(ABI::Windows::UI::Notifications::IToastNotification *,std::shared_ptr<WinToastLib::IWinToastHandler>,INT64,EventRegistrationToken &,EventRegistrationToken &,EventRegistrationToken &,FunctorT &&)' being compiled
          with
          [
              FunctorT=WinToastLib::WinToast::showToast::<lambda_1>
          ]
  
0>wintoastlib.cpp(371,100): Warning C4100 : 'notify': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Dependencies/wintoastlib.cpp')
  
0>wintoastlib.cpp(388,119): Warning C4100 : 'e': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Dependencies/wintoastlib.cpp')
  
0>wintoastlib.cpp(388,88): Warning C4100 : 'notify': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Dependencies/wintoastlib.cpp')
  
0>ToastHandler.h(45,29): Warning C4100 : 'actionIndex': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>ToastHandler.h(54,38): Warning C4100 : 'response': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>ToastHandler.h(63,49): Warning C4100 : 'state': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>Window.cpp(1192,27): Warning C4100 : 'webview': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>Window.cpp(1202,27): Warning C4100 : 'sender': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>Window.cpp(1248,28): Warning C4100 : 'sender': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>Window.cpp(1402,21): Warning C4100 : 'error': unreferenced parameter [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
  (compiling source file '../../../Platform/Windows/Window.cpp')
  
0>wintoastlib.cpp(824,1): Warning C4701 : potentially uninitialized local variable 'failedToken' used [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
0>wintoastlib.cpp(824,1): Warning C4701 : potentially uninitialized local variable 'dismissedToken' used [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
0>wintoastlib.cpp(824,1): Warning C4701 : potentially uninitialized local variable 'activatedToken' used [C:\Dev\InfiniFrame\src\InfiniFrame.Native\build\x64\Debug\InfiniFrame.Native.vcxproj]
     Creating library C:/Dev/InfiniFrame/src/InfiniFrame.Native/build/x64/Debug/Debug/InfiniFrame.Native.lib and object C:/Dev/InfiniFrame/src/InfiniFrame.Native/build/x64/Debug/Debug/InfiniFrame.Native.exp

- Adjusted `.gitignore` to improve handling of `cmake-build` directories and native build outputs.
- Updated `InfiniFrame.Native.proj` to explicitly exclude build artifacts and package directories from the project.
@AnnaSasDev
Copy link
Member

Alligned some code style consistency with the C# code.
Also removed some folders from showing up in the IDE view for C# projects

AnnaSasDev and others added 4 commits March 15, 2026 18:40
- Add /W0 flag to wintoastlib
- Add caching to CMake
- Add --parallel to CMake
- Added run for GSettings schemas
- Added saving for topmost in window Impl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants