WebWindow
WebWindow copied to clipboard
Full screen and maximize support
WebWindow.h
WebWindow(AutoString title, WebWindow* parent, WebMessageReceivedCallback webMessageReceivedCallback, bool fullscreen, int x, int y, int width, int height);
WebWindow.Windows.cpp
WebWindow::WebWindow(AutoString title, WebWindow* parent, WebMessageReceivedCallback webMessageReceivedCallback, bool fullscreen, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int width = CW_USEDEFAULT, int height = CW_USEDEFAULT)
{
// Create the window
_webMessageReceivedCallback = webMessageReceivedCallback;
_parent = parent;
if (fullscreen)
{
x = 0;
y = 0;
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
}
_hWnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
title, // Window text
fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW, // Window style
// Size and position
x, y, width, height,
parent ? parent->_hWnd : NULL, // Parent window
NULL, // Menu
_hInstance, // Instance handle
this // Additional application data
);
hwndToWebWindow[_hWnd] = this;
}
WebWindow.Linux.cpp
WebWindow::WebWindow(AutoString title, WebWindow* parent, WebMessageReceivedCallback webMessageReceivedCallback, bool fullscreen, int x, int y, int width, int height) : _webview(nullptr)
{
_webMessageReceivedCallback = webMessageReceivedCallback;
// It makes xlib thread safe.
// Needed for get_position.
XInitThreads();
gtk_init(0, NULL);
_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
if (fullscreen)
{
GdkRectangle geometry = { 0 };
gdk_monitor_get_geometry(gdk_display_get_primary_monitor(gdk_display_get_default()), &geometry);
x = 0;
y = 0;
width = geometry.width;
height = geometry.height;
gtk_window_fullscreen(GTK_WINDOW(_window));
}
gtk_window_move(GTK_WINDOW(_window), x, y);
gtk_window_set_default_size(GTK_WINDOW(_window), width, height);
SetTitle(title);
if (parent == NULL)
{
g_signal_connect(G_OBJECT(_window), "destroy",
G_CALLBACK(+[](GtkWidget* w, gpointer arg) { gtk_main_quit(); }),
this);
g_signal_connect(G_OBJECT(_window), "size-allocate",
G_CALLBACK(on_size_allocate),
this);
g_signal_connect(G_OBJECT(_window), "configure-event",
G_CALLBACK(on_configure_event),
this);
}
}
Exports.cpp
EXPORTED WebWindow* WebWindow_ctor(AutoString title, WebWindow* parent, WebMessageReceivedCallback webMessageReceivedCallback, bool fullscreen, int x, int y, int width, int height)
{
return new WebWindow(title, parent, webMessageReceivedCallback, fullscreen, x, y, width, height);
}
WebWindow.cs
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] static extern IntPtr WebWindow_ctor(string title, IntPtr parentWebWindow, OnWebMessageReceivedCallback webMessageReceivedCallback, bool fullscreen, int x, int y, int width, int height);
public WebWindow(string title, Action<WebWindowOptions> configure, bool fullscreen = false, int x = 0, int y = 0, int width = 800, int height = 600)
{
_ownerThreadId = Thread.CurrentThread.ManagedThreadId;
if (configure is null)
{
throw new ArgumentNullException(nameof(configure));
}
var options = new WebWindowOptions();
configure.Invoke(options);
WriteTitleField(title);
var onWebMessageReceivedDelegate = (OnWebMessageReceivedCallback)ReceiveWebMessage;
_gcHandlesToFree.Add(GCHandle.Alloc(onWebMessageReceivedDelegate));
var parentPtr = options.Parent?._nativeWebWindow ?? default;
_nativeWebWindow = WebWindow_ctor(_title, parentPtr, onWebMessageReceivedDelegate, fullscreen, x, y, width, height);
foreach (var (schemeName, handler) in options.SchemeHandlers)
{
AddCustomScheme(schemeName, handler);
}
var onResizedDelegate = (ResizedCallback)OnResized;
_gcHandlesToFree.Add(GCHandle.Alloc(onResizedDelegate));
WebWindow_SetResizedCallback(_nativeWebWindow, onResizedDelegate);
var onMovedDelegate = (MovedCallback)OnMoved;
_gcHandlesToFree.Add(GCHandle.Alloc(onMovedDelegate));
WebWindow_SetMovedCallback(_nativeWebWindow, onMovedDelegate);
// Auto-show to simplify the API, but more importantly because you can't
// do things like navigate until it has been shown
Show();
}
ComponentsDesktop.cs
public static void Run<TStartup>(string windowTitle, string hostHtmlPath, bool fullscreen = false, int x = 0, int y = 0, int width = 800, int height = 600)
{
DesktopSynchronizationContext.UnhandledException += (sender, exception) =>
{
UnhandledException(exception);
};
WebWindow = new WebWindow(windowTitle, options =>
{
var contentRootAbsolute = Path.GetDirectoryName(Path.GetFullPath(hostHtmlPath));
options.SchemeHandlers.Add(BlazorAppScheme, (string url, out string contentType) =>
{
// TODO: Only intercept for the hostname 'app' and passthrough for others
// TODO: Prevent directory traversal?
var appFile = Path.Combine(contentRootAbsolute, new Uri(url).AbsolutePath.Substring(1));
if (appFile == contentRootAbsolute)
{
appFile = hostHtmlPath;
}
contentType = GetContentType(appFile);
return File.Exists(appFile) ? File.OpenRead(appFile) : null;
});
// framework:// is resolved as embedded resources
options.SchemeHandlers.Add("framework", (string url, out string contentType) =>
{
contentType = GetContentType(url);
return SupplyFrameworkFile(url);
});
}, fullscreen, x, y, width, height);
CancellationTokenSource appLifetimeCts = new CancellationTokenSource();
Task.Factory.StartNew(async () =>
{
try
{
var ipc = new IPC(WebWindow);
await RunAsync<TStartup>(ipc, appLifetimeCts.Token);
}
catch (Exception ex)
{
UnhandledException(ex);
throw;
}
});
try
{
WebWindow.NavigateToUrl(BlazorAppScheme + "://app/");
WebWindow.WaitForExit();
}
finally
{
appLifetimeCts.Cancel();
}
}
What is the status of this issue?