2
0
Files
Dave Friedel f7043ab9c7 Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext

Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method

Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method

Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator

Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods

Build: SUCCESS (0 errors)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00

257 lines
9.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Microsoft.Maui.Platform.Linux.Native;
internal static class WebKitNative
{
private delegate IntPtr WebKitWebViewNewDelegate();
private delegate void WebKitWebViewLoadUriDelegate(IntPtr webView, string uri);
private delegate void WebKitWebViewLoadHtmlDelegate(IntPtr webView, string content, string? baseUri);
private delegate IntPtr WebKitWebViewGetUriDelegate(IntPtr webView);
private delegate IntPtr WebKitWebViewGetTitleDelegate(IntPtr webView);
private delegate void WebKitWebViewGoBackDelegate(IntPtr webView);
private delegate void WebKitWebViewGoForwardDelegate(IntPtr webView);
private delegate bool WebKitWebViewCanGoBackDelegate(IntPtr webView);
private delegate bool WebKitWebViewCanGoForwardDelegate(IntPtr webView);
private delegate void WebKitWebViewReloadDelegate(IntPtr webView);
private delegate void WebKitWebViewStopLoadingDelegate(IntPtr webView);
private delegate IntPtr WebKitWebViewGetSettingsDelegate(IntPtr webView);
private delegate void WebKitSettingsSetHardwareAccelerationPolicyDelegate(IntPtr settings, int policy);
private delegate void WebKitSettingsSetEnableJavascriptDelegate(IntPtr settings, bool enabled);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LoadChangedCallback(IntPtr webView, int loadEvent, IntPtr userData);
private delegate ulong GSignalConnectDataDelegate(IntPtr instance, string signalName, LoadChangedCallback callback, IntPtr userData, IntPtr destroyNotify, int connectFlags);
public enum WebKitLoadEvent
{
Started,
Redirected,
Committed,
Finished
}
private static IntPtr _handle;
private static bool _initialized;
private static readonly string[] LibraryNames = new string[4]
{
"libwebkit2gtk-4.1.so.0",
"libwebkit2gtk-4.0.so.37",
"libwebkit2gtk-4.0.so",
"libwebkit2gtk-4.1.so"
};
private static WebKitWebViewNewDelegate? _webkitWebViewNew;
private static WebKitWebViewLoadUriDelegate? _webkitLoadUri;
private static WebKitWebViewLoadHtmlDelegate? _webkitLoadHtml;
private static WebKitWebViewGetUriDelegate? _webkitGetUri;
private static WebKitWebViewGetTitleDelegate? _webkitGetTitle;
private static WebKitWebViewGoBackDelegate? _webkitGoBack;
private static WebKitWebViewGoForwardDelegate? _webkitGoForward;
private static WebKitWebViewCanGoBackDelegate? _webkitCanGoBack;
private static WebKitWebViewCanGoForwardDelegate? _webkitCanGoForward;
private static WebKitWebViewReloadDelegate? _webkitReload;
private static WebKitWebViewStopLoadingDelegate? _webkitStopLoading;
private static WebKitWebViewGetSettingsDelegate? _webkitGetSettings;
private static WebKitSettingsSetHardwareAccelerationPolicyDelegate? _webkitSetHardwareAccel;
private static WebKitSettingsSetEnableJavascriptDelegate? _webkitSetJavascript;
private static GSignalConnectDataDelegate? _gSignalConnectData;
private static readonly Dictionary<IntPtr, LoadChangedCallback> _loadChangedCallbacks = new Dictionary<IntPtr, LoadChangedCallback>();
private const int RTLD_NOW = 2;
private const int RTLD_GLOBAL = 256;
private static IntPtr _gobjectHandle;
[DllImport("libdl.so.2")]
private static extern IntPtr dlopen(string? filename, int flags);
[DllImport("libdl.so.2")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so.2")]
private static extern IntPtr dlerror();
public static bool Initialize()
{
if (_initialized)
{
return _handle != IntPtr.Zero;
}
_initialized = true;
string[] libraryNames = LibraryNames;
foreach (string text in libraryNames)
{
_handle = dlopen(text, 258);
if (_handle != IntPtr.Zero)
{
Console.WriteLine("[WebKitNative] Loaded " + text);
break;
}
}
if (_handle == IntPtr.Zero)
{
Console.WriteLine("[WebKitNative] Failed to load WebKitGTK library");
return false;
}
_webkitWebViewNew = LoadFunction<WebKitWebViewNewDelegate>("webkit_web_view_new");
_webkitLoadUri = LoadFunction<WebKitWebViewLoadUriDelegate>("webkit_web_view_load_uri");
_webkitLoadHtml = LoadFunction<WebKitWebViewLoadHtmlDelegate>("webkit_web_view_load_html");
_webkitGetUri = LoadFunction<WebKitWebViewGetUriDelegate>("webkit_web_view_get_uri");
_webkitGetTitle = LoadFunction<WebKitWebViewGetTitleDelegate>("webkit_web_view_get_title");
_webkitGoBack = LoadFunction<WebKitWebViewGoBackDelegate>("webkit_web_view_go_back");
_webkitGoForward = LoadFunction<WebKitWebViewGoForwardDelegate>("webkit_web_view_go_forward");
_webkitCanGoBack = LoadFunction<WebKitWebViewCanGoBackDelegate>("webkit_web_view_can_go_back");
_webkitCanGoForward = LoadFunction<WebKitWebViewCanGoForwardDelegate>("webkit_web_view_can_go_forward");
_webkitReload = LoadFunction<WebKitWebViewReloadDelegate>("webkit_web_view_reload");
_webkitStopLoading = LoadFunction<WebKitWebViewStopLoadingDelegate>("webkit_web_view_stop_loading");
_webkitGetSettings = LoadFunction<WebKitWebViewGetSettingsDelegate>("webkit_web_view_get_settings");
_webkitSetHardwareAccel = LoadFunction<WebKitSettingsSetHardwareAccelerationPolicyDelegate>("webkit_settings_set_hardware_acceleration_policy");
_webkitSetJavascript = LoadFunction<WebKitSettingsSetEnableJavascriptDelegate>("webkit_settings_set_enable_javascript");
_gobjectHandle = dlopen("libgobject-2.0.so.0", 258);
if (_gobjectHandle != IntPtr.Zero)
{
IntPtr intPtr = dlsym(_gobjectHandle, "g_signal_connect_data");
if (intPtr != IntPtr.Zero)
{
_gSignalConnectData = Marshal.GetDelegateForFunctionPointer<GSignalConnectDataDelegate>(intPtr);
Console.WriteLine("[WebKitNative] Loaded g_signal_connect_data");
}
}
return _webkitWebViewNew != null;
}
private static T? LoadFunction<T>(string name) where T : Delegate
{
if (_handle == IntPtr.Zero)
{
return null;
}
IntPtr intPtr = dlsym(_handle, name);
if (intPtr == IntPtr.Zero)
{
return null;
}
return Marshal.GetDelegateForFunctionPointer<T>(intPtr);
}
public static IntPtr WebViewNew()
{
if (!Initialize() || _webkitWebViewNew == null)
{
return IntPtr.Zero;
}
return _webkitWebViewNew();
}
public static void LoadUri(IntPtr webView, string uri)
{
_webkitLoadUri?.Invoke(webView, uri);
}
public static void LoadHtml(IntPtr webView, string content, string? baseUri = null)
{
_webkitLoadHtml?.Invoke(webView, content, baseUri);
}
public static string? GetUri(IntPtr webView)
{
IntPtr intPtr = _webkitGetUri?.Invoke(webView) ?? IntPtr.Zero;
if (intPtr == IntPtr.Zero)
{
return null;
}
return Marshal.PtrToStringUTF8(intPtr);
}
public static string? GetTitle(IntPtr webView)
{
IntPtr intPtr = _webkitGetTitle?.Invoke(webView) ?? IntPtr.Zero;
if (intPtr == IntPtr.Zero)
{
return null;
}
return Marshal.PtrToStringUTF8(intPtr);
}
public static void GoBack(IntPtr webView)
{
_webkitGoBack?.Invoke(webView);
}
public static void GoForward(IntPtr webView)
{
_webkitGoForward?.Invoke(webView);
}
public static bool CanGoBack(IntPtr webView)
{
return _webkitCanGoBack?.Invoke(webView) ?? false;
}
public static bool CanGoForward(IntPtr webView)
{
return _webkitCanGoForward?.Invoke(webView) ?? false;
}
public static void Reload(IntPtr webView)
{
_webkitReload?.Invoke(webView);
}
public static void StopLoading(IntPtr webView)
{
_webkitStopLoading?.Invoke(webView);
}
public static void ConfigureSettings(IntPtr webView, bool disableHardwareAccel = true)
{
if (_webkitGetSettings != null)
{
IntPtr intPtr = _webkitGetSettings(webView);
if (intPtr != IntPtr.Zero && disableHardwareAccel && _webkitSetHardwareAccel != null)
{
_webkitSetHardwareAccel(intPtr, 2);
}
}
}
public static void SetJavascriptEnabled(IntPtr webView, bool enabled)
{
if (_webkitGetSettings != null && _webkitSetJavascript != null)
{
IntPtr intPtr = _webkitGetSettings(webView);
if (intPtr != IntPtr.Zero)
{
_webkitSetJavascript(intPtr, enabled);
}
}
}
public static ulong ConnectLoadChanged(IntPtr webView, LoadChangedCallback callback)
{
if (_gSignalConnectData == null || webView == IntPtr.Zero)
{
Console.WriteLine("[WebKitNative] Cannot connect load-changed: signal connect not available");
return 0uL;
}
_loadChangedCallbacks[webView] = callback;
return _gSignalConnectData(webView, "load-changed", callback, IntPtr.Zero, IntPtr.Zero, 0);
}
public static void DisconnectLoadChanged(IntPtr webView)
{
_loadChangedCallbacks.Remove(webView);
}
}