PhotinoX.Cpp is a modern C++ application framework for building lightweight, native, multi-window desktop applications with Web UI technologies and operating-system WebView controls.
It is built on PhotinoX.Native, which provides the native application runtime, operating-system windows, platform WebView integration, message loop, dispatcher, notifications, and cross-platform C ABI.
PhotinoX.Cpp follows the application model established by PhotinoX while providing an idiomatic modern C++ API based on RAII, explicit ownership, strong typing, deterministic lifetime, native exception semantics, and CMake.
- Windows: Microsoft Edge WebView2
- macOS: WKWebView
- Linux: WebKitGTK 4.1
PhotinoX.Cpp provides the high-level application framework layer between modern C++ application code and the cross-platform runtime, windowing, dispatch, and WebView services of PhotinoX.Native.
Modern C++ application
↓
PhotinoX.Cpp
├── Application
├── Dispatcher
├── Window
├── WindowCollection
├── Typed event arguments
├── Removable event subscriptions
└── Native notifications
↓
PhotinoX.Native
├── Application lifetime
├── Native message loop
├── Cross-thread dispatch
├── Native window management
├── Notification integration
└── Stable cross-platform ABI
↓
Operating-system WebView
├── Windows: WebView2
├── macOS: WKWebView
└── Linux: WebKitGTK 4.1
The framework allows a C++ desktop application to use HTML, CSS, and JavaScript for its user interface without bundling Electron, Node.js, or an application-specific Chromium runtime.
The native browser engine is provided by the operating system. This keeps deployment size and runtime overhead significantly lower than frameworks that ship a complete browser runtime with each application.
PhotinoX.Native provides a language-independent native foundation for idiomatic application frameworks targeting different development environments.
PhotinoX.Native
├── PhotinoX
│ └── PhotinoX.App
│ └── PhotinoX.Blazor
└── PhotinoX.Cpp
The responsibilities of the primary layers are:
- PhotinoX.Native provides the native cross-platform application runtime, C ABI, platform windows, WebView integration, dispatcher, notifications, and operating-system-specific implementation.
- PhotinoX provides the primary .NET application framework and serves as the reference implementation for shared PhotinoX application semantics.
- PhotinoX.Cpp provides an idiomatic modern C++ application framework over the same native runtime.
- PhotinoX.App adds dependency injection, configuration, logging, environment services, and application composition for .NET.
- PhotinoX.Blazor builds on PhotinoX.App and adds Blazor hosting and integration for .NET applications.
PhotinoX and PhotinoX.Cpp share the same fundamental application semantics, including application lifetime, dispatcher behavior, window tracking, shutdown behavior, notifications, callback ownership, and exception boundaries. Each framework expresses those concepts using the conventions and capabilities of its language.
Most C++ WebView libraries center their API around a WebView and leave application lifetime, message-loop ownership, dispatch, window tracking, shutdown behavior, and callback failure handling to the application.
PhotinoX.Cpp is application-first rather than WebView-first. It provides an explicit desktop application model in which windows, dispatch, lifecycle, notifications, and shutdown behavior are coordinated by the framework, while the operating-system WebView remains the UI renderer.
- Application model: explicit lifetime, native message-loop ownership, main-window tracking, and configurable shutdown behavior.
- Multi-window architecture: observable window collection, stable snapshots, typed collection events, and dispatcher-thread mutations.
- Threading: centralized dispatcher with synchronous, result-returning, asynchronous, and failure-aware operations.
- Lifetime and safety: RAII, deterministic ownership, removable subscriptions, callback cancellation, and exception-safe ABI boundaries.
- Native integration: operating-system windows, dialogs, notifications, platform handles, and runtime diagnostics.
- Cross-language runtime: shared PhotinoX.Native application semantics across the .NET and C++ frameworks.
PhotinoX.Cpp combines the convenience and consistency of high-level desktop frameworks with the performance, control, deterministic lifetime, and native integration expected from modern C++.
Application is the explicit owner of the native desktop lifetime.
It provides:
Run(...)Shutdown(...)IsRunning()IsShuttingDown()- configurable
ShutdownMode - startup, shutdown-requested, and exit events
- main-window tracking
- observable application window collection
- native notification integration
#include <photinox/photinox.hpp>
using namespace photinox;
int main()
{
Application application;
Window window(application);
window
.SetTitle("PhotinoX.Cpp")
.LoadString(R"(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PhotinoX.Cpp</title>
</head>
<body>
<h1>PhotinoX.Cpp</h1>
<p>Native desktop applications with modern C++ and Web UI.</p>
</body>
</html>
)");
application.SetShutdownMode(ShutdownMode::OnMainWindowClose);
return application.Run(&window);
}Only one Application instance may exist at a time because PhotinoX.Native provides a process-wide application runtime that owns the native message loop, dispatcher, and platform application state.
Dispatcher centralizes access to the native application thread.
Available operations include:
CheckAccess()VerifyAccess()Invoke(...)- result-returning
Invoke(...) TryInvoke(...)- result-returning
TryInvoke(...) BeginInvoke(...)- dispatcher-level unhandled exception events
const int result = application.GetDispatcher().Invoke([]
{
return 42;
});Asynchronous native callbacks use explicit execution and release callbacks. If a pending operation is canceled during application shutdown, its state is released without executing the user callback.
Exceptions from asynchronous dispatcher operations are forwarded to the dispatcher unhandled-exception handlers without crossing the native ABI boundary.
Window provides a dispatcher-aware, multi-window desktop API with explicit lifecycle management, geometry and state control, appearance and visibility settings, WebView configuration and navigation, messaging, custom schemes, native dialogs, monitor information, platform handle access, and typed removable event subscriptions.
Window window(application);
window
.SetTitle("Settings")
.LoadString("<html><body>Settings</body></html>")
.RegisterClosingHandler([](ClosingEventArgs& args)
{
args.cancel = false;
});
window.Show();Window objects use deterministic C++ lifetime rules. Destroying a window while its native instance is still active is treated as a lifetime contract violation.
Application::Windows() returns a WindowCollection, not a non-owning view into an internal container.
The collection provides:
Size()Empty()Contains(...)- stable snapshot enumeration
- collection-changed notifications
- removable collection event subscriptions
- thread-safe snapshot access
application.Windows().RegisterCollectionChangedHandler(
[](const WindowCollectionChangedEventArgs& args)
{
if (args.action == NotifyCollectionChangedAction::Add)
{
for (Window* window : args.newItems)
{
// A window was added to the application.
}
}
});A stable copy can be requested explicitly:
const auto windows = application.Windows().Snapshot();
for (Window* window : windows)
{
if (window)
{
// Use the current window snapshot.
}
}Collection mutations occur on the application dispatcher thread. Read operations use a synchronized snapshot model.
PhotinoX.Cpp supports two event registration models.
Permanent fluent registration:
application.RegisterStartupHandler([]
{
// Called before the native application message loop starts.
});Removable token-based subscriptions:
const EventToken token = application.SubscribeStartupHandler([]
{
// Removable startup handler.
});
application.UnsubscribeStartupHandler(token);EventToken is a lightweight implementation-independent value type. Native event callback handles remain private and are not exposed through the public API.
The same subscription infrastructure is shared by:
- application lifecycle events;
- notification events;
- dispatcher unhandled-exception events;
- window collection events;
- window events.
Notifications are owned by Application, not by individual windows.
const int notificationId = application.ShowNotification(
"PhotinoX.Cpp",
"The application has started.",
{},
std::string("startup-notification"));ShowNotification(...) returns:
- a positive notification correlation identifier when accepted;
- 0 when not shown because of policy or application state;
- -1 for an invalid or untracked request;
- -2 when notification backend initialization fails;
- -3 when native notification display fails synchronously.
Notification events include:
- activation;
- action activation;
- input activation;
- dismissal;
- asynchronous failure.
Optional user state is stored using std::any and returned through the terminal notification event.
application.RegisterNotificationActivatedHandler(
[](const NotificationActivatedEventArgs& args)
{
if (const auto* value = std::any_cast<std::string>(&args.state))
{
// Use the associated notification state.
}
});Notification state is released when a terminal callback is received, when the request is rejected, or when the application finishes running.
PhotinoX.Cpp prevents C++ exceptions from crossing the native C ABI boundary.
Synchronous lifecycle callback exceptions are handled as application lifecycle failures:
Startup / ShutdownRequested / Exit
↓
native trampoline catches the exception
↓
the first exception is retained
↓
the application completes or shuts down
↓
Application::Run() rethrows the original exception
Asynchronous callback exceptions are forwarded through the dispatcher:
BeginInvoke / notification handler / window collection handler
↓
native or framework callback catches the exception
↓
Dispatcher::UnhandledException
↓
the application continues running
This preserves structured exception propagation for synchronous application lifetime operations while keeping asynchronous event failures isolated from the native runtime.
PhotinoX.Cpp follows modern C++ conventions instead of reproducing the .NET surface mechanically.
The API uses:
- RAII and deterministic destruction;
- deleted copy and move operations for native lifetime objects;
std::unique_ptrfor implementation ownership;std::string_viewfor synchronous non-owning string inputs and configuration access;std::spanfor temporary contiguous callback payloads;std::vectorfor stable collection snapshots;std::anyfor optional user-defined notification state;std::exception_ptrfor deferred and asynchronous exception propagation;std::atomicfor cross-thread lifecycle state;- typed
enum classvalues; - explicit
[[nodiscard]]contracts; noexceptwhere operations are guaranteed not to throw;- internal PImpl-based implementation isolation;
- CMake FetchContent integration.
Shared behavior is aligned with PhotinoX, but language-specific API design is intentionally preserved.
Examples:
- .NET events map to explicit C++ register, subscribe, and unsubscribe methods.
- .NET
objectnotification state maps tostd::any. - managed observable window collections map to synchronized snapshots and typed collection events.
- asynchronous exception events carry
std::exception_ptr. - native handles and eventpp implementation details remain private.
Add PhotinoX.Cpp to your CMake project using FetchContent:
cmake_minimum_required(VERSION 3.25)
project(
MyApplication
LANGUAGES CXX
)
include(FetchContent)
FetchContent_Declare(
PhotinoXCpp
GIT_REPOSITORY https://github.com/ivanvoyager/PhotinoX.Cpp.git
GIT_TAG v5.3.5
)
FetchContent_MakeAvailable(PhotinoXCpp)
add_executable(MyApplication main.cpp)
target_link_libraries(
MyApplication
PRIVATE
PhotinoX::Cpp
)
target_compile_features(
MyApplication
PRIVATE
cxx_std_20
)
photinox_copy_native_runtime(MyApplication)PhotinoX.Cpp automatically downloads the required PhotinoX.Native runtime for the target platform. Call photinox_copy_native_runtime(<target>) to copy the runtime to the application output directory.
#include <photinox/photinox.hpp>
#include <iostream>
using namespace photinox;
int main()
{
Application application;
Window window(application);
application
.SetName("My PhotinoX Application")
.SetShutdownMode(ShutdownMode::OnMainWindowClose)
.RegisterStartupHandler([]
{
std::cout << "Application started.\n";
})
.RegisterExitHandler([](ExitEventArgs& args)
{
std::cout << "Application exiting with code "
<< args.applicationExitCode
<< ".\n";
});
application.GetDispatcher().RegisterUnhandledExceptionHandler(
[](std::exception_ptr exception)
{
try
{
if (exception)
std::rethrow_exception(exception);
}
catch (const std::exception& error)
{
std::cerr << "Unhandled dispatcher exception: "
<< error.what()
<< '\n';
}
});
window
.SetTitle("My PhotinoX Application")
.LoadString(R"(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My PhotinoX Application</title>
</head>
<body>
<h1>Hello from PhotinoX.Cpp</h1>
</body>
</html>
)");
return application.Run(&window);
}PhotinoX.Cpp uses the same PhotinoX.Native ABI on all supported desktop platforms.
| Platform | Native window system | WebView |
|---|---|---|
| Windows | Win32 | Microsoft Edge WebView2 |
| macOS | Cocoa | WKWebView |
| Linux | GTK 3 | WebKitGTK 4.1 |
PhotinoX.Native owns the native application runtime and platform-specific implementation. PhotinoX.Cpp provides the C++ application framework while keeping platform-specific implementation details isolated behind explicit native interoperability APIs.
| Operating system | Architecture | Native runtime |
|---|---|---|
| Windows | x64 | PhotinoX.Native.dll |
| Windows | ARM64 | PhotinoX.Native.dll |
| Linux | x64 | PhotinoX.Native.so |
| Linux | arm64 | PhotinoX.Native.so |
| macOS | x64 | PhotinoX.Native.dylib |
| macOS | arm64 | PhotinoX.Native.dylib |
The native runtime is resolved from the PhotinoX.Native package and copied next to the application executable by photinox_copy_native_runtime(<target>).
- CMake 3.25 or later
- C++20-compatible compiler
- PhotinoX.Native package for the target platform
- Visual Studio 2022 or later with C++ desktop tools
- Microsoft Edge WebView2 Runtime
- GCC or Clang with C++20 support
- GTK 3 runtime
- WebKitGTK 4.1 runtime
- libnotify runtime
- a desktop notification service for native notifications
For Ubuntu-based environments:
sudo apt-get update
sudo apt-get install \
libgtk-3-0 \
libwebkit2gtk-4.1-0 \
libnotify4- Xcode with a C++20-compatible Apple Clang toolchain
- WKWebView provided by the system WebKit framework
cmake -S . -B build/release \
-DCMAKE_BUILD_TYPE=Release \
-DPHOTINOX_BUILD_SAMPLES=ONcmake --build build/release --config Release- HelloWorld demonstrates application lifetime, window events, WebView messaging, and window collection access.
- ChromelessDragResizeDemo demonstrates a custom title bar with native window dragging and resizing.
- CustomSchemes serves local HTML, CSS, JavaScript, and JSON through a custom URI scheme.
- DialogsDemo demonstrates native file, folder, save, and message dialogs.
- NavigationPolicyDemo demonstrates navigation interception and external browser handling.
- NotificationDiagnostics exercises native notifications, notification events, and application shutdown handling.
- RuntimeDiagnostics displays native runtime, WebView engine, and platform-specific runtime information.
- SplashScreen demonstrates hidden window initialization and a chromeless splash-screen workflow.
- TransparencyDemo demonstrates startup and runtime window transparency.
- WindowDiagnostics exercises window lifecycle, state, geometry, child windows, and typed events.
Photino originally demonstrated that lightweight desktop applications could host Web UI through operating-system WebViews without bundling Electron, while presenting Photino.Native as a foundation for language wrappers targeting C++, Rust, Go, Java, Objective-C, and other environments.
PhotinoX continues that architectural direction as an independently maintained ecosystem:
- PhotinoX.Native evolves the native application runtime and ABI.
- PhotinoX provides the managed reference implementation.
- PhotinoX.Cpp provides the modern C++ framework layer.
- Future language frameworks can target the same application-oriented native ABI.
PhotinoX.Cpp builds on the evolving PhotinoX.Native runtime and follows the shared application semantics established by PhotinoX, while expressing them through an idiomatic modern C++ API.
PhotinoX.Cpp provides the complete application and window framework layer over PhotinoX.Native. Future updates will maintain compatibility and semantic alignment with PhotinoX and PhotinoX.Native as the shared platform evolves.
Issues and PRs are welcome. Keep PRs focused, minimal, and consistent with the rest of PhotinoX.Cpp.
PhotinoX.Cpp is licensed under Apache-2.0.