Cross-platform native desktop windows with embedded web views, powered by Rust.
Inspired by Photino.NET.
Rustino replaces Photino's C++ native layer with Rust, using wry for the webview and tao for window management — the same libraries that power Tauri.
Your .NET App
└── RustinoWindow (C#) ← Rustino.NET
└── P/Invoke
└── rustino_native ← Rustino.Native (Rust cdylib)
├── wry → WebView2 (Windows)
├── wry → WKWebView (macOS)
└── wry → WebKitGTK (Linux)
usingRustino.NET;varwindow=newRustinoWindow();window.SetTitle("My App").SetUseOsDefaultSize(false).SetSize(1280,800).SetResizable(true).Center().Load(newUri("https://example.com"));window.WaitForClose();The API is identical. Change two things:
- using Photino.NET;+ using Rustino.NET;- var window = new PhotinoWindow();+ var window = new RustinoWindow();All .Set*(), .Center(), .Load(), and .WaitForClose() calls remain the same.
| Method | Description |
|---|---|
SetTitle(string) | Set the window title |
SetSize(int, int) | Set window dimensions in pixels |
SetMinSize(int, int) | Set minimum window size |
SetMaxSize(int, int) | Set maximum window size |
SetPosition(int, int) | Set window position |
SetUseOsDefaultSize(bool) | Use OS default window size |
SetResizable(bool) | Allow/prevent window resizing |
SetTopMost(bool) | Keep window above all others |
SetChromeless(bool) | Remove window decorations (title bar, borders) |
SetTransparent(bool) | Enable transparent background |
SetMaximized(bool) | Start maximized |
SetBackgroundColor(r, g, b, a) | Set webview background color |
SetIconFile(string) | Set window icon from .ico/.png file path |
SetIcon(Stream) | Set window icon from a .NET stream (e.g. embedded resource) |
Center() | Center window on the primary monitor |
SetDevToolsEnabled(bool) | Enable browser developer tools |
SetJavascriptClipboardAccessEnabled(bool) | Allow JS clipboard access |
SetIgnoreCertificateErrorsEnabled(bool) | Ignore SSL certificate errors |
SetWebSecurityEnabled(bool) | Enable/disable web security (CORS, etc.) |
SetMediaAutoplayEnabled(bool) | Allow media to autoplay |
SetZoomHotkeysEnabled(bool) | Enable Ctrl+/- zoom hotkeys |
SetUserAgent(string) | Set custom user agent string |
SetUserDataFolder(string) | Set webview data folder path |
AddInitScript(string) | Add JavaScript to run before page loads |
Load(Uri) / Load(string) | Navigate to a URL or local file |
LogVerbosity | Set log verbosity (0 = silent) |
| Method | Description |
|---|---|
Minimize() | Minimize the window |
Maximize() | Maximize the window |
Restore() | Restore from minimized/maximized |
SetFullscreen(bool) | Enter/exit fullscreen |
SetVisible(bool) | Show/hide the window |
Focus() | Bring focus to the window |
Close() | Close the window |
ExecuteScript(string) | Evaluate JavaScript in the webview |
SendWebMessage(string) | Post a message to the webview |
SetZoom(double) | Set webview zoom factor |
SetBadgeCount(int?, string?, string?) | Set taskbar/dock badge with optional bg/fg hex colors |
ClearBadge() | Remove the taskbar/dock badge |
WaitForClose() | Block until the window is closed |
Dispose() | Release native resources (RustinoWindow implements IDisposable) |
Native cross-platform file dialogs (powered by rfd):
// Open file (single)string[]?files=window.ShowOpenFileDialog(title:"Select an image",filters:[newFileFilter("Images","jpg","png","gif")]);// Open files (multi-select)string[]?files=window.ShowOpenFileDialog(title:"Select files",multiSelect:true);// Save filestring?path=window.ShowSaveFileDialog(title:"Save as",defaultPath:"document.pdf",filters:[newFileFilter("PDF","pdf")]);// Select folderstring[]?folders=window.ShowSelectFolderDialog(title:"Choose output directory");All dialogs return null when canceled. File filters use the format new FileFilter("Name", "ext1", "ext2", ...).
Native cross-platform toast notifications (powered by notify-rust):
// Static — no window instance requiredRustinoWindow.ShowNotification("Download Complete","Your file has been saved.");// With icon (file path)RustinoWindow.ShowNotification("Alert","Something happened",iconPath:"/path/to/icon.png");// With icon (embedded resource stream)usingvarstream=Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApp.notify.png")!;RustinoWindow.ShowNotification("Alert","Something happened",stream);Uses WinRT Toast (Windows), NSUserNotification (macOS), and D-Bus (Linux).
Native cross-platform application menus and context menus (powered by muda):
// Application menu barvarmenu=newRustinoMenu().AddSubmenu("File", file =>file.AddItem("new","New",accelerator:"CmdOrCtrl+N").AddItem("open","Open...",accelerator:"CmdOrCtrl+O").AddSeparator().AddItem("exit","Exit")).AddSubmenu("Edit", edit =>edit.AddItem("undo","Undo",accelerator:"CmdOrCtrl+Z").AddItem("redo","Redo",accelerator:"CmdOrCtrl+Y").AddSeparator().AddCheckItem("wordwrap","Word Wrap",isChecked:true)).AddSubmenu("Help", help =>help.AddItem("about","About"));window.SetMenu(menu);// Context menu (right-click)varctx=newRustinoMenu().AddItem("cut","Cut").AddItem("copy","Copy").AddItem("paste","Paste");window.ShowContextMenu(ctx);// Handle clickswindow.MenuItemClicked+=(_,id)=>Console.WriteLine($"Clicked: {id}");// Remove menu barwindow.RemoveMenu();Native cross-platform system tray icon with optional context menu (powered by tray-icon):
// Tray icon with tooltip and context menuvartrayMenu=newRustinoMenu().AddItem("show","Show Window").AddItem("hide","Hide Window").AddSeparator().AddItem("quit","Quit");window.SetTrayIcon("icon.png",tooltip:"My App",menu:trayMenu);// From embedded resource (Stream)usingvarstream=Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApp.tray.png")!;window.SetTrayIcon(stream,tooltip:"My App",menu:trayMenu);// Handle tray icon clickswindow.TrayIconClicked+=(_,_)=>window.SetVisible(true);// Remove tray iconwindow.RemoveTrayIcon();Set a numeric badge on the taskbar icon (Windows) or dock icon (macOS):
// Set badge with default colors (red background, white text)window.SetBadgeCount(5);// Set badge with custom colors (Windows only, hex format)window.SetBadgeCount(5,background:"#4A154B",foreground:"#FFFFFF");// Clear the badgewindow.ClearBadge();On Windows, this renders an overlay icon on the taskbar button using a 32px anti-aliased circle with bold Segoe UI text. Numbers above 99 display as "99+". The background and foreground parameters accept #RRGGBB hex strings and default to #E01E5A (red) and #FFFFFF (white).
On macOS, the native dockTile.setBadgeLabel API is used — color parameters are ignored as the OS controls badge appearance.
Enumerate connected displays with position, resolution, and DPI scale factor:
// Get all monitorsMonitorInfo[]monitors=window.GetMonitors();foreach(varminmonitors)Console.WriteLine($"{m.Name}: {m.Width}x{m.Height} at ({m.X},{m.Y}), scale={m.ScaleFactor}, primary={m.IsPrimary}");// Get the monitor containing this windowMonitorInfo?current=window.GetCurrentMonitor();// DPI-aware positioning: center window on a specific monitorvartarget=monitors.First(m =>!m.IsPrimary);var(w,h)=window.GetSize();window.SetPosition(target.X+(target.Width-w)/2,target.Y+(target.Height-h)/2);MonitorInfo properties: Name, X, Y, Width, Height, ScaleFactor, IsPrimary.
| Property | Description |
|---|---|
IsMinimized | Whether the window is minimized |
IsMaximized | Whether the window is maximized |
IsFullscreen | Whether the window is in fullscreen |
GetPosition() | Returns (X, Y) position |
GetSize() | Returns (Width, Height) size |
GetMonitors() | Returns all connected MonitorInfo[] |
GetCurrentMonitor() | Returns MonitorInfo? for the monitor containing the window |
| Event | Args | Description |
|---|---|---|
WindowClosing | CancelEventArgs | Fired before close (set Cancel = true to prevent) |
WindowClosed | EventArgs | Fired after the window is destroyed |
SizeChanged | SizeEventArgs | Fired on resize (.Width, .Height) |
LocationChanged | PointEventArgs | Fired on move (.X, .Y) |
FocusChanged | bool | Fired on focus/blur |
WebMessageReceived | string | Fired when JS calls window.ipc.postMessage(msg) |
PageLoaded | PageLoadEventArgs | Fired on page load start/finish (.IsStarted, .Url) |
Navigating | NavigationEventArgs | Fired before navigation (.Url, set Cancel = true to block) |
MenuItemClicked | string | Fired when a menu item is clicked (the item's ID) |
TrayIconClicked | EventArgs | Fired when the system tray icon is clicked |
All events are also available as IObservable<T> properties for reactive programming (no System.Reactive dependency required):
| Property | Type | Description |
|---|---|---|
WhenSizeChanged | IObservable<(int Width, int Height)> | Size change stream |
WhenLocationChanged | IObservable<(int X, int Y)> | Position change stream |
WhenFocusChanged | IObservable<bool> | Focus/blur stream |
WhenWebMessageReceived | IObservable<string> | JS message stream |
WhenPageLoaded | IObservable<PageLoadEventArgs> | Page load stream |
WhenNavigating | IObservable<NavigationEventArgs> | Navigation stream |
WhenWindowClosed | IObservable<EventArgs> | Window closed stream |
WhenMenuItemClicked | IObservable<string> | Menu item click stream |
WhenTrayIconClicked | IObservable<EventArgs> | Tray icon click stream |
All streams complete automatically when the window closes or is disposed.
For System.Reactive operators, add the Rustino.NET.Reactive package:
usingSystem.Reactive.Linq;usingRustino.NET.Reactive;// Throttled resizewindow.WhenSizeChangedThrottled(TimeSpan.FromMilliseconds(200)).Subscribe(size =>Console.WriteLine($"{size.Width}x{size.Height}"));// Message routing by prefixwindow.WhenWebMessageWithPrefix("cmd:").Subscribe(cmd =>HandleCommand(cmd));// Page load completion onlywindow.WhenPageLoadCompleted().Subscribe(e =>Console.WriteLine($"Loaded: {e.Url}"));// Throttled move eventswindow.WhenLocationChangedThrottled(TimeSpan.FromMilliseconds(100)).Subscribe(pos =>Console.WriteLine($"Moved to {pos.X},{pos.Y}"));// Distinct focus changeswindow.WhenFocusChangedDistinct().Subscribe(focused =>Console.WriteLine($"Focus: {focused}"));- Rust toolchain (1.80+)
- .NET SDK (10.0+)
- Windows: WebView2 runtime (pre-installed on Windows 10/11)
- macOS: Xcode Command Line Tools
- Linux:
libgtk-3-dev libwebkit2gtk-4.1-dev
# Build the Rust native librarycd src/Rustino.Native
cargo build --release
# Build the .NET wrappercd ../Rustino.NET
dotnet build
# Run a samplecd ../Rustino.Samples/Rustino.Samples.HelloWorld
dotnet run| Platform | WebView Engine | Native Library |
|---|---|---|
| Windows x64/ARM64 | WebView2 (Chromium) | rustino_native.dll |
| macOS x64/ARM64 | WKWebView (WebKit) | librustino_native.dylib |
| Linux x64/ARM64 | WebKitGTK | librustino_native.so |
MIT — see LICENSE.
Inspired by and API-compatible with Photino, originally created by TryPhotino (Apache-2.0).