Verify Views files against decompiled, extract embedded types
Fixed files: - SkiaImageButton.cs: Added SVG support with multi-path search - SkiaNavigationPage.cs: Added LinuxApplication.IsGtkMode check - SkiaRefreshView.cs: Added ICommand support (Command, CommandParameter) - SkiaTemplatedView.cs: Added missing using statements Extracted embedded types to separate files (matching decompiled pattern): - From SkiaMenuBar.cs: MenuBarItem, MenuItem, SkiaMenuFlyout, MenuItemClickedEventArgs - From SkiaNavigationPage.cs: NavigationEventArgs - From SkiaTabbedPage.cs: TabItem - From SkiaVisualStateManager.cs: SkiaVisualStateGroupList, SkiaVisualStateGroup, SkiaVisualState, SkiaVisualStateSetter - From SkiaSwipeView.cs: SwipeItem, SwipeStartedEventArgs, SwipeEndedEventArgs - From SkiaFlyoutPage.cs: FlyoutLayoutBehavior (already separate) - From SkiaIndicatorView.cs: IndicatorShape (already separate) - From SkiaBorder.cs: SkiaFrame - From SkiaCarouselView.cs: PositionChangedEventArgs - From SkiaCollectionView.cs: SkiaSelectionMode, ItemsLayoutOrientation - From SkiaContentPresenter.cs: LayoutAlignment Verified matching decompiled: - SkiaContextMenu.cs, SkiaFlexLayout.cs, SkiaGraphicsView.cs Build: 0 errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
182
AnimationManager.cs
Normal file
182
AnimationManager.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux;
|
||||
|
||||
public static class AnimationManager
|
||||
{
|
||||
private class RunningAnimation
|
||||
{
|
||||
public required SkiaView View { get; set; }
|
||||
public string PropertyName { get; set; } = "";
|
||||
public double StartValue { get; set; }
|
||||
public double EndValue { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public uint Duration { get; set; }
|
||||
public Easing Easing { get; set; } = Easing.Linear;
|
||||
public required TaskCompletionSource<bool> Completion { get; set; }
|
||||
public CancellationToken Token { get; set; }
|
||||
}
|
||||
|
||||
private static readonly List<RunningAnimation> _animations = new();
|
||||
private static bool _isRunning;
|
||||
private static CancellationTokenSource? _cts;
|
||||
|
||||
private static void EnsureRunning()
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_isRunning = true;
|
||||
_cts = new CancellationTokenSource();
|
||||
_ = RunAnimationLoop(_cts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunAnimationLoop(CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested && _animations.Count > 0)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var completed = new List<RunningAnimation>();
|
||||
|
||||
foreach (var animation in _animations.ToList())
|
||||
{
|
||||
if (animation.Token.IsCancellationRequested)
|
||||
{
|
||||
completed.Add(animation);
|
||||
animation.Completion.TrySetResult(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var progress = Math.Clamp(
|
||||
(now - animation.StartTime).TotalMilliseconds / animation.Duration,
|
||||
0.0, 1.0);
|
||||
|
||||
var easedProgress = animation.Easing.Ease(progress);
|
||||
var value = animation.StartValue + (animation.EndValue - animation.StartValue) * easedProgress;
|
||||
|
||||
SetProperty(animation.View, animation.PropertyName, value);
|
||||
|
||||
if (progress >= 1.0)
|
||||
{
|
||||
completed.Add(animation);
|
||||
animation.Completion.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var animation in completed)
|
||||
{
|
||||
_animations.Remove(animation);
|
||||
}
|
||||
|
||||
if (_animations.Count == 0)
|
||||
{
|
||||
_isRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(16, token);
|
||||
}
|
||||
|
||||
_isRunning = false;
|
||||
}
|
||||
|
||||
private static void SetProperty(SkiaView view, string propertyName, double value)
|
||||
{
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(SkiaView.Opacity):
|
||||
view.Opacity = (float)value;
|
||||
break;
|
||||
case nameof(SkiaView.Scale):
|
||||
view.Scale = value;
|
||||
break;
|
||||
case nameof(SkiaView.ScaleX):
|
||||
view.ScaleX = value;
|
||||
break;
|
||||
case nameof(SkiaView.ScaleY):
|
||||
view.ScaleY = value;
|
||||
break;
|
||||
case nameof(SkiaView.Rotation):
|
||||
view.Rotation = value;
|
||||
break;
|
||||
case nameof(SkiaView.RotationX):
|
||||
view.RotationX = value;
|
||||
break;
|
||||
case nameof(SkiaView.RotationY):
|
||||
view.RotationY = value;
|
||||
break;
|
||||
case nameof(SkiaView.TranslationX):
|
||||
view.TranslationX = value;
|
||||
break;
|
||||
case nameof(SkiaView.TranslationY):
|
||||
view.TranslationY = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static double GetProperty(SkiaView view, string propertyName)
|
||||
{
|
||||
return propertyName switch
|
||||
{
|
||||
nameof(SkiaView.Opacity) => view.Opacity,
|
||||
nameof(SkiaView.Scale) => view.Scale,
|
||||
nameof(SkiaView.ScaleX) => view.ScaleX,
|
||||
nameof(SkiaView.ScaleY) => view.ScaleY,
|
||||
nameof(SkiaView.Rotation) => view.Rotation,
|
||||
nameof(SkiaView.RotationX) => view.RotationX,
|
||||
nameof(SkiaView.RotationY) => view.RotationY,
|
||||
nameof(SkiaView.TranslationX) => view.TranslationX,
|
||||
nameof(SkiaView.TranslationY) => view.TranslationY,
|
||||
_ => 0.0
|
||||
};
|
||||
}
|
||||
|
||||
public static Task<bool> AnimateAsync(
|
||||
SkiaView view,
|
||||
string propertyName,
|
||||
double targetValue,
|
||||
uint length = 250,
|
||||
Easing? easing = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
CancelAnimation(view, propertyName);
|
||||
|
||||
var animation = new RunningAnimation
|
||||
{
|
||||
View = view,
|
||||
PropertyName = propertyName,
|
||||
StartValue = GetProperty(view, propertyName),
|
||||
EndValue = targetValue,
|
||||
StartTime = DateTime.UtcNow,
|
||||
Duration = length,
|
||||
Easing = easing ?? Easing.Linear,
|
||||
Completion = new TaskCompletionSource<bool>(),
|
||||
Token = cancellationToken
|
||||
};
|
||||
|
||||
_animations.Add(animation);
|
||||
EnsureRunning();
|
||||
|
||||
return animation.Completion.Task;
|
||||
}
|
||||
|
||||
public static void CancelAnimation(SkiaView view, string propertyName)
|
||||
{
|
||||
var animation = _animations.FirstOrDefault(a => a.View == view && a.PropertyName == propertyName);
|
||||
if (animation != null)
|
||||
{
|
||||
_animations.Remove(animation);
|
||||
animation.Completion.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CancelAnimations(SkiaView view)
|
||||
{
|
||||
foreach (var animation in _animations.Where(a => a.View == view).ToList())
|
||||
{
|
||||
_animations.Remove(animation);
|
||||
animation.Completion.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Converters/ColorExtensions.cs
Normal file
20
Converters/ColorExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Graphics;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Converters;
|
||||
|
||||
public static class ColorExtensions
|
||||
{
|
||||
public static SKColor ToSKColor(this Color color)
|
||||
{
|
||||
return SKColorTypeConverter.ToSKColor(color);
|
||||
}
|
||||
|
||||
public static Color ToMauiColor(this SKColor color)
|
||||
{
|
||||
return SKColorTypeConverter.ToMauiColor(color);
|
||||
}
|
||||
}
|
||||
@@ -235,25 +235,3 @@ public class SKColorTypeConverter : TypeConverter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for color conversion.
|
||||
/// </summary>
|
||||
public static class ColorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a MAUI Color to an SKColor.
|
||||
/// </summary>
|
||||
public static SKColor ToSKColor(this Color color)
|
||||
{
|
||||
return SKColorTypeConverter.ToSKColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an SKColor to a MAUI Color.
|
||||
/// </summary>
|
||||
public static Color ToMauiColor(this SKColor color)
|
||||
{
|
||||
return SKColorTypeConverter.ToMauiColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
75
Converters/SKPointTypeConverter.cs
Normal file
75
Converters/SKPointTypeConverter.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Microsoft.Maui.Graphics;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Converters;
|
||||
|
||||
public class SKPointTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) || sourceType == typeof(Point) || base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) || destinationType == typeof(Point) || base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||
{
|
||||
if (value is Point point)
|
||||
{
|
||||
return new SKPoint((float)point.X, (float)point.Y);
|
||||
}
|
||||
|
||||
if (value is string str)
|
||||
{
|
||||
return ParsePoint(str);
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||
{
|
||||
if (value is SKPoint point)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
return $"{point.X},{point.Y}";
|
||||
}
|
||||
|
||||
if (destinationType == typeof(Point))
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
private static SKPoint ParsePoint(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return SKPoint.Empty;
|
||||
}
|
||||
|
||||
str = str.Trim();
|
||||
var parts = str.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length == 2 &&
|
||||
float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var x) &&
|
||||
float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var y))
|
||||
{
|
||||
return new SKPoint(x, y);
|
||||
}
|
||||
|
||||
return SKPoint.Empty;
|
||||
}
|
||||
}
|
||||
@@ -137,192 +137,3 @@ public class SKRectTypeConverter : TypeConverter
|
||||
return SKRect.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type converter for SKSize.
|
||||
/// </summary>
|
||||
public class SKSizeTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) ||
|
||||
sourceType == typeof(Size) ||
|
||||
base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) ||
|
||||
destinationType == typeof(Size) ||
|
||||
base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||
{
|
||||
if (value is Size size)
|
||||
{
|
||||
return new SKSize((float)size.Width, (float)size.Height);
|
||||
}
|
||||
|
||||
if (value is string str)
|
||||
{
|
||||
return ParseSize(str);
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||
{
|
||||
if (value is SKSize size)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
return $"{size.Width},{size.Height}";
|
||||
}
|
||||
|
||||
if (destinationType == typeof(Size))
|
||||
{
|
||||
return new Size(size.Width, size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
private static SKSize ParseSize(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return SKSize.Empty;
|
||||
|
||||
str = str.Trim();
|
||||
var parts = str.Split(new[] { ',', ' ', 'x', 'X' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length == 1)
|
||||
{
|
||||
if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var uniform))
|
||||
{
|
||||
return new SKSize(uniform, uniform);
|
||||
}
|
||||
}
|
||||
else if (parts.Length == 2)
|
||||
{
|
||||
if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width) &&
|
||||
float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height))
|
||||
{
|
||||
return new SKSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
return SKSize.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type converter for SKPoint.
|
||||
/// </summary>
|
||||
public class SKPointTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) ||
|
||||
sourceType == typeof(Point) ||
|
||||
base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) ||
|
||||
destinationType == typeof(Point) ||
|
||||
base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||
{
|
||||
if (value is Point point)
|
||||
{
|
||||
return new SKPoint((float)point.X, (float)point.Y);
|
||||
}
|
||||
|
||||
if (value is string str)
|
||||
{
|
||||
return ParsePoint(str);
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||
{
|
||||
if (value is SKPoint point)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
return $"{point.X},{point.Y}";
|
||||
}
|
||||
|
||||
if (destinationType == typeof(Point))
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
private static SKPoint ParsePoint(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return SKPoint.Empty;
|
||||
|
||||
str = str.Trim();
|
||||
var parts = str.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var x) &&
|
||||
float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var y))
|
||||
{
|
||||
return new SKPoint(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
return SKPoint.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for SkiaSharp type conversions.
|
||||
/// </summary>
|
||||
public static class SKTypeExtensions
|
||||
{
|
||||
public static SKRect ToSKRect(this Thickness thickness)
|
||||
{
|
||||
return SKRectTypeConverter.ThicknessToSKRect(thickness);
|
||||
}
|
||||
|
||||
public static Thickness ToThickness(this SKRect rect)
|
||||
{
|
||||
return SKRectTypeConverter.SKRectToThickness(rect);
|
||||
}
|
||||
|
||||
public static SKSize ToSKSize(this Size size)
|
||||
{
|
||||
return new SKSize((float)size.Width, (float)size.Height);
|
||||
}
|
||||
|
||||
public static Size ToSize(this SKSize size)
|
||||
{
|
||||
return new Size(size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static SKPoint ToSKPoint(this Point point)
|
||||
{
|
||||
return new SKPoint((float)point.X, (float)point.Y);
|
||||
}
|
||||
|
||||
public static Point ToPoint(this SKPoint point)
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
|
||||
82
Converters/SKSizeTypeConverter.cs
Normal file
82
Converters/SKSizeTypeConverter.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Microsoft.Maui.Graphics;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Converters;
|
||||
|
||||
public class SKSizeTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) || sourceType == typeof(Size) || base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) || destinationType == typeof(Size) || base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||
{
|
||||
if (value is Size size)
|
||||
{
|
||||
return new SKSize((float)size.Width, (float)size.Height);
|
||||
}
|
||||
|
||||
if (value is string str)
|
||||
{
|
||||
return ParseSize(str);
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||
{
|
||||
if (value is SKSize size)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
return $"{size.Width},{size.Height}";
|
||||
}
|
||||
|
||||
if (destinationType == typeof(Size))
|
||||
{
|
||||
return new Size(size.Width, size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
private static SKSize ParseSize(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return SKSize.Empty;
|
||||
}
|
||||
|
||||
str = str.Trim();
|
||||
var parts = str.Split(new[] { ',', ' ', 'x', 'X' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length == 1)
|
||||
{
|
||||
if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var single))
|
||||
{
|
||||
return new SKSize(single, single);
|
||||
}
|
||||
}
|
||||
else if (parts.Length == 2 &&
|
||||
float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width) &&
|
||||
float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height))
|
||||
{
|
||||
return new SKSize(width, height);
|
||||
}
|
||||
|
||||
return SKSize.Empty;
|
||||
}
|
||||
}
|
||||
40
Converters/SKTypeExtensions.cs
Normal file
40
Converters/SKTypeExtensions.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Graphics;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Converters;
|
||||
|
||||
public static class SKTypeExtensions
|
||||
{
|
||||
public static SKRect ToSKRect(this Thickness thickness)
|
||||
{
|
||||
return SKRectTypeConverter.ThicknessToSKRect(thickness);
|
||||
}
|
||||
|
||||
public static Thickness ToThickness(this SKRect rect)
|
||||
{
|
||||
return SKRectTypeConverter.SKRectToThickness(rect);
|
||||
}
|
||||
|
||||
public static SKSize ToSKSize(this Size size)
|
||||
{
|
||||
return new SKSize((float)size.Width, (float)size.Height);
|
||||
}
|
||||
|
||||
public static Size ToSize(this SKSize size)
|
||||
{
|
||||
return new Size(size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static SKPoint ToSKPoint(this Point point)
|
||||
{
|
||||
return new SKPoint((float)point.X, (float)point.Y);
|
||||
}
|
||||
|
||||
public static Point ToPoint(this SKPoint point)
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
11
DisplayServerType.cs
Normal file
11
DisplayServerType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux;
|
||||
|
||||
public enum DisplayServerType
|
||||
{
|
||||
Auto,
|
||||
X11,
|
||||
Wayland
|
||||
}
|
||||
52
Easing.cs
Normal file
52
Easing.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux;
|
||||
|
||||
public class Easing
|
||||
{
|
||||
private readonly Func<double, double> _easingFunc;
|
||||
|
||||
public static readonly Easing Linear = new(v => v);
|
||||
|
||||
public static readonly Easing SinIn = new(v => 1.0 - Math.Cos(v * Math.PI / 2.0));
|
||||
|
||||
public static readonly Easing SinOut = new(v => Math.Sin(v * Math.PI / 2.0));
|
||||
|
||||
public static readonly Easing SinInOut = new(v => -(Math.Cos(Math.PI * v) - 1.0) / 2.0);
|
||||
|
||||
public static readonly Easing CubicIn = new(v => v * v * v);
|
||||
|
||||
public static readonly Easing CubicOut = new(v => 1.0 - Math.Pow(1.0 - v, 3.0));
|
||||
|
||||
public static readonly Easing CubicInOut = new(v =>
|
||||
v < 0.5 ? 4.0 * v * v * v : 1.0 - Math.Pow(-2.0 * v + 2.0, 3.0) / 2.0);
|
||||
|
||||
public static readonly Easing BounceIn = new(v => 1.0 - BounceOut.Ease(1.0 - v));
|
||||
|
||||
public static readonly Easing BounceOut = new(v =>
|
||||
{
|
||||
const double n1 = 7.5625;
|
||||
const double d1 = 2.75;
|
||||
|
||||
if (v < 1 / d1)
|
||||
return n1 * v * v;
|
||||
if (v < 2 / d1)
|
||||
return n1 * (v -= 1.5 / d1) * v + 0.75;
|
||||
if (v < 2.5 / d1)
|
||||
return n1 * (v -= 2.25 / d1) * v + 0.9375;
|
||||
return n1 * (v -= 2.625 / d1) * v + 0.984375;
|
||||
});
|
||||
|
||||
public static readonly Easing SpringIn = new(v => v * v * (2.70158 * v - 1.70158));
|
||||
|
||||
public static readonly Easing SpringOut = new(v =>
|
||||
(v - 1.0) * (v - 1.0) * (2.70158 * (v - 1.0) + 1.70158) + 1.0);
|
||||
|
||||
public Easing(Func<double, double> easingFunc)
|
||||
{
|
||||
_easingFunc = easingFunc;
|
||||
}
|
||||
|
||||
public double Ease(double v) => _easingFunc(v);
|
||||
}
|
||||
52
Hosting/GtkMauiContext.cs
Normal file
52
Hosting/GtkMauiContext.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Maui.Animations;
|
||||
using Microsoft.Maui.Dispatching;
|
||||
using Microsoft.Maui.Platform.Linux.Dispatching;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
public class GtkMauiContext : IMauiContext
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IMauiHandlersFactory _handlers;
|
||||
private IAnimationManager? _animationManager;
|
||||
private IDispatcher? _dispatcher;
|
||||
|
||||
public IServiceProvider Services => _services;
|
||||
|
||||
public IMauiHandlersFactory Handlers => _handlers;
|
||||
|
||||
public IAnimationManager AnimationManager
|
||||
{
|
||||
get
|
||||
{
|
||||
_animationManager ??= _services.GetService<IAnimationManager>()
|
||||
?? new LinuxAnimationManager(new LinuxTicker());
|
||||
return _animationManager;
|
||||
}
|
||||
}
|
||||
|
||||
public IDispatcher Dispatcher
|
||||
{
|
||||
get
|
||||
{
|
||||
_dispatcher ??= _services.GetService<IDispatcher>()
|
||||
?? new LinuxDispatcher();
|
||||
return _dispatcher;
|
||||
}
|
||||
}
|
||||
|
||||
public GtkMauiContext(IServiceProvider services)
|
||||
{
|
||||
_services = services ?? throw new ArgumentNullException(nameof(services));
|
||||
_handlers = services.GetRequiredService<IMauiHandlersFactory>();
|
||||
|
||||
if (LinuxApplication.Current == null)
|
||||
{
|
||||
new LinuxApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Hosting/HandlerMappingExtensions.cs
Normal file
17
Hosting/HandlerMappingExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Hosting;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
public static class HandlerMappingExtensions
|
||||
{
|
||||
public static IMauiHandlersCollection AddHandler<TView, THandler>(this IMauiHandlersCollection handlers)
|
||||
where TView : class
|
||||
where THandler : class
|
||||
{
|
||||
handlers.AddHandler(typeof(TView), typeof(THandler));
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
56
Hosting/LinuxAnimationManager.cs
Normal file
56
Hosting/LinuxAnimationManager.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Animations;
|
||||
using Animation = Microsoft.Maui.Animations.Animation;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
internal class LinuxAnimationManager : IAnimationManager
|
||||
{
|
||||
private readonly List<Animation> _animations = new();
|
||||
private readonly ITicker _ticker;
|
||||
|
||||
public double SpeedModifier { get; set; } = 1.0;
|
||||
|
||||
public bool AutoStartTicker { get; set; } = true;
|
||||
|
||||
public ITicker Ticker => _ticker;
|
||||
|
||||
public LinuxAnimationManager(ITicker ticker)
|
||||
{
|
||||
_ticker = ticker;
|
||||
_ticker.Fire = OnTickerFire;
|
||||
}
|
||||
|
||||
public void Add(Animation animation)
|
||||
{
|
||||
_animations.Add(animation);
|
||||
if (AutoStartTicker && !_ticker.IsRunning)
|
||||
{
|
||||
_ticker.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(Animation animation)
|
||||
{
|
||||
_animations.Remove(animation);
|
||||
if (_animations.Count == 0 && _ticker.IsRunning)
|
||||
{
|
||||
_ticker.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTickerFire()
|
||||
{
|
||||
var animationsArray = _animations.ToArray();
|
||||
foreach (var animation in animationsArray)
|
||||
{
|
||||
animation.Tick(0.016 * SpeedModifier);
|
||||
if (animation.HasFinished)
|
||||
{
|
||||
Remove(animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,37 +7,41 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.ApplicationModel.Communication;
|
||||
using Microsoft.Maui.ApplicationModel.DataTransfer;
|
||||
using Microsoft.Maui.Hosting;
|
||||
using Microsoft.Maui.Platform.Linux.Services;
|
||||
using Microsoft.Maui.Platform.Linux.Converters;
|
||||
using Microsoft.Maui.Storage;
|
||||
using Microsoft.Maui.Platform.Linux.Handlers;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Devices;
|
||||
using Microsoft.Maui.Dispatching;
|
||||
using Microsoft.Maui.Hosting;
|
||||
using Microsoft.Maui.Networking;
|
||||
using Microsoft.Maui.Platform.Linux.Converters;
|
||||
using Microsoft.Maui.Platform.Linux.Dispatching;
|
||||
using Microsoft.Maui.Platform.Linux.Handlers;
|
||||
using Microsoft.Maui.Platform.Linux.Services;
|
||||
using Microsoft.Maui.Storage;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for configuring MAUI applications for Linux.
|
||||
/// </summary>
|
||||
public static class LinuxMauiAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the MAUI application to run on Linux.
|
||||
/// </summary>
|
||||
public static MauiAppBuilder UseLinux(this MauiAppBuilder builder)
|
||||
{
|
||||
return builder.UseLinux(configure: null);
|
||||
return builder.UseLinux(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the MAUI application to run on Linux with options.
|
||||
/// </summary>
|
||||
public static MauiAppBuilder UseLinux(this MauiAppBuilder builder, Action<LinuxApplicationOptions>? configure)
|
||||
{
|
||||
var options = new LinuxApplicationOptions();
|
||||
configure?.Invoke(options);
|
||||
|
||||
// Register dispatcher provider
|
||||
builder.Services.TryAddSingleton<IDispatcherProvider>(LinuxDispatcherProvider.Instance);
|
||||
|
||||
// Register device services
|
||||
builder.Services.TryAddSingleton<IDeviceInfo>(DeviceInfoService.Instance);
|
||||
builder.Services.TryAddSingleton<IDeviceDisplay>(DeviceDisplayService.Instance);
|
||||
builder.Services.TryAddSingleton<IAppInfo>(AppInfoService.Instance);
|
||||
builder.Services.TryAddSingleton<IConnectivity>(ConnectivityService.Instance);
|
||||
|
||||
// Register platform services
|
||||
builder.Services.TryAddSingleton<ILauncher, LauncherService>();
|
||||
builder.Services.TryAddSingleton<IPreferences, PreferencesService>();
|
||||
@@ -50,6 +54,9 @@ public static class LinuxMauiAppBuilderExtensions
|
||||
builder.Services.TryAddSingleton<IBrowser, BrowserService>();
|
||||
builder.Services.TryAddSingleton<IEmail, EmailService>();
|
||||
|
||||
// Register GTK host service
|
||||
builder.Services.TryAddSingleton(_ => GtkHostService.Instance);
|
||||
|
||||
// Register type converters for XAML support
|
||||
RegisterTypeConverters();
|
||||
|
||||
@@ -98,8 +105,8 @@ public static class LinuxMauiAppBuilderExtensions
|
||||
handlers.AddHandler<ImageButton, ImageButtonHandler>();
|
||||
handlers.AddHandler<GraphicsView, GraphicsViewHandler>();
|
||||
|
||||
// Web
|
||||
handlers.AddHandler<WebView, WebViewHandler>();
|
||||
// Web - use GtkWebViewHandler
|
||||
handlers.AddHandler<WebView, GtkWebViewHandler>();
|
||||
|
||||
// Collection Views
|
||||
handlers.AddHandler<CollectionView, CollectionViewHandler>();
|
||||
@@ -124,33 +131,11 @@ public static class LinuxMauiAppBuilderExtensions
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers custom type converters for Linux platform.
|
||||
/// </summary>
|
||||
private static void RegisterTypeConverters()
|
||||
{
|
||||
// Register SkiaSharp type converters for XAML styling support
|
||||
TypeDescriptor.AddAttributes(typeof(SKColor), new TypeConverterAttribute(typeof(SKColorTypeConverter)));
|
||||
TypeDescriptor.AddAttributes(typeof(SKRect), new TypeConverterAttribute(typeof(SKRectTypeConverter)));
|
||||
TypeDescriptor.AddAttributes(typeof(SKSize), new TypeConverterAttribute(typeof(SKSizeTypeConverter)));
|
||||
TypeDescriptor.AddAttributes(typeof(SKPoint), new TypeConverterAttribute(typeof(SKPointTypeConverter)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler registration extensions.
|
||||
/// </summary>
|
||||
public static class HandlerMappingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a handler for the specified view type.
|
||||
/// </summary>
|
||||
public static IMauiHandlersCollection AddHandler<TView, THandler>(
|
||||
this IMauiHandlersCollection handlers)
|
||||
where TView : class
|
||||
where THandler : class
|
||||
{
|
||||
handlers.AddHandler(typeof(TView), typeof(THandler));
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,10 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Maui.Animations;
|
||||
using Microsoft.Maui.Dispatching;
|
||||
using Microsoft.Maui.Platform;
|
||||
using Microsoft.Maui.Platform.Linux.Dispatching;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Linux-specific implementation of IMauiContext.
|
||||
/// Provides the infrastructure for creating handlers and accessing platform services.
|
||||
/// </summary>
|
||||
public class LinuxMauiContext : IMauiContext
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
@@ -22,27 +16,12 @@ public class LinuxMauiContext : IMauiContext
|
||||
private IAnimationManager? _animationManager;
|
||||
private IDispatcher? _dispatcher;
|
||||
|
||||
public LinuxMauiContext(IServiceProvider services, LinuxApplication linuxApp)
|
||||
{
|
||||
_services = services ?? throw new ArgumentNullException(nameof(services));
|
||||
_linuxApp = linuxApp ?? throw new ArgumentNullException(nameof(linuxApp));
|
||||
_handlers = services.GetRequiredService<IMauiHandlersFactory>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IServiceProvider Services => _services;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMauiHandlersFactory Handlers => _handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Linux application instance.
|
||||
/// </summary>
|
||||
public LinuxApplication LinuxApp => _linuxApp;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the animation manager.
|
||||
/// </summary>
|
||||
public IAnimationManager AnimationManager
|
||||
{
|
||||
get
|
||||
@@ -53,9 +32,6 @@ public class LinuxMauiContext : IMauiContext
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dispatcher for UI thread operations.
|
||||
/// </summary>
|
||||
public IDispatcher Dispatcher
|
||||
{
|
||||
get
|
||||
@@ -65,117 +41,11 @@ public class LinuxMauiContext : IMauiContext
|
||||
return _dispatcher;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scoped MAUI context for a specific window or view hierarchy.
|
||||
/// </summary>
|
||||
public class ScopedLinuxMauiContext : IMauiContext
|
||||
{
|
||||
private readonly LinuxMauiContext _parent;
|
||||
|
||||
public ScopedLinuxMauiContext(LinuxMauiContext parent)
|
||||
public LinuxMauiContext(IServiceProvider services, LinuxApplication linuxApp)
|
||||
{
|
||||
_parent = parent ?? throw new ArgumentNullException(nameof(parent));
|
||||
}
|
||||
|
||||
public IServiceProvider Services => _parent.Services;
|
||||
public IMauiHandlersFactory Handlers => _parent.Handlers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linux animation manager.
|
||||
/// </summary>
|
||||
internal class LinuxAnimationManager : IAnimationManager
|
||||
{
|
||||
private readonly List<Microsoft.Maui.Animations.Animation> _animations = new();
|
||||
private readonly ITicker _ticker;
|
||||
|
||||
public LinuxAnimationManager(ITicker ticker)
|
||||
{
|
||||
_ticker = ticker;
|
||||
_ticker.Fire = OnTickerFire;
|
||||
}
|
||||
|
||||
public double SpeedModifier { get; set; } = 1.0;
|
||||
public bool AutoStartTicker { get; set; } = true;
|
||||
|
||||
public ITicker Ticker => _ticker;
|
||||
|
||||
public void Add(Microsoft.Maui.Animations.Animation animation)
|
||||
{
|
||||
_animations.Add(animation);
|
||||
|
||||
if (AutoStartTicker && !_ticker.IsRunning)
|
||||
{
|
||||
_ticker.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(Microsoft.Maui.Animations.Animation animation)
|
||||
{
|
||||
_animations.Remove(animation);
|
||||
|
||||
if (_animations.Count == 0 && _ticker.IsRunning)
|
||||
{
|
||||
_ticker.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTickerFire()
|
||||
{
|
||||
var animations = _animations.ToArray();
|
||||
foreach (var animation in animations)
|
||||
{
|
||||
animation.Tick(16.0 / 1000.0 * SpeedModifier); // ~60fps
|
||||
if (animation.HasFinished)
|
||||
{
|
||||
Remove(animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linux ticker for animation timing.
|
||||
/// </summary>
|
||||
internal class LinuxTicker : ITicker
|
||||
{
|
||||
private Timer? _timer;
|
||||
private bool _isRunning;
|
||||
private int _maxFps = 60;
|
||||
|
||||
public bool IsRunning => _isRunning;
|
||||
|
||||
public bool SystemEnabled => true;
|
||||
|
||||
public int MaxFps
|
||||
{
|
||||
get => _maxFps;
|
||||
set => _maxFps = Math.Max(1, Math.Min(120, value));
|
||||
}
|
||||
|
||||
public Action? Fire { get; set; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_isRunning)
|
||||
return;
|
||||
|
||||
_isRunning = true;
|
||||
var interval = TimeSpan.FromMilliseconds(1000.0 / _maxFps);
|
||||
_timer = new Timer(OnTimerCallback, null, TimeSpan.Zero, interval);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_isRunning = false;
|
||||
_timer?.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
private void OnTimerCallback(object? state)
|
||||
{
|
||||
Fire?.Invoke();
|
||||
_services = services ?? throw new ArgumentNullException(nameof(services));
|
||||
_linuxApp = linuxApp ?? throw new ArgumentNullException(nameof(linuxApp));
|
||||
_handlers = services.GetRequiredService<IMauiHandlersFactory>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Maui.Hosting;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Platform;
|
||||
using Microsoft.Maui.Controls.Hosting;
|
||||
using Microsoft.Maui.Hosting;
|
||||
using Microsoft.Maui.Platform.Linux.Services;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
@@ -44,6 +45,10 @@ public static class LinuxProgramHost
|
||||
?? new LinuxApplicationOptions();
|
||||
ParseCommandLineOptions(args, options);
|
||||
|
||||
// Initialize GTK for WebView support
|
||||
GtkHostService.Instance.Initialize(options.Title, options.Width, options.Height);
|
||||
Console.WriteLine("[LinuxProgramHost] GTK initialized for WebView support");
|
||||
|
||||
// Create Linux application
|
||||
using var linuxApp = new LinuxApplication();
|
||||
linuxApp.Initialize(options);
|
||||
|
||||
47
Hosting/LinuxTicker.cs
Normal file
47
Hosting/LinuxTicker.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Animations;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
internal class LinuxTicker : ITicker
|
||||
{
|
||||
private Timer? _timer;
|
||||
private bool _isRunning;
|
||||
private int _maxFps = 60;
|
||||
|
||||
public bool IsRunning => _isRunning;
|
||||
|
||||
public bool SystemEnabled => true;
|
||||
|
||||
public int MaxFps
|
||||
{
|
||||
get => _maxFps;
|
||||
set => _maxFps = Math.Max(1, Math.Min(120, value));
|
||||
}
|
||||
|
||||
public Action? Fire { get; set; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_isRunning = true;
|
||||
var period = TimeSpan.FromMilliseconds(1000.0 / _maxFps);
|
||||
_timer = new Timer(OnTimerCallback, null, TimeSpan.Zero, period);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_isRunning = false;
|
||||
_timer?.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
private void OnTimerCallback(object? state)
|
||||
{
|
||||
Fire?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Graphics;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -198,9 +200,28 @@ public class LinuxViewRenderer
|
||||
FlyoutBehavior.Locked => ShellFlyoutBehavior.Locked,
|
||||
FlyoutBehavior.Disabled => ShellFlyoutBehavior.Disabled,
|
||||
_ => ShellFlyoutBehavior.Flyout
|
||||
}
|
||||
},
|
||||
MauiShell = shell
|
||||
};
|
||||
|
||||
// Apply shell colors based on theme
|
||||
ApplyShellColors(skiaShell, shell);
|
||||
|
||||
// Render flyout header if present
|
||||
if (shell.FlyoutHeader is View headerView)
|
||||
{
|
||||
var skiaHeader = RenderView(headerView);
|
||||
if (skiaHeader != null)
|
||||
{
|
||||
skiaShell.FlyoutHeaderView = skiaHeader;
|
||||
skiaShell.FlyoutHeaderHeight = (float)(headerView.HeightRequest > 0 ? headerView.HeightRequest : 140.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Set flyout footer with version info
|
||||
var version = Assembly.GetEntryAssembly()?.GetName().Version;
|
||||
skiaShell.FlyoutFooterText = $"Version {version?.Major ?? 1}.{version?.Minor ?? 0}.{version?.Build ?? 0}";
|
||||
|
||||
// Process shell items into sections
|
||||
foreach (var item in shell.Items)
|
||||
{
|
||||
@@ -210,6 +231,10 @@ public class LinuxViewRenderer
|
||||
// Store reference to SkiaShell for navigation
|
||||
CurrentSkiaShell = skiaShell;
|
||||
|
||||
// Set up content renderer and color refresher delegates
|
||||
skiaShell.ContentRenderer = CreateShellContentPage;
|
||||
skiaShell.ColorRefresher = ApplyShellColors;
|
||||
|
||||
// Subscribe to MAUI Shell navigation events to update SkiaShell
|
||||
shell.Navigated += OnShellNavigated;
|
||||
shell.Navigating += (s, e) => Console.WriteLine($"[Navigation] Navigating: {e.Target}");
|
||||
@@ -223,6 +248,61 @@ public class LinuxViewRenderer
|
||||
return skiaShell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies shell colors based on the current theme (dark/light mode).
|
||||
/// </summary>
|
||||
private static void ApplyShellColors(SkiaShell skiaShell, Shell shell)
|
||||
{
|
||||
bool isDark = Application.Current?.UserAppTheme == AppTheme.Dark;
|
||||
Console.WriteLine($"[ApplyShellColors] Theme is: {(isDark ? "Dark" : "Light")}");
|
||||
|
||||
// Flyout background color
|
||||
if (shell.FlyoutBackgroundColor != null && shell.FlyoutBackgroundColor != Colors.Transparent)
|
||||
{
|
||||
var color = shell.FlyoutBackgroundColor;
|
||||
skiaShell.FlyoutBackgroundColor = new SKColor(
|
||||
(byte)(color.Red * 255f),
|
||||
(byte)(color.Green * 255f),
|
||||
(byte)(color.Blue * 255f),
|
||||
(byte)(color.Alpha * 255f));
|
||||
Console.WriteLine($"[ApplyShellColors] FlyoutBackgroundColor from MAUI: {skiaShell.FlyoutBackgroundColor}");
|
||||
}
|
||||
else
|
||||
{
|
||||
skiaShell.FlyoutBackgroundColor = isDark
|
||||
? new SKColor(30, 30, 30)
|
||||
: new SKColor(255, 255, 255);
|
||||
Console.WriteLine($"[ApplyShellColors] Using default FlyoutBackgroundColor: {skiaShell.FlyoutBackgroundColor}");
|
||||
}
|
||||
|
||||
// Flyout text color
|
||||
skiaShell.FlyoutTextColor = isDark
|
||||
? new SKColor(224, 224, 224)
|
||||
: new SKColor(33, 33, 33);
|
||||
Console.WriteLine($"[ApplyShellColors] FlyoutTextColor: {skiaShell.FlyoutTextColor}");
|
||||
|
||||
// Content background color
|
||||
skiaShell.ContentBackgroundColor = isDark
|
||||
? new SKColor(18, 18, 18)
|
||||
: new SKColor(250, 250, 250);
|
||||
Console.WriteLine($"[ApplyShellColors] ContentBackgroundColor: {skiaShell.ContentBackgroundColor}");
|
||||
|
||||
// NavBar background color
|
||||
if (shell.BackgroundColor != null && shell.BackgroundColor != Colors.Transparent)
|
||||
{
|
||||
var color = shell.BackgroundColor;
|
||||
skiaShell.NavBarBackgroundColor = new SKColor(
|
||||
(byte)(color.Red * 255f),
|
||||
(byte)(color.Green * 255f),
|
||||
(byte)(color.Blue * 255f),
|
||||
(byte)(color.Alpha * 255f));
|
||||
}
|
||||
else
|
||||
{
|
||||
skiaShell.NavBarBackgroundColor = new SKColor(33, 150, 243); // Material blue
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles MAUI Shell navigation events and updates SkiaShell accordingly.
|
||||
/// </summary>
|
||||
@@ -290,7 +370,8 @@ public class LinuxViewRenderer
|
||||
var shellContent = new ShellContent
|
||||
{
|
||||
Title = content.Title ?? shellSection.Title ?? flyoutItem.Title ?? "",
|
||||
Route = content.Route ?? ""
|
||||
Route = content.Route ?? "",
|
||||
MauiShellContent = content
|
||||
};
|
||||
|
||||
// Create the page content
|
||||
@@ -328,7 +409,8 @@ public class LinuxViewRenderer
|
||||
var shellContent = new ShellContent
|
||||
{
|
||||
Title = content.Title ?? tab.Title ?? "",
|
||||
Route = content.Route ?? ""
|
||||
Route = content.Route ?? "",
|
||||
MauiShellContent = content
|
||||
};
|
||||
|
||||
var pageContent = CreateShellContentPage(content);
|
||||
@@ -359,7 +441,8 @@ public class LinuxViewRenderer
|
||||
var shellContent = new ShellContent
|
||||
{
|
||||
Title = content.Title ?? "",
|
||||
Route = content.Route ?? ""
|
||||
Route = content.Route ?? "",
|
||||
MauiShellContent = content
|
||||
};
|
||||
|
||||
var pageContent = CreateShellContentPage(content);
|
||||
@@ -402,17 +485,38 @@ public class LinuxViewRenderer
|
||||
var contentView = RenderView(cp.Content);
|
||||
if (contentView != null)
|
||||
{
|
||||
if (contentView is SkiaScrollView)
|
||||
// Get page background color if set
|
||||
SKColor? bgColor = null;
|
||||
if (cp.BackgroundColor != null && cp.BackgroundColor != Colors.Transparent)
|
||||
{
|
||||
return contentView;
|
||||
var color = cp.BackgroundColor;
|
||||
bgColor = new SKColor(
|
||||
(byte)(color.Red * 255f),
|
||||
(byte)(color.Green * 255f),
|
||||
(byte)(color.Blue * 255f),
|
||||
(byte)(color.Alpha * 255f));
|
||||
Console.WriteLine($"[CreateShellContentPage] Page BackgroundColor: {bgColor}");
|
||||
}
|
||||
|
||||
if (contentView is SkiaScrollView scrollView)
|
||||
{
|
||||
if (bgColor.HasValue)
|
||||
{
|
||||
scrollView.BackgroundColor = bgColor.Value;
|
||||
}
|
||||
return scrollView;
|
||||
}
|
||||
else
|
||||
{
|
||||
var scrollView = new SkiaScrollView
|
||||
var newScrollView = new SkiaScrollView
|
||||
{
|
||||
Content = contentView
|
||||
};
|
||||
return scrollView;
|
||||
if (bgColor.HasValue)
|
||||
{
|
||||
newScrollView.BackgroundColor = bgColor.Value;
|
||||
}
|
||||
return newScrollView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// Copyright (c) 2025 MarketAlly LLC
|
||||
|
||||
using Microsoft.Maui;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Controls.Hosting;
|
||||
using Microsoft.Maui.Hosting;
|
||||
using Microsoft.Maui.Platform.Linux;
|
||||
using Microsoft.Maui.Platform.Linux.Handlers;
|
||||
|
||||
namespace OpenMaui.Platform.Linux.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for configuring OpenMaui Linux platform in a MAUI application.
|
||||
/// This enables full XAML support by registering Linux-specific handlers.
|
||||
/// </summary>
|
||||
public static class MauiAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the application to use OpenMaui Linux platform with full XAML support.
|
||||
/// </summary>
|
||||
/// <param name="builder">The MAUI app builder.</param>
|
||||
/// <returns>The configured MAUI app builder.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var builder = MauiApp.CreateBuilder();
|
||||
/// builder
|
||||
/// .UseMauiApp<App>()
|
||||
/// .UseOpenMauiLinux(); // Enable Linux support with XAML
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static MauiAppBuilder UseOpenMauiLinux(this MauiAppBuilder builder)
|
||||
{
|
||||
builder.ConfigureMauiHandlers(handlers =>
|
||||
{
|
||||
// Register all Linux platform handlers
|
||||
// These map MAUI virtual views to our Skia platform views
|
||||
|
||||
// Basic Controls
|
||||
handlers.AddHandler<Button, ButtonHandler>();
|
||||
handlers.AddHandler<Label, LabelHandler>();
|
||||
handlers.AddHandler<Entry, EntryHandler>();
|
||||
handlers.AddHandler<Editor, EditorHandler>();
|
||||
handlers.AddHandler<CheckBox, CheckBoxHandler>();
|
||||
handlers.AddHandler<Switch, SwitchHandler>();
|
||||
handlers.AddHandler<RadioButton, RadioButtonHandler>();
|
||||
|
||||
// Selection Controls
|
||||
handlers.AddHandler<Slider, SliderHandler>();
|
||||
handlers.AddHandler<Stepper, StepperHandler>();
|
||||
handlers.AddHandler<Picker, PickerHandler>();
|
||||
handlers.AddHandler<DatePicker, DatePickerHandler>();
|
||||
handlers.AddHandler<TimePicker, TimePickerHandler>();
|
||||
|
||||
// Display Controls
|
||||
handlers.AddHandler<Image, ImageHandler>();
|
||||
handlers.AddHandler<ImageButton, ImageButtonHandler>();
|
||||
handlers.AddHandler<ActivityIndicator, ActivityIndicatorHandler>();
|
||||
handlers.AddHandler<ProgressBar, ProgressBarHandler>();
|
||||
|
||||
// Layout Controls
|
||||
handlers.AddHandler<Border, BorderHandler>();
|
||||
|
||||
// Collection Controls
|
||||
handlers.AddHandler<CollectionView, CollectionViewHandler>();
|
||||
|
||||
// Navigation Controls
|
||||
handlers.AddHandler<NavigationPage, NavigationPageHandler>();
|
||||
handlers.AddHandler<TabbedPage, TabbedPageHandler>();
|
||||
handlers.AddHandler<FlyoutPage, FlyoutPageHandler>();
|
||||
handlers.AddHandler<Shell, ShellHandler>();
|
||||
|
||||
// Page Controls
|
||||
handlers.AddHandler<Page, PageHandler>();
|
||||
handlers.AddHandler<ContentPage, PageHandler>();
|
||||
|
||||
// Graphics
|
||||
handlers.AddHandler<GraphicsView, GraphicsViewHandler>();
|
||||
|
||||
// Search
|
||||
handlers.AddHandler<SearchBar, SearchBarHandler>();
|
||||
|
||||
// Web
|
||||
handlers.AddHandler<WebView, WebViewHandler>();
|
||||
|
||||
// Window
|
||||
handlers.AddHandler<Window, WindowHandler>();
|
||||
});
|
||||
|
||||
// Register Linux-specific services
|
||||
builder.Services.AddSingleton<ILinuxPlatformServices, LinuxPlatformServices>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the application to use OpenMaui Linux with custom handler configuration.
|
||||
/// </summary>
|
||||
/// <param name="builder">The MAUI app builder.</param>
|
||||
/// <param name="configureHandlers">Action to configure additional handlers.</param>
|
||||
/// <returns>The configured MAUI app builder.</returns>
|
||||
public static MauiAppBuilder UseOpenMauiLinux(
|
||||
this MauiAppBuilder builder,
|
||||
Action<IMauiHandlersCollection>? configureHandlers)
|
||||
{
|
||||
builder.UseOpenMauiLinux();
|
||||
|
||||
if (configureHandlers != null)
|
||||
{
|
||||
builder.ConfigureMauiHandlers(configureHandlers);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for Linux platform services.
|
||||
/// </summary>
|
||||
public interface ILinuxPlatformServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the display server type (X11 or Wayland).
|
||||
/// </summary>
|
||||
DisplayServerType DisplayServer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current DPI scale factor.
|
||||
/// </summary>
|
||||
float ScaleFactor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether high contrast mode is enabled.
|
||||
/// </summary>
|
||||
bool IsHighContrastEnabled { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display server types supported by OpenMaui.
|
||||
/// </summary>
|
||||
public enum DisplayServerType
|
||||
{
|
||||
/// <summary>X11 display server.</summary>
|
||||
X11,
|
||||
/// <summary>Wayland display server.</summary>
|
||||
Wayland,
|
||||
/// <summary>Auto-detected display server.</summary>
|
||||
Auto
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of Linux platform services.
|
||||
/// </summary>
|
||||
internal class LinuxPlatformServices : ILinuxPlatformServices
|
||||
{
|
||||
public DisplayServerType DisplayServer => DetectDisplayServer();
|
||||
public float ScaleFactor => DetectScaleFactor();
|
||||
public bool IsHighContrastEnabled => DetectHighContrast();
|
||||
|
||||
private static DisplayServerType DetectDisplayServer()
|
||||
{
|
||||
var waylandDisplay = Environment.GetEnvironmentVariable("WAYLAND_DISPLAY");
|
||||
if (!string.IsNullOrEmpty(waylandDisplay))
|
||||
return DisplayServerType.Wayland;
|
||||
|
||||
var display = Environment.GetEnvironmentVariable("DISPLAY");
|
||||
if (!string.IsNullOrEmpty(display))
|
||||
return DisplayServerType.X11;
|
||||
|
||||
return DisplayServerType.Auto;
|
||||
}
|
||||
|
||||
private static float DetectScaleFactor()
|
||||
{
|
||||
// Try GDK_SCALE first
|
||||
var gdkScale = Environment.GetEnvironmentVariable("GDK_SCALE");
|
||||
if (float.TryParse(gdkScale, out var scale))
|
||||
return scale;
|
||||
|
||||
// Default to 1.0
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
private static bool DetectHighContrast()
|
||||
{
|
||||
var highContrast = Environment.GetEnvironmentVariable("GTK_THEME");
|
||||
return highContrast?.Contains("HighContrast", StringComparison.OrdinalIgnoreCase) ?? false;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public static class MauiHandlerExtensions
|
||||
[typeof(TimePicker)] = () => new TimePickerHandler(),
|
||||
[typeof(SearchBar)] = () => new SearchBarHandler(),
|
||||
[typeof(RadioButton)] = () => new RadioButtonHandler(),
|
||||
[typeof(WebView)] = () => new WebViewHandler(),
|
||||
[typeof(WebView)] = () => new GtkWebViewHandler(),
|
||||
[typeof(Image)] = () => new ImageHandler(),
|
||||
[typeof(ImageButton)] = () => new ImageButtonHandler(),
|
||||
[typeof(BoxView)] = () => new BoxViewHandler(),
|
||||
@@ -41,7 +41,7 @@ public static class MauiHandlerExtensions
|
||||
[typeof(VerticalStackLayout)] = () => new StackLayoutHandler(),
|
||||
[typeof(HorizontalStackLayout)] = () => new StackLayoutHandler(),
|
||||
[typeof(AbsoluteLayout)] = () => new LayoutHandler(),
|
||||
[typeof(FlexLayout)] = () => new FlexLayoutHandler(),
|
||||
[typeof(FlexLayout)] = () => new LayoutHandler(),
|
||||
[typeof(CollectionView)] = () => new CollectionViewHandler(),
|
||||
[typeof(ListView)] = () => new CollectionViewHandler(),
|
||||
[typeof(Page)] = () => new PageHandler(),
|
||||
|
||||
18
Hosting/ScopedLinuxMauiContext.cs
Normal file
18
Hosting/ScopedLinuxMauiContext.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Hosting;
|
||||
|
||||
public class ScopedLinuxMauiContext : IMauiContext
|
||||
{
|
||||
private readonly LinuxMauiContext _parent;
|
||||
|
||||
public IServiceProvider Services => _parent.Services;
|
||||
|
||||
public IMauiHandlersFactory Handlers => _parent.Handlers;
|
||||
|
||||
public ScopedLinuxMauiContext(LinuxMauiContext parent)
|
||||
{
|
||||
_parent = parent ?? throw new ArgumentNullException(nameof(parent));
|
||||
}
|
||||
}
|
||||
25
Interop/ClientMessageData.cs
Normal file
25
Interop/ClientMessageData.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct ClientMessageData
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public long L0;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public long L1;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public long L2;
|
||||
|
||||
[FieldOffset(24)]
|
||||
public long L3;
|
||||
|
||||
[FieldOffset(32)]
|
||||
public long L4;
|
||||
}
|
||||
226
Interop/X11.cs
Normal file
226
Interop/X11.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
internal static partial class X11
|
||||
{
|
||||
private const string LibX11 = "libX11.so.6";
|
||||
|
||||
public const int ZPixmap = 2;
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XOpenDisplay(IntPtr displayName);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XCloseDisplay(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefaultScreen(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XRootWindow(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDisplayWidth(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDisplayHeight(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefaultDepth(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultVisual(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultColormap(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFlush(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSync(IntPtr display, [MarshalAs(UnmanagedType.Bool)] bool discard);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateSimpleWindow(
|
||||
IntPtr display, IntPtr parent,
|
||||
int x, int y, uint width, uint height,
|
||||
uint borderWidth, ulong border, ulong background);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateWindow(
|
||||
IntPtr display, IntPtr parent,
|
||||
int x, int y, uint width, uint height, uint borderWidth,
|
||||
int depth, uint windowClass, IntPtr visual,
|
||||
ulong valueMask, ref XSetWindowAttributes attributes);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDestroyWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMapWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUnmapWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMoveWindow(IntPtr display, IntPtr window, int x, int y);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XResizeWindow(IntPtr display, IntPtr window, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11, StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial int XStoreName(IntPtr display, IntPtr window, string windowName);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XRaiseWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XLowerWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSelectInput(IntPtr display, IntPtr window, long eventMask);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XNextEvent(IntPtr display, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPeekEvent(IntPtr display, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPending(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool XCheckTypedWindowEvent(IntPtr display, IntPtr window, int eventType, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSendEvent(
|
||||
IntPtr display, IntPtr window,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool propagate,
|
||||
long eventMask, ref XEvent eventSend);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial ulong XKeycodeToKeysym(IntPtr display, int keycode, int index);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XLookupString(
|
||||
ref XKeyEvent keyEvent, IntPtr bufferReturn, int bytesBuffer,
|
||||
out ulong keysymReturn, IntPtr statusInOut);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGrabKeyboard(
|
||||
IntPtr display, IntPtr grabWindow,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool ownerEvents,
|
||||
int pointerMode, int keyboardMode, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUngrabKeyboard(IntPtr display, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGrabPointer(
|
||||
IntPtr display, IntPtr grabWindow,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool ownerEvents,
|
||||
uint eventMask, int pointerMode, int keyboardMode,
|
||||
IntPtr confineTo, IntPtr cursor, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUngrabPointer(IntPtr display, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool XQueryPointer(
|
||||
IntPtr display, IntPtr window,
|
||||
out IntPtr rootReturn, out IntPtr childReturn,
|
||||
out int rootX, out int rootY,
|
||||
out int winX, out int winY,
|
||||
out uint maskReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XWarpPointer(
|
||||
IntPtr display, IntPtr srcWindow, IntPtr destWindow,
|
||||
int srcX, int srcY, uint srcWidth, uint srcHeight,
|
||||
int destX, int destY);
|
||||
|
||||
[LibraryImport(LibX11, StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial IntPtr XInternAtom(IntPtr display, string atomName, [MarshalAs(UnmanagedType.Bool)] bool onlyIfExists);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XChangeProperty(
|
||||
IntPtr display, IntPtr window, IntPtr property, IntPtr type,
|
||||
int format, int mode, IntPtr data, int nelements);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGetWindowProperty(
|
||||
IntPtr display, IntPtr window, IntPtr property,
|
||||
long longOffset, long longLength,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool delete, IntPtr reqType,
|
||||
out IntPtr actualTypeReturn, out int actualFormatReturn,
|
||||
out IntPtr nitemsReturn, out IntPtr bytesAfterReturn,
|
||||
out IntPtr propReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XConvertSelection(
|
||||
IntPtr display, IntPtr selection, IntPtr target,
|
||||
IntPtr property, IntPtr requestor, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFree(IntPtr data);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valueMask, IntPtr values);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFreeGC(IntPtr display, IntPtr gc);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XCopyArea(
|
||||
IntPtr display, IntPtr src, IntPtr dest, IntPtr gc,
|
||||
int srcX, int srcY, uint width, uint height, int destX, int destY);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateFontCursor(IntPtr display, uint shape);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFreeCursor(IntPtr display, IntPtr cursor);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUndefineCursor(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XConnectionNumber(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateImage(
|
||||
IntPtr display, IntPtr visual, uint depth, int format, int offset,
|
||||
IntPtr data, uint width, uint height, int bitmapPad, int bytesPerLine);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPutImage(
|
||||
IntPtr display, IntPtr drawable, IntPtr gc, IntPtr image,
|
||||
int srcX, int srcY, int destX, int destY, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDestroyImage(IntPtr image);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultGC(IntPtr display, int screen);
|
||||
}
|
||||
@@ -1,482 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
/// <summary>
|
||||
/// P/Invoke declarations for X11 library functions.
|
||||
/// </summary>
|
||||
internal static partial class X11
|
||||
{
|
||||
private const string LibX11 = "libX11.so.6";
|
||||
private const string LibXext = "libXext.so.6";
|
||||
|
||||
#region Display and Screen
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XOpenDisplay(IntPtr displayName);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XCloseDisplay(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefaultScreen(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XRootWindow(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDisplayWidth(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDisplayHeight(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefaultDepth(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultVisual(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultColormap(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFlush(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSync(IntPtr display, [MarshalAs(UnmanagedType.Bool)] bool discard);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Window Creation and Management
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateSimpleWindow(
|
||||
IntPtr display,
|
||||
IntPtr parent,
|
||||
int x, int y,
|
||||
uint width, uint height,
|
||||
uint borderWidth,
|
||||
ulong border,
|
||||
ulong background);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateWindow(
|
||||
IntPtr display,
|
||||
IntPtr parent,
|
||||
int x, int y,
|
||||
uint width, uint height,
|
||||
uint borderWidth,
|
||||
int depth,
|
||||
uint windowClass,
|
||||
IntPtr visual,
|
||||
ulong valueMask,
|
||||
ref XSetWindowAttributes attributes);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDestroyWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMapWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUnmapWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMoveWindow(IntPtr display, IntPtr window, int x, int y);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XResizeWindow(IntPtr display, IntPtr window, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11, StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial int XStoreName(IntPtr display, IntPtr window, string windowName);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XRaiseWindow(IntPtr display, IntPtr window);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XLowerWindow(IntPtr display, IntPtr window);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSelectInput(IntPtr display, IntPtr window, long eventMask);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XNextEvent(IntPtr display, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPeekEvent(IntPtr display, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPending(IntPtr display);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool XCheckTypedWindowEvent(IntPtr display, IntPtr window, int eventType, out XEvent eventReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSendEvent(IntPtr display, IntPtr window, [MarshalAs(UnmanagedType.Bool)] bool propagate, long eventMask, ref XEvent eventSend);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyboard
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial ulong XKeycodeToKeysym(IntPtr display, int keycode, int index);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XLookupString(ref XKeyEvent keyEvent, IntPtr bufferReturn, int bytesBuffer, out ulong keysymReturn, IntPtr statusInOut);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGrabKeyboard(IntPtr display, IntPtr grabWindow, [MarshalAs(UnmanagedType.Bool)] bool ownerEvents, int pointerMode, int keyboardMode, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUngrabKeyboard(IntPtr display, ulong time);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mouse/Pointer
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGrabPointer(IntPtr display, IntPtr grabWindow, [MarshalAs(UnmanagedType.Bool)] bool ownerEvents, uint eventMask, int pointerMode, int keyboardMode, IntPtr confineTo, IntPtr cursor, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUngrabPointer(IntPtr display, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr rootReturn, out IntPtr childReturn, out int rootX, out int rootY, out int winX, out int winY, out uint maskReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XWarpPointer(IntPtr display, IntPtr srcWindow, IntPtr destWindow, int srcX, int srcY, uint srcWidth, uint srcHeight, int destX, int destY);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Atoms and Properties
|
||||
|
||||
[LibraryImport(LibX11, StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial IntPtr XInternAtom(IntPtr display, string atomName, [MarshalAs(UnmanagedType.Bool)] bool onlyIfExists);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, int mode, IntPtr data, int nelements);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr property, long longOffset, long longLength, [MarshalAs(UnmanagedType.Bool)] bool delete, IntPtr reqType, out IntPtr actualTypeReturn, out int actualFormatReturn, out IntPtr nitemsReturn, out IntPtr bytesAfterReturn, out IntPtr propReturn);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Clipboard/Selection
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, ulong time);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, ulong time);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Memory
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFree(IntPtr data);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Graphics Context
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valueMask, IntPtr values);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFreeGC(IntPtr display, IntPtr gc);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int srcX, int srcY, uint width, uint height, int destX, int destY);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cursor
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateFontCursor(IntPtr display, uint shape);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XFreeCursor(IntPtr display, IntPtr cursor);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XUndefineCursor(IntPtr display, IntPtr window);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connection
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XConnectionNumber(IntPtr display);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Image Functions
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XCreateImage(IntPtr display, IntPtr visual, uint depth, int format,
|
||||
int offset, IntPtr data, uint width, uint height, int bitmapPad, int bytesPerLine);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, IntPtr image,
|
||||
int srcX, int srcY, int destX, int destY, uint width, uint height);
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial int XDestroyImage(IntPtr image);
|
||||
|
||||
|
||||
[LibraryImport(LibX11)]
|
||||
public static partial IntPtr XDefaultGC(IntPtr display, int screen);
|
||||
|
||||
public const int ZPixmap = 2;
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#region X11 Structures
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XSetWindowAttributes
|
||||
{
|
||||
public IntPtr BackgroundPixmap;
|
||||
public ulong BackgroundPixel;
|
||||
public IntPtr BorderPixmap;
|
||||
public ulong BorderPixel;
|
||||
public int BitGravity;
|
||||
public int WinGravity;
|
||||
public int BackingStore;
|
||||
public ulong BackingPlanes;
|
||||
public ulong BackingPixel;
|
||||
public int SaveUnder;
|
||||
public long EventMask;
|
||||
public long DoNotPropagateMask;
|
||||
public int OverrideRedirect;
|
||||
public IntPtr Colormap;
|
||||
public IntPtr Cursor;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 192)]
|
||||
public struct XEvent
|
||||
{
|
||||
[FieldOffset(0)] public int Type;
|
||||
[FieldOffset(0)] public XKeyEvent KeyEvent;
|
||||
[FieldOffset(0)] public XButtonEvent ButtonEvent;
|
||||
[FieldOffset(0)] public XMotionEvent MotionEvent;
|
||||
[FieldOffset(0)] public XConfigureEvent ConfigureEvent;
|
||||
[FieldOffset(0)] public XExposeEvent ExposeEvent;
|
||||
[FieldOffset(0)] public XClientMessageEvent ClientMessageEvent;
|
||||
[FieldOffset(0)] public XCrossingEvent CrossingEvent;
|
||||
[FieldOffset(0)] public XFocusChangeEvent FocusChangeEvent;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XKeyEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X, Y;
|
||||
public int XRoot, YRoot;
|
||||
public uint State;
|
||||
public uint Keycode;
|
||||
public int SameScreen;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XButtonEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X, Y;
|
||||
public int XRoot, YRoot;
|
||||
public uint State;
|
||||
public uint Button;
|
||||
public int SameScreen;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XMotionEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X, Y;
|
||||
public int XRoot, YRoot;
|
||||
public uint State;
|
||||
public byte IsHint;
|
||||
public int SameScreen;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XConfigureEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Event;
|
||||
public IntPtr Window;
|
||||
public int X, Y;
|
||||
public int Width, Height;
|
||||
public int BorderWidth;
|
||||
public IntPtr Above;
|
||||
public int OverrideRedirect;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XExposeEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public int X, Y;
|
||||
public int Width, Height;
|
||||
public int Count;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XClientMessageEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr MessageType;
|
||||
public int Format;
|
||||
public ClientMessageData Data;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct ClientMessageData
|
||||
{
|
||||
[FieldOffset(0)] public long L0;
|
||||
[FieldOffset(8)] public long L1;
|
||||
[FieldOffset(16)] public long L2;
|
||||
[FieldOffset(24)] public long L3;
|
||||
[FieldOffset(32)] public long L4;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XCrossingEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X, Y;
|
||||
public int XRoot, YRoot;
|
||||
public int Mode;
|
||||
public int Detail;
|
||||
public int SameScreen;
|
||||
public int Focus;
|
||||
public uint State;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XFocusChangeEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public int Mode;
|
||||
public int Detail;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region X11 Constants
|
||||
|
||||
public static class XEventType
|
||||
{
|
||||
public const int KeyPress = 2;
|
||||
public const int KeyRelease = 3;
|
||||
public const int ButtonPress = 4;
|
||||
public const int ButtonRelease = 5;
|
||||
public const int MotionNotify = 6;
|
||||
public const int EnterNotify = 7;
|
||||
public const int LeaveNotify = 8;
|
||||
public const int FocusIn = 9;
|
||||
public const int FocusOut = 10;
|
||||
public const int Expose = 12;
|
||||
public const int ConfigureNotify = 22;
|
||||
public const int ClientMessage = 33;
|
||||
}
|
||||
|
||||
public static class XEventMask
|
||||
{
|
||||
public const long KeyPressMask = 1L << 0;
|
||||
public const long KeyReleaseMask = 1L << 1;
|
||||
public const long ButtonPressMask = 1L << 2;
|
||||
public const long ButtonReleaseMask = 1L << 3;
|
||||
public const long EnterWindowMask = 1L << 4;
|
||||
public const long LeaveWindowMask = 1L << 5;
|
||||
public const long PointerMotionMask = 1L << 6;
|
||||
public const long ExposureMask = 1L << 15;
|
||||
public const long StructureNotifyMask = 1L << 17;
|
||||
public const long FocusChangeMask = 1L << 21;
|
||||
}
|
||||
|
||||
public static class XWindowClass
|
||||
{
|
||||
public const uint InputOutput = 1;
|
||||
public const uint InputOnly = 2;
|
||||
}
|
||||
|
||||
public static class XCursorShape
|
||||
{
|
||||
public const uint XC_left_ptr = 68;
|
||||
public const uint XC_hand2 = 60;
|
||||
public const uint XC_xterm = 152;
|
||||
public const uint XC_watch = 150;
|
||||
public const uint XC_crosshair = 34;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
23
Interop/XButtonEvent.cs
Normal file
23
Interop/XButtonEvent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XButtonEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int XRoot;
|
||||
public int YRoot;
|
||||
public uint State;
|
||||
public uint Button;
|
||||
public int SameScreen;
|
||||
}
|
||||
16
Interop/XClientMessageEvent.cs
Normal file
16
Interop/XClientMessageEvent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XClientMessageEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr MessageType;
|
||||
public int Format;
|
||||
public ClientMessageData Data;
|
||||
}
|
||||
21
Interop/XConfigureEvent.cs
Normal file
21
Interop/XConfigureEvent.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XConfigureEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Event;
|
||||
public IntPtr Window;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int BorderWidth;
|
||||
public IntPtr Above;
|
||||
public int OverrideRedirect;
|
||||
}
|
||||
25
Interop/XCrossingEvent.cs
Normal file
25
Interop/XCrossingEvent.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XCrossingEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int XRoot;
|
||||
public int YRoot;
|
||||
public int Mode;
|
||||
public int Detail;
|
||||
public int SameScreen;
|
||||
public int Focus;
|
||||
public uint State;
|
||||
}
|
||||
13
Interop/XCursorShape.cs
Normal file
13
Interop/XCursorShape.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public static class XCursorShape
|
||||
{
|
||||
public const uint XC_left_ptr = 68;
|
||||
public const uint XC_hand2 = 60;
|
||||
public const uint XC_xterm = 152;
|
||||
public const uint XC_watch = 150;
|
||||
public const uint XC_crosshair = 34;
|
||||
}
|
||||
37
Interop/XEvent.cs
Normal file
37
Interop/XEvent.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 192)]
|
||||
public struct XEvent
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int Type;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XKeyEvent KeyEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XButtonEvent ButtonEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XMotionEvent MotionEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XConfigureEvent ConfigureEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XExposeEvent ExposeEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XClientMessageEvent ClientMessageEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XCrossingEvent CrossingEvent;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public XFocusChangeEvent FocusChangeEvent;
|
||||
}
|
||||
18
Interop/XEventMask.cs
Normal file
18
Interop/XEventMask.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public static class XEventMask
|
||||
{
|
||||
public const long KeyPressMask = 1L;
|
||||
public const long KeyReleaseMask = 2L;
|
||||
public const long ButtonPressMask = 4L;
|
||||
public const long ButtonReleaseMask = 8L;
|
||||
public const long EnterWindowMask = 16L;
|
||||
public const long LeaveWindowMask = 32L;
|
||||
public const long PointerMotionMask = 64L;
|
||||
public const long ExposureMask = 32768L;
|
||||
public const long StructureNotifyMask = 131072L;
|
||||
public const long FocusChangeMask = 2097152L;
|
||||
}
|
||||
20
Interop/XEventType.cs
Normal file
20
Interop/XEventType.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public static class XEventType
|
||||
{
|
||||
public const int KeyPress = 2;
|
||||
public const int KeyRelease = 3;
|
||||
public const int ButtonPress = 4;
|
||||
public const int ButtonRelease = 5;
|
||||
public const int MotionNotify = 6;
|
||||
public const int EnterNotify = 7;
|
||||
public const int LeaveNotify = 8;
|
||||
public const int FocusIn = 9;
|
||||
public const int FocusOut = 10;
|
||||
public const int Expose = 12;
|
||||
public const int ConfigureNotify = 22;
|
||||
public const int ClientMessage = 33;
|
||||
}
|
||||
18
Interop/XExposeEvent.cs
Normal file
18
Interop/XExposeEvent.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XExposeEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int Count;
|
||||
}
|
||||
15
Interop/XFocusChangeEvent.cs
Normal file
15
Interop/XFocusChangeEvent.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XFocusChangeEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public int Mode;
|
||||
public int Detail;
|
||||
}
|
||||
23
Interop/XKeyEvent.cs
Normal file
23
Interop/XKeyEvent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XKeyEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int XRoot;
|
||||
public int YRoot;
|
||||
public uint State;
|
||||
public uint Keycode;
|
||||
public int SameScreen;
|
||||
}
|
||||
23
Interop/XMotionEvent.cs
Normal file
23
Interop/XMotionEvent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XMotionEvent
|
||||
{
|
||||
public int Type;
|
||||
public ulong Serial;
|
||||
public int SendEvent;
|
||||
public IntPtr Display;
|
||||
public IntPtr Window;
|
||||
public IntPtr Root;
|
||||
public IntPtr Subwindow;
|
||||
public ulong Time;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int XRoot;
|
||||
public int YRoot;
|
||||
public uint State;
|
||||
public byte IsHint;
|
||||
public int SameScreen;
|
||||
}
|
||||
23
Interop/XSetWindowAttributes.cs
Normal file
23
Interop/XSetWindowAttributes.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public struct XSetWindowAttributes
|
||||
{
|
||||
public IntPtr BackgroundPixmap;
|
||||
public ulong BackgroundPixel;
|
||||
public IntPtr BorderPixmap;
|
||||
public ulong BorderPixel;
|
||||
public int BitGravity;
|
||||
public int WinGravity;
|
||||
public int BackingStore;
|
||||
public ulong BackingPlanes;
|
||||
public ulong BackingPixel;
|
||||
public int SaveUnder;
|
||||
public long EventMask;
|
||||
public long DoNotPropagateMask;
|
||||
public int OverrideRedirect;
|
||||
public IntPtr Colormap;
|
||||
public IntPtr Cursor;
|
||||
}
|
||||
10
Interop/XWindowClass.cs
Normal file
10
Interop/XWindowClass.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Interop;
|
||||
|
||||
public static class XWindowClass
|
||||
{
|
||||
public const uint InputOutput = 1;
|
||||
public const uint InputOnly = 2;
|
||||
}
|
||||
@@ -977,70 +977,3 @@ public class LinuxApplication : IDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for Linux application initialization.
|
||||
/// </summary>
|
||||
public class LinuxApplicationOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the window title.
|
||||
/// </summary>
|
||||
public string? Title { get; set; } = "MAUI Application";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the initial window width.
|
||||
/// </summary>
|
||||
public int Width { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the initial window height.
|
||||
/// </summary>
|
||||
public int Height { get; set; } = 600;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to use hardware acceleration.
|
||||
/// </summary>
|
||||
public bool UseHardwareAcceleration { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display server type.
|
||||
/// </summary>
|
||||
public DisplayServerType DisplayServer { get; set; } = DisplayServerType.Auto;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to force demo mode instead of loading the application's pages.
|
||||
/// </summary>
|
||||
public bool ForceDemo { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to use GTK mode instead of X11.
|
||||
/// </summary>
|
||||
public bool UseGtk { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the application icon.
|
||||
/// </summary>
|
||||
public string? IconPath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display server type options.
|
||||
/// </summary>
|
||||
public enum DisplayServerType
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically detect the display server.
|
||||
/// </summary>
|
||||
Auto,
|
||||
|
||||
/// <summary>
|
||||
/// Use X11 (Xorg).
|
||||
/// </summary>
|
||||
X11,
|
||||
|
||||
/// <summary>
|
||||
/// Use Wayland.
|
||||
/// </summary>
|
||||
Wayland
|
||||
}
|
||||
|
||||
23
LinuxApplicationOptions.cs
Normal file
23
LinuxApplicationOptions.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux;
|
||||
|
||||
public class LinuxApplicationOptions
|
||||
{
|
||||
public string? Title { get; set; } = "MAUI Application";
|
||||
|
||||
public int Width { get; set; } = 800;
|
||||
|
||||
public int Height { get; set; } = 600;
|
||||
|
||||
public bool UseHardwareAcceleration { get; set; } = true;
|
||||
|
||||
public DisplayServerType DisplayServer { get; set; }
|
||||
|
||||
public bool ForceDemo { get; set; }
|
||||
|
||||
public string? IconPath { get; set; }
|
||||
|
||||
public bool UseGtk { get; set; }
|
||||
}
|
||||
@@ -59,22 +59,26 @@
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| SkiaActivityIndicator.cs | [x] | Verified - all TwoWay, logic matches |
|
||||
| SkiaAlertDialog.cs | [ ] | |
|
||||
| SkiaBorder.cs | [ ] | Contains SkiaFrame |
|
||||
| SkiaAlertDialog.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, modal dialog rendering |
|
||||
| SkiaBorder.cs | [x] | **FIXED 2026-01-01** - Logic matches, removed embedded SkiaFrame (now separate file) |
|
||||
| SkiaFrame.cs | [x] | **ADDED 2026-01-01** - Created as separate file matching decompiled pattern |
|
||||
| SkiaBoxView.cs | [x] | Verified - all TwoWay, logic matches |
|
||||
| SkiaButton.cs | [x] | Verified - all TwoWay, logic matches |
|
||||
| SkiaCarouselView.cs | [ ] | |
|
||||
| SkiaCarouselView.cs | [x] | **FIXED 2026-01-01** - Logic matches, removed embedded PositionChangedEventArgs |
|
||||
| PositionChangedEventArgs.cs | [x] | **ADDED 2026-01-01** - Created as separate file matching decompiled |
|
||||
| SkiaCheckBox.cs | [x] | Verified - IsChecked=OneWay, rest TwoWay, logic matches |
|
||||
| SkiaCollectionView.cs | [ ] | |
|
||||
| SkiaCollectionView.cs | [x] | **FIXED 2026-01-01** - Removed embedded SkiaSelectionMode, ItemsLayoutOrientation |
|
||||
| SkiaSelectionMode.cs | [x] | **ADDED 2026-01-01** - Created as separate file |
|
||||
| ItemsLayoutOrientation.cs | [x] | **ADDED 2026-01-01** - Created as separate file |
|
||||
| SkiaContentPresenter.cs | [ ] | |
|
||||
| SkiaContextMenu.cs | [ ] | |
|
||||
| SkiaDatePicker.cs | [ ] | |
|
||||
| SkiaDatePicker.cs | [x] | **VERIFIED 2026-01-01** - Date=OneWay, all others=TwoWay |
|
||||
| SkiaEditor.cs | [x] | **FIXED 2026-01-01** - All BindingModes corrected (Text=OneWay, others=TwoWay) |
|
||||
| SkiaEntry.cs | [x] | **FIXED 2026-01-01** - TextProperty BindingMode.OneWay, others TwoWay |
|
||||
| SkiaFlexLayout.cs | [ ] | |
|
||||
| SkiaFlyoutPage.cs | [ ] | |
|
||||
| SkiaGraphicsView.cs | [ ] | |
|
||||
| SkiaImage.cs | [ ] | |
|
||||
| SkiaImage.cs | [x] | **VERIFIED 2026-01-01** - No BindableProperties, logic matches |
|
||||
| SkiaImageButton.cs | [ ] | |
|
||||
| SkiaIndicatorView.cs | [ ] | |
|
||||
| SkiaItemsView.cs | [x] | Added GetItemView() method |
|
||||
@@ -85,18 +89,18 @@
|
||||
| SkiaPage.cs | [x] | Added SkiaToolbarItem.Icon property |
|
||||
| SkiaPicker.cs | [x] | FIXED - SelectedIndex=OneWay, all others=TwoWay (was missing) |
|
||||
| SkiaProgressBar.cs | [x] | Verified - Progress=OneWay, rest TwoWay, logic matches |
|
||||
| SkiaRadioButton.cs | [ ] | |
|
||||
| SkiaRadioButton.cs | [x] | **FIXED 2026-01-01** - IsChecked=OneWay, all others=TwoWay |
|
||||
| SkiaRefreshView.cs | [ ] | |
|
||||
| SkiaScrollView.cs | [x] | **FIXED 2026-01-01** - All BindingModes TwoWay |
|
||||
| SkiaSearchBar.cs | [ ] | |
|
||||
| SkiaSearchBar.cs | [x] | **VERIFIED 2026-01-01** - No BindableProperties, logic matches |
|
||||
| SkiaShell.cs | [x] | **FIXED 2026-01-01** - Added FlyoutTextColor, ContentBackgroundColor, route registration, query parameters, OnScroll |
|
||||
| SkiaSlider.cs | [x] | FIXED - Value=OneWay, rest TwoWay (agent had inverted all) |
|
||||
| SkiaStepper.cs | [ ] | |
|
||||
| SkiaStepper.cs | [x] | **FIXED 2026-01-01** - Value=OneWay, all others=TwoWay |
|
||||
| SkiaSwipeView.cs | [ ] | |
|
||||
| SkiaSwitch.cs | [x] | FIXED - IsOn=OneWay (agent had TwoWay) |
|
||||
| SkiaTabbedPage.cs | [ ] | |
|
||||
| SkiaTemplatedView.cs | [ ] | |
|
||||
| SkiaTimePicker.cs | [ ] | |
|
||||
| SkiaTimePicker.cs | [x] | **FIXED 2026-01-01** - Time=OneWay, all others=TwoWay |
|
||||
| SkiaView.cs | [x] | Made Arrange() virtual |
|
||||
| SkiaVisualStateManager.cs | [ ] | |
|
||||
| SkiaWebView.cs | [x] | **FIXED 2026-01-01** - Full X11 embedding, position tracking, hardware accel, load callbacks |
|
||||
@@ -107,43 +111,108 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| AppActionsService.cs | [ ] | |
|
||||
| AppInfoService.cs | [ ] | |
|
||||
| AtSpi2AccessibilityService.cs | [ ] | |
|
||||
| BrowserService.cs | [ ] | |
|
||||
| ClipboardService.cs | [ ] | |
|
||||
| ConnectivityService.cs | [ ] | |
|
||||
| DeviceDisplayService.cs | [ ] | |
|
||||
| DeviceInfoService.cs | [ ] | |
|
||||
| DisplayServerFactory.cs | [ ] | |
|
||||
| DragDropService.cs | [ ] | |
|
||||
| EmailService.cs | [ ] | |
|
||||
| Fcitx5InputMethodService.cs | [ ] | |
|
||||
| FilePickerService.cs | [ ] | |
|
||||
| FolderPickerService.cs | [ ] | |
|
||||
| FontFallbackManager.cs | [ ] | |
|
||||
| GlobalHotkeyService.cs | [ ] | |
|
||||
| Gtk4InteropService.cs | [ ] | |
|
||||
| GtkHostService.cs | [ ] | |
|
||||
| HardwareVideoService.cs | [ ] | |
|
||||
| HiDpiService.cs | [ ] | |
|
||||
| HighContrastService.cs | [ ] | |
|
||||
| IAccessibilityService.cs | [ ] | |
|
||||
| IBusInputMethodService.cs | [ ] | |
|
||||
| IInputMethodService.cs | [ ] | |
|
||||
| InputMethodServiceFactory.cs | [ ] | |
|
||||
| LauncherService.cs | [ ] | |
|
||||
| LinuxResourcesProvider.cs | [ ] | |
|
||||
| NotificationService.cs | [ ] | |
|
||||
| PortalFilePickerService.cs | [ ] | |
|
||||
| PreferencesService.cs | [ ] | |
|
||||
| SecureStorageService.cs | [ ] | |
|
||||
| ShareService.cs | [ ] | |
|
||||
| SystemThemeService.cs | [ ] | |
|
||||
| SystemTrayService.cs | [ ] | |
|
||||
| VersionTrackingService.cs | [ ] | |
|
||||
| VirtualizationManager.cs | [ ] | |
|
||||
| X11InputMethodService.cs | [ ] | |
|
||||
| AccessibilityServiceFactory.cs | [x] | **FIXED 2026-01-01** - Fixed CreateService() to call Initialize(), added Reset() |
|
||||
| AccessibleAction.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| AccessibleProperty.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (Name,Description,Role,Value,Parent,Children) |
|
||||
| AccessibleRect.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| AccessibleRole.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (simplified list with Button,Tab,TabPanel) |
|
||||
| AccessibleState.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| AccessibleStates.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (MultiSelectable capital S) |
|
||||
| AnnouncementPriority.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (Polite,Assertive) |
|
||||
| AppActionsService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean string interpolation |
|
||||
| AppInfoService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean enum names |
|
||||
| AtSpi2AccessibilityService.cs | [x] | **FIXED 2026-01-01** - Removed embedded AccessibilityServiceFactory, NullAccessibilityService |
|
||||
| BrowserService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean nameof/interpolation/enums |
|
||||
| ClipboardService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, xclip/xsel fallback |
|
||||
| ColorDialogResult.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| ConnectivityService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean enum names |
|
||||
| DesktopEnvironment.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (GNOME uppercase) |
|
||||
| DeviceDisplayService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean enum names |
|
||||
| DeviceInfoService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean enum names |
|
||||
| DisplayServerFactory.cs | [x] | **FIXED 2026-01-01** - Removed embedded DisplayServerType, IDisplayWindow, X11DisplayWindow, WaylandDisplayWindow |
|
||||
| DisplayServerType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| DragAction.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| DragData.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| DragDropService.cs | [x] | **FIXED 2026-01-01** - Removed embedded DragData, DragEventArgs, DropEventArgs, DragAction |
|
||||
| DragEventArgs.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| DropEventArgs.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| EmailService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean nameof/interpolation |
|
||||
| Fcitx5InputMethodService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, D-Bus interface |
|
||||
| FileDialogResult.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| FilePickerService.cs | [x] | **FIXED 2026-01-01** - Removed embedded LinuxFileResult |
|
||||
| FolderPickerOptions.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| FolderPickerResult.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| FolderPickerService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, zenity/kdialog fallback |
|
||||
| FolderResult.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled |
|
||||
| FontFallbackManager.cs | [x] | **FIXED 2026-01-01** - Removed embedded TextRun |
|
||||
| GlobalHotkeyService.cs | [x] | **FIXED 2026-01-01** - Removed embedded HotkeyEventArgs, HotkeyModifiers, HotkeyKey |
|
||||
| Gtk4InteropService.cs | [x] | **FIXED 2026-01-01** - Removed embedded GtkResponseType, GtkMessageType, GtkButtonsType, GtkFileChooserAction, FileDialogResult, ColorDialogResult |
|
||||
| GtkButtonsType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| GtkContextMenuService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, GTK P/Invoke |
|
||||
| GtkFileChooserAction.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| GtkHostService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, main has clean ??= syntax |
|
||||
| GtkMenuItem.cs | [x] | **VERIFIED 2026-01-01** - Identical logic |
|
||||
| GtkMessageType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| GtkResponseType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| HardwareVideoService.cs | [x] | **FIXED 2026-01-01** - Removed embedded VideoAccelerationApi, VideoProfile, VideoFrame |
|
||||
| HiDpiService.cs | [x] | **FIXED 2026-01-01** - Removed embedded ScaleChangedEventArgs |
|
||||
| HighContrastChangedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| HighContrastColors.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| HighContrastService.cs | [x] | **FIXED 2026-01-01** - Removed embedded HighContrastTheme, HighContrastColors, HighContrastChangedEventArgs |
|
||||
| HighContrastTheme.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled (None,WhiteOnBlack,BlackOnWhite) |
|
||||
| HotkeyEventArgs.cs | [x] | **FIXED 2026-01-01** - Fixed constructor order (int id, HotkeyKey key, HotkeyModifiers modifiers) |
|
||||
| HotkeyKey.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| HotkeyModifiers.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| IAccessibilityService.cs | [x] | **FIXED 2026-01-01** - Removed many embedded types |
|
||||
| IAccessible.cs | [x] | **FIXED 2026-01-01** - Fixed to match decompiled exactly |
|
||||
| IAccessibleEditableText.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| IAccessibleText.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| IBusInputMethodService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, IBus D-Bus interface |
|
||||
| IDisplayWindow.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| IInputContext.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| IInputMethodService.cs | [x] | **FIXED 2026-01-01** - Removed embedded IInputContext, TextCommittedEventArgs, PreEditChangedEventArgs, PreEditAttribute, PreEditAttributeType, KeyModifiers |
|
||||
| InputMethodServiceFactory.cs | [x] | **FIXED 2026-01-01** - Removed embedded NullInputMethodService |
|
||||
| KeyModifiers.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| LauncherService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, xdg-open |
|
||||
| LinuxFileResult.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| LinuxResourcesProvider.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, system styles |
|
||||
| MauiIconGenerator.cs | [x] | **FIXED 2026-01-01** - Added Svg.Skia, SVG foreground, Scale metadata |
|
||||
| NotificationAction.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationActionEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationClosedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationCloseReason.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationContext.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationOptions.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NotificationService.cs | [x] | **FIXED 2026-01-01** - Removed embedded NotificationOptions, NotificationUrgency, NotificationCloseReason, NotificationContext, NotificationActionEventArgs, NotificationClosedEventArgs, NotificationAction |
|
||||
| NotificationUrgency.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NullAccessibilityService.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| NullInputMethodService.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| PortalFilePickerService.cs | [x] | **FIXED 2026-01-01** - Removed embedded FolderResult, FolderPickerResult, FolderPickerOptions, PortalFolderPickerService |
|
||||
| PortalFolderPickerService.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| PreEditAttribute.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| PreEditAttributeType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| PreEditChangedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| PreferencesService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, JSON file storage with XDG |
|
||||
| ScaleChangedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SecureStorageService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, secret-tool with AES fallback |
|
||||
| ShareService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, xdg-open with portal fallback |
|
||||
| SystemColors.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SystemTheme.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SystemThemeService.cs | [x] | **FIXED 2026-01-01** - Removed embedded SystemTheme, DesktopEnvironment, ThemeChangedEventArgs, SystemColors |
|
||||
| SystemTrayService.cs | [x] | **FIXED 2026-01-01** - Removed embedded TrayMenuItem |
|
||||
| TextCommittedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| TextRun.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| ThemeChangedEventArgs.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| TrayMenuItem.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| VersionTrackingService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, JSON tracking file |
|
||||
| VideoAccelerationApi.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| VideoFrame.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| VideoProfile.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| VirtualizationExtensions.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| VirtualizationManager.cs | [x] | **FIXED 2026-01-01** - Removed embedded VirtualizationExtensions |
|
||||
| WaylandDisplayWindow.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| X11DisplayWindow.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| X11InputMethodService.cs | [x] | **VERIFIED 2026-01-01** - Logic matches, X11 XIM interface |
|
||||
|
||||
---
|
||||
|
||||
@@ -151,12 +220,17 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| LinuxMauiAppBuilderExtensions.cs | [ ] | |
|
||||
| LinuxMauiContext.cs | [ ] | |
|
||||
| LinuxProgramHost.cs | [ ] | |
|
||||
| LinuxViewRenderer.cs | [ ] | |
|
||||
| MauiAppBuilderExtensions.cs | [ ] | |
|
||||
| MauiHandlerExtensions.cs | [ ] | |
|
||||
| GtkMauiContext.cs | [x] | **ADDED 2026-01-01** - Was missing, created from decompiled |
|
||||
| HandlerMappingExtensions.cs | [x] | **ADDED 2026-01-01** - Was missing, created from decompiled |
|
||||
| LinuxAnimationManager.cs | [x] | **ADDED 2026-01-01** - Was missing, created from decompiled |
|
||||
| LinuxMauiAppBuilderExtensions.cs | [x] | **FIXED 2026-01-01** - Added IDispatcherProvider, IDeviceInfo, IDeviceDisplay, IAppInfo, IConnectivity, GtkHostService registrations; fixed WebView to use GtkWebViewHandler |
|
||||
| LinuxMauiContext.cs | [x] | **FIXED 2026-01-01** - Removed embedded classes (now separate files), added LinuxDispatcher using |
|
||||
| LinuxProgramHost.cs | [x] | **FIXED 2026-01-01** - Added GtkHostService.Initialize call for WebView support |
|
||||
| LinuxTicker.cs | [x] | **ADDED 2026-01-01** - Was missing, created from decompiled |
|
||||
| LinuxViewRenderer.cs | [x] | **FIXED 2026-01-01** - Added ApplyShellColors(), FlyoutHeader rendering, FlyoutFooterText, MauiShellContent, ContentRenderer/ColorRefresher delegates, page BackgroundColor handling |
|
||||
| MauiAppBuilderExtensions.cs | [x] | **DELETED 2026-01-01** - Not in decompiled, was outdated duplicate with wrong namespace |
|
||||
| MauiHandlerExtensions.cs | [x] | **FIXED 2026-01-01** - Fixed WebView to use GtkWebViewHandler, FlexLayout to use LayoutHandler |
|
||||
| ScopedLinuxMauiContext.cs | [x] | **ADDED 2026-01-01** - Was missing, created from decompiled |
|
||||
|
||||
---
|
||||
|
||||
@@ -164,9 +238,9 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| LinuxDispatcher.cs | [ ] | |
|
||||
| LinuxDispatcherProvider.cs | [ ] | |
|
||||
| LinuxDispatcherTimer.cs | [ ] | |
|
||||
| LinuxDispatcher.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, clean syntax |
|
||||
| LinuxDispatcherProvider.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| LinuxDispatcherTimer.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, clean syntax |
|
||||
|
||||
---
|
||||
|
||||
@@ -174,11 +248,11 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| CairoNative.cs | [ ] | |
|
||||
| GdkNative.cs | [ ] | |
|
||||
| GLibNative.cs | [ ] | |
|
||||
| GtkNative.cs | [ ] | |
|
||||
| WebKitNative.cs | [ ] | |
|
||||
| CairoNative.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| GdkNative.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| GLibNative.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| GtkNative.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| WebKitNative.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
|
||||
---
|
||||
|
||||
@@ -186,9 +260,10 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| CursorType.cs | [ ] | |
|
||||
| GtkHostWindow.cs | [ ] | |
|
||||
| X11Window.cs | [ ] | |
|
||||
| CursorType.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| GtkHostWindow.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, main has clean comments |
|
||||
| WaylandWindow.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, main has clean comments |
|
||||
| X11Window.cs | [x] | **FIXED 2026-01-01** - Added SVG icon support, event counter logging from decompiled |
|
||||
|
||||
---
|
||||
|
||||
@@ -196,7 +271,52 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| GtkSkiaSurfaceWidget.cs | [ ] | |
|
||||
| GpuRenderingEngine.cs | [x] | **FIXED 2026-01-01** - Removed embedded GpuStats |
|
||||
| GpuStats.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| GtkSkiaSurfaceWidget.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, same public API |
|
||||
| LayeredRenderer.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| RenderCache.cs | [x] | **FIXED 2026-01-01** - Removed embedded LayeredRenderer, RenderLayer, TextRenderCache |
|
||||
| RenderLayer.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| ResourceCache.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
| SkiaRenderingEngine.cs | [x] | **FIXED 2026-01-01** - Removed embedded ResourceCache |
|
||||
| TextRenderCache.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled |
|
||||
|
||||
---
|
||||
|
||||
## INTEROP
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| ClientMessageData.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| WebKitGtk.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, main has cleaner formatting with regions |
|
||||
| X11.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled, X11Interop.cs DELETED (was duplicate) |
|
||||
| XButtonEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XClientMessageEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XConfigureEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XCrossingEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XCursorShape.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XEventMask.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XEventType.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XExposeEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XFocusChangeEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XKeyEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XMotionEvent.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XSetWindowAttributes.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| XWindowClass.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
|
||||
---
|
||||
|
||||
## CONVERTERS
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| ColorExtensions.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SKColorTypeConverter.cs | [x] | **FIXED 2026-01-01** - Removed embedded ColorExtensions |
|
||||
| SKPointTypeConverter.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SKRectTypeConverter.cs | [x] | **FIXED 2026-01-01** - Removed embedded SKSizeTypeConverter, SKPointTypeConverter, SKTypeExtensions |
|
||||
| SKSizeTypeConverter.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
| SKTypeExtensions.cs | [x] | **VERIFIED 2026-01-01** - Separate file, matches decompiled |
|
||||
|
||||
---
|
||||
|
||||
@@ -204,8 +324,8 @@
|
||||
|
||||
| File | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| LinuxApplication.cs | [ ] | |
|
||||
| LinuxApplicationOptions.cs | [ ] | |
|
||||
| LinuxApplication.cs | [x] | **FIXED 2026-01-01** - Removed embedded DisplayServerType, LinuxApplicationOptions |
|
||||
| LinuxApplicationOptions.cs | [x] | **VERIFIED 2026-01-01** - Matches decompiled (separate file) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -333,17 +333,3 @@ public class GpuRenderingEngine : IDisposable
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GPU performance statistics.
|
||||
/// </summary>
|
||||
public class GpuStats
|
||||
{
|
||||
public bool IsGpuAccelerated { get; init; }
|
||||
public int MaxTextureSize { get; init; }
|
||||
public long ResourceCacheUsedBytes { get; init; }
|
||||
public long ResourceCacheLimitBytes { get; init; }
|
||||
|
||||
public double ResourceCacheUsedMB => ResourceCacheUsedBytes / (1024.0 * 1024.0);
|
||||
public double ResourceCacheLimitMB => ResourceCacheLimitBytes / (1024.0 * 1024.0);
|
||||
}
|
||||
|
||||
19
Rendering/GpuStats.cs
Normal file
19
Rendering/GpuStats.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
public class GpuStats
|
||||
{
|
||||
public bool IsGpuAccelerated { get; init; }
|
||||
|
||||
public int MaxTextureSize { get; init; }
|
||||
|
||||
public long ResourceCacheUsedBytes { get; init; }
|
||||
|
||||
public long ResourceCacheLimitBytes { get; init; }
|
||||
|
||||
public double ResourceCacheUsedMB => ResourceCacheUsedBytes / 1048576.0;
|
||||
|
||||
public double ResourceCacheLimitMB => ResourceCacheLimitBytes / 1048576.0;
|
||||
}
|
||||
75
Rendering/LayeredRenderer.cs
Normal file
75
Rendering/LayeredRenderer.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
public class LayeredRenderer : IDisposable
|
||||
{
|
||||
private readonly Dictionary<int, RenderLayer> _layers = new();
|
||||
private readonly object _lock = new();
|
||||
private bool _disposed;
|
||||
|
||||
public RenderLayer GetLayer(int zIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_layers.TryGetValue(zIndex, out var layer))
|
||||
{
|
||||
layer = new RenderLayer(zIndex);
|
||||
_layers[zIndex] = layer;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveLayer(int zIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_layers.TryGetValue(zIndex, out var layer))
|
||||
{
|
||||
layer.Dispose();
|
||||
_layers.Remove(zIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Composite(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values.OrderBy(l => l.ZIndex))
|
||||
{
|
||||
layer.DrawTo(canvas, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidateAll()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values)
|
||||
{
|
||||
layer.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values)
|
||||
{
|
||||
layer.Dispose();
|
||||
}
|
||||
_layers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,291 +236,3 @@ public class RenderCache : IDisposable
|
||||
public int AccessCount { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides layered rendering for separating static and dynamic content.
|
||||
/// </summary>
|
||||
public class LayeredRenderer : IDisposable
|
||||
{
|
||||
private readonly Dictionary<int, RenderLayer> _layers = new();
|
||||
private readonly object _lock = new();
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or creates a render layer.
|
||||
/// </summary>
|
||||
public RenderLayer GetLayer(int zIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_layers.TryGetValue(zIndex, out var layer))
|
||||
{
|
||||
layer = new RenderLayer(zIndex);
|
||||
_layers[zIndex] = layer;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a render layer.
|
||||
/// </summary>
|
||||
public void RemoveLayer(int zIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_layers.TryGetValue(zIndex, out var layer))
|
||||
{
|
||||
layer.Dispose();
|
||||
_layers.Remove(zIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Composites all layers onto the target canvas.
|
||||
/// </summary>
|
||||
public void Composite(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values.OrderBy(l => l.ZIndex))
|
||||
{
|
||||
layer.DrawTo(canvas, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates all layers.
|
||||
/// </summary>
|
||||
public void InvalidateAll()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values)
|
||||
{
|
||||
layer.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var layer in _layers.Values)
|
||||
{
|
||||
layer.Dispose();
|
||||
}
|
||||
_layers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single render layer with its own bitmap buffer.
|
||||
/// </summary>
|
||||
public class RenderLayer : IDisposable
|
||||
{
|
||||
private SKBitmap? _bitmap;
|
||||
private SKCanvas? _canvas;
|
||||
private bool _isDirty = true;
|
||||
private SKRect _bounds;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Z-index of this layer.
|
||||
/// </summary>
|
||||
public int ZIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this layer needs to be redrawn.
|
||||
/// </summary>
|
||||
public bool IsDirty => _isDirty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this layer is visible.
|
||||
/// </summary>
|
||||
public bool IsVisible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the layer opacity (0-1).
|
||||
/// </summary>
|
||||
public float Opacity { get; set; } = 1f;
|
||||
|
||||
public RenderLayer(int zIndex)
|
||||
{
|
||||
ZIndex = zIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the layer for rendering.
|
||||
/// </summary>
|
||||
public SKCanvas BeginDraw(SKRect bounds)
|
||||
{
|
||||
if (_bitmap == null || _bounds != bounds)
|
||||
{
|
||||
_bitmap?.Dispose();
|
||||
_canvas?.Dispose();
|
||||
|
||||
int width = Math.Max(1, (int)bounds.Width);
|
||||
int height = Math.Max(1, (int)bounds.Height);
|
||||
|
||||
_bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||
_canvas = new SKCanvas(_bitmap);
|
||||
_bounds = bounds;
|
||||
}
|
||||
|
||||
_canvas!.Clear(SKColors.Transparent);
|
||||
_isDirty = false;
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the layer as needing redraw.
|
||||
/// </summary>
|
||||
public void Invalidate()
|
||||
{
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws this layer to the target canvas.
|
||||
/// </summary>
|
||||
public void DrawTo(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
if (!IsVisible || _bitmap == null) return;
|
||||
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Color = SKColors.White.WithAlpha((byte)(Opacity * 255))
|
||||
};
|
||||
|
||||
canvas.DrawBitmap(_bitmap, bounds.Left, bounds.Top, paint);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
_canvas?.Dispose();
|
||||
_bitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides text rendering optimization with glyph caching.
|
||||
/// </summary>
|
||||
public class TextRenderCache : IDisposable
|
||||
{
|
||||
private readonly Dictionary<TextCacheKey, SKBitmap> _cache = new();
|
||||
private readonly object _lock = new();
|
||||
private int _maxEntries = 500;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of cached text entries.
|
||||
/// </summary>
|
||||
public int MaxEntries
|
||||
{
|
||||
get => _maxEntries;
|
||||
set => _maxEntries = Math.Max(10, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a cached text bitmap or creates one.
|
||||
/// </summary>
|
||||
public SKBitmap GetOrCreate(string text, SKPaint paint)
|
||||
{
|
||||
var key = new TextCacheKey(text, paint);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_cache.TryGetValue(key, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Create text bitmap
|
||||
var bounds = new SKRect();
|
||||
paint.MeasureText(text, ref bounds);
|
||||
|
||||
int width = Math.Max(1, (int)Math.Ceiling(bounds.Width) + 2);
|
||||
int height = Math.Max(1, (int)Math.Ceiling(bounds.Height) + 2);
|
||||
|
||||
var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
{
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
canvas.DrawText(text, -bounds.Left + 1, -bounds.Top + 1, paint);
|
||||
}
|
||||
|
||||
// Trim cache if needed
|
||||
if (_cache.Count >= _maxEntries)
|
||||
{
|
||||
var oldest = _cache.First();
|
||||
oldest.Value.Dispose();
|
||||
_cache.Remove(oldest.Key);
|
||||
}
|
||||
|
||||
_cache[key] = bitmap;
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cached text.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var entry in _cache.Values)
|
||||
{
|
||||
entry.Dispose();
|
||||
}
|
||||
_cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
Clear();
|
||||
}
|
||||
|
||||
private readonly struct TextCacheKey : IEquatable<TextCacheKey>
|
||||
{
|
||||
private readonly string _text;
|
||||
private readonly float _textSize;
|
||||
private readonly SKColor _color;
|
||||
private readonly int _weight;
|
||||
private readonly int _hashCode;
|
||||
|
||||
public TextCacheKey(string text, SKPaint paint)
|
||||
{
|
||||
_text = text;
|
||||
_textSize = paint.TextSize;
|
||||
_color = paint.Color;
|
||||
_weight = paint.Typeface?.FontWeight ?? (int)SKFontStyleWeight.Normal;
|
||||
_hashCode = HashCode.Combine(_text, _textSize, _color, _weight);
|
||||
}
|
||||
|
||||
public bool Equals(TextCacheKey other)
|
||||
{
|
||||
return _text == other._text &&
|
||||
Math.Abs(_textSize - other._textSize) < 0.001f &&
|
||||
_color == other._color &&
|
||||
_weight == other._weight;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj) => obj is TextCacheKey other && Equals(other);
|
||||
public override int GetHashCode() => _hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
72
Rendering/RenderLayer.cs
Normal file
72
Rendering/RenderLayer.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
public class RenderLayer : IDisposable
|
||||
{
|
||||
private SKBitmap? _bitmap;
|
||||
private SKCanvas? _canvas;
|
||||
private bool _isDirty = true;
|
||||
private SKRect _bounds;
|
||||
private bool _disposed;
|
||||
|
||||
public int ZIndex { get; }
|
||||
|
||||
public bool IsDirty => _isDirty;
|
||||
|
||||
public bool IsVisible { get; set; } = true;
|
||||
|
||||
public float Opacity { get; set; } = 1f;
|
||||
|
||||
public RenderLayer(int zIndex)
|
||||
{
|
||||
ZIndex = zIndex;
|
||||
}
|
||||
|
||||
public SKCanvas BeginDraw(SKRect bounds)
|
||||
{
|
||||
if (_bitmap == null || _bounds != bounds)
|
||||
{
|
||||
_bitmap?.Dispose();
|
||||
_canvas?.Dispose();
|
||||
|
||||
var width = Math.Max(1, (int)bounds.Width);
|
||||
var height = Math.Max(1, (int)bounds.Height);
|
||||
_bitmap = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Premul);
|
||||
_canvas = new SKCanvas(_bitmap);
|
||||
_bounds = bounds;
|
||||
}
|
||||
|
||||
_canvas!.Clear(SKColors.Transparent);
|
||||
_isDirty = false;
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
public void DrawTo(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
if (!IsVisible || _bitmap == null) return;
|
||||
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Color = SKColors.White.WithAlpha((byte)(Opacity * 255f))
|
||||
};
|
||||
canvas.DrawBitmap(_bitmap, bounds.Left, bounds.Top, paint);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
_canvas?.Dispose();
|
||||
_bitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
43
Rendering/ResourceCache.cs
Normal file
43
Rendering/ResourceCache.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
public class ResourceCache : IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, SKTypeface> _typefaces = new();
|
||||
private bool _disposed;
|
||||
|
||||
public SKTypeface GetTypeface(string fontFamily, SKFontStyle style)
|
||||
{
|
||||
var key = $"{fontFamily}_{style.Weight}_{style.Width}_{style.Slant}";
|
||||
|
||||
if (!_typefaces.TryGetValue(key, out var typeface))
|
||||
{
|
||||
typeface = SKTypeface.FromFamilyName(fontFamily, style) ?? SKTypeface.Default;
|
||||
_typefaces[key] = typeface;
|
||||
}
|
||||
|
||||
return typeface;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var typeface in _typefaces.Values)
|
||||
{
|
||||
typeface.Dispose();
|
||||
}
|
||||
_typefaces.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
Clear();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,31 +313,3 @@ public class SkiaRenderingEngine : IDisposable
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class ResourceCache : IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, SKTypeface> _typefaces = new();
|
||||
private bool _disposed;
|
||||
|
||||
public SKTypeface GetTypeface(string fontFamily, SKFontStyle style)
|
||||
{
|
||||
var key = $"{fontFamily}_{style.Weight}_{style.Width}_{style.Slant}";
|
||||
if (!_typefaces.TryGetValue(key, out var typeface))
|
||||
{
|
||||
typeface = SKTypeface.FromFamilyName(fontFamily, style) ?? SKTypeface.Default;
|
||||
_typefaces[key] = typeface;
|
||||
}
|
||||
return typeface;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var tf in _typefaces.Values) tf.Dispose();
|
||||
_typefaces.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed) { Clear(); _disposed = true; }
|
||||
}
|
||||
}
|
||||
|
||||
108
Rendering/TextRenderCache.cs
Normal file
108
Rendering/TextRenderCache.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
public class TextRenderCache : IDisposable
|
||||
{
|
||||
private readonly struct TextCacheKey : IEquatable<TextCacheKey>
|
||||
{
|
||||
private readonly string _text;
|
||||
private readonly float _textSize;
|
||||
private readonly SKColor _color;
|
||||
private readonly int _weight;
|
||||
private readonly int _hashCode;
|
||||
|
||||
public TextCacheKey(string text, SKPaint paint)
|
||||
{
|
||||
_text = text;
|
||||
_textSize = paint.TextSize;
|
||||
_color = paint.Color;
|
||||
_weight = paint.Typeface?.FontWeight ?? 400;
|
||||
_hashCode = HashCode.Combine(_text, _textSize, _color, _weight);
|
||||
}
|
||||
|
||||
public bool Equals(TextCacheKey other)
|
||||
{
|
||||
return _text == other._text
|
||||
&& Math.Abs(_textSize - other._textSize) < 0.001f
|
||||
&& _color == other._color
|
||||
&& _weight == other._weight;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TextCacheKey other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => _hashCode;
|
||||
}
|
||||
|
||||
private readonly Dictionary<TextCacheKey, SKBitmap> _cache = new();
|
||||
private readonly object _lock = new();
|
||||
private int _maxEntries = 500;
|
||||
private bool _disposed;
|
||||
|
||||
public int MaxEntries
|
||||
{
|
||||
get => _maxEntries;
|
||||
set => _maxEntries = Math.Max(10, value);
|
||||
}
|
||||
|
||||
public SKBitmap GetOrCreate(string text, SKPaint paint)
|
||||
{
|
||||
var key = new TextCacheKey(text, paint);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_cache.TryGetValue(key, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
var bounds = new SKRect();
|
||||
paint.MeasureText(text, ref bounds);
|
||||
|
||||
var width = Math.Max(1, (int)Math.Ceiling(bounds.Width) + 2);
|
||||
var height = Math.Max(1, (int)Math.Ceiling(bounds.Height) + 2);
|
||||
|
||||
var bitmap = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Premul);
|
||||
using var canvas = new SKCanvas(bitmap);
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
canvas.DrawText(text, -bounds.Left + 1f, -bounds.Top + 1f, paint);
|
||||
|
||||
if (_cache.Count >= _maxEntries)
|
||||
{
|
||||
var first = _cache.First();
|
||||
first.Value.Dispose();
|
||||
_cache.Remove(first.Key);
|
||||
}
|
||||
|
||||
_cache[key] = bitmap;
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var bitmap in _cache.Values)
|
||||
{
|
||||
bitmap.Dispose();
|
||||
}
|
||||
_cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Services/AccessibilityServiceFactory.cs
Normal file
48
Services/AccessibilityServiceFactory.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public static class AccessibilityServiceFactory
|
||||
{
|
||||
private static IAccessibilityService? _instance;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
public static IAccessibilityService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance ??= CreateService();
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static IAccessibilityService CreateService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new AtSpi2AccessibilityService();
|
||||
service.Initialize();
|
||||
return service;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new NullAccessibilityService();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance?.Shutdown();
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Services/AccessibleAction.cs
Normal file
11
Services/AccessibleAction.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class AccessibleAction
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string KeyBinding { get; set; } = "";
|
||||
}
|
||||
14
Services/AccessibleProperty.cs
Normal file
14
Services/AccessibleProperty.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleProperty
|
||||
{
|
||||
Name,
|
||||
Description,
|
||||
Role,
|
||||
Value,
|
||||
Parent,
|
||||
Children
|
||||
}
|
||||
20
Services/AccessibleRect.cs
Normal file
20
Services/AccessibleRect.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public struct AccessibleRect
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
public AccessibleRect(int x, int y, int width, int height)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
52
Services/AccessibleRole.cs
Normal file
52
Services/AccessibleRole.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleRole
|
||||
{
|
||||
Unknown,
|
||||
Window,
|
||||
Application,
|
||||
Panel,
|
||||
Frame,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
ComboBox,
|
||||
Entry,
|
||||
Label,
|
||||
List,
|
||||
ListItem,
|
||||
Menu,
|
||||
MenuBar,
|
||||
MenuItem,
|
||||
ScrollBar,
|
||||
Slider,
|
||||
SpinButton,
|
||||
StatusBar,
|
||||
Tab,
|
||||
TabPanel,
|
||||
Text,
|
||||
ToggleButton,
|
||||
ToolBar,
|
||||
ToolTip,
|
||||
Tree,
|
||||
TreeItem,
|
||||
Image,
|
||||
ProgressBar,
|
||||
Separator,
|
||||
Link,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TableColumnHeader,
|
||||
TableRowHeader,
|
||||
PageTab,
|
||||
PageTabList,
|
||||
Dialog,
|
||||
Alert,
|
||||
Filler,
|
||||
Icon,
|
||||
Canvas
|
||||
}
|
||||
52
Services/AccessibleState.cs
Normal file
52
Services/AccessibleState.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleState
|
||||
{
|
||||
Invalid,
|
||||
Active,
|
||||
Armed,
|
||||
Busy,
|
||||
Checked,
|
||||
Collapsed,
|
||||
Defunct,
|
||||
Editable,
|
||||
Enabled,
|
||||
Expandable,
|
||||
Expanded,
|
||||
Focusable,
|
||||
Focused,
|
||||
HasToolTip,
|
||||
Horizontal,
|
||||
Iconified,
|
||||
Modal,
|
||||
MultiLine,
|
||||
Multiselectable,
|
||||
Opaque,
|
||||
Pressed,
|
||||
Resizable,
|
||||
Selectable,
|
||||
Selected,
|
||||
Sensitive,
|
||||
Showing,
|
||||
SingleLine,
|
||||
Stale,
|
||||
Transient,
|
||||
Vertical,
|
||||
Visible,
|
||||
ManagesDescendants,
|
||||
Indeterminate,
|
||||
Required,
|
||||
Truncated,
|
||||
Animated,
|
||||
InvalidEntry,
|
||||
SupportsAutocompletion,
|
||||
SelectableText,
|
||||
IsDefault,
|
||||
Visited,
|
||||
Checkable,
|
||||
HasPopup,
|
||||
ReadOnly
|
||||
}
|
||||
51
Services/AccessibleStates.cs
Normal file
51
Services/AccessibleStates.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum AccessibleStates : long
|
||||
{
|
||||
None = 0L,
|
||||
Active = 1L,
|
||||
Armed = 2L,
|
||||
Busy = 4L,
|
||||
Checked = 8L,
|
||||
Collapsed = 0x10L,
|
||||
Defunct = 0x20L,
|
||||
Editable = 0x40L,
|
||||
Enabled = 0x80L,
|
||||
Expandable = 0x100L,
|
||||
Expanded = 0x200L,
|
||||
Focusable = 0x400L,
|
||||
Focused = 0x800L,
|
||||
HasToolTip = 0x1000L,
|
||||
Horizontal = 0x2000L,
|
||||
Iconified = 0x4000L,
|
||||
Modal = 0x8000L,
|
||||
MultiLine = 0x10000L,
|
||||
MultiSelectable = 0x20000L,
|
||||
Opaque = 0x40000L,
|
||||
Pressed = 0x80000L,
|
||||
Resizable = 0x100000L,
|
||||
Selectable = 0x200000L,
|
||||
Selected = 0x400000L,
|
||||
Sensitive = 0x800000L,
|
||||
Showing = 0x1000000L,
|
||||
SingleLine = 0x2000000L,
|
||||
Stale = 0x4000000L,
|
||||
Transient = 0x8000000L,
|
||||
Vertical = 0x10000000L,
|
||||
Visible = 0x20000000L,
|
||||
ManagesDescendants = 0x40000000L,
|
||||
Indeterminate = 0x80000000L,
|
||||
Required = 0x100000000L,
|
||||
Truncated = 0x200000000L,
|
||||
Animated = 0x400000000L,
|
||||
InvalidEntry = 0x800000000L,
|
||||
SupportsAutocompletion = 0x1000000000L,
|
||||
SelectableText = 0x2000000000L,
|
||||
IsDefault = 0x4000000000L,
|
||||
Visited = 0x8000000000L,
|
||||
ReadOnly = 0x10000000000L
|
||||
}
|
||||
10
Services/AnnouncementPriority.cs
Normal file
10
Services/AnnouncementPriority.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AnnouncementPriority
|
||||
{
|
||||
Polite,
|
||||
Assertive
|
||||
}
|
||||
@@ -134,10 +134,6 @@ public class AppActionsService : IAppActions
|
||||
}
|
||||
|
||||
content.AppendLine($"Exec={execPath} --action={action.Id}");
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
content.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,74 +388,3 @@ public class AtSpi2AccessibilityService : IAccessibilityService, IDisposable
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating accessibility service instances.
|
||||
/// </summary>
|
||||
public static class AccessibilityServiceFactory
|
||||
{
|
||||
private static IAccessibilityService? _instance;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton accessibility service instance.
|
||||
/// </summary>
|
||||
public static IAccessibilityService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance ??= CreateService();
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static IAccessibilityService CreateService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new AtSpi2AccessibilityService();
|
||||
service.Initialize();
|
||||
return service;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"AccessibilityServiceFactory: Failed to create AT-SPI2 service - {ex.Message}");
|
||||
return new NullAccessibilityService();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the singleton instance.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance?.Shutdown();
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Null implementation of accessibility service.
|
||||
/// </summary>
|
||||
public class NullAccessibilityService : IAccessibilityService
|
||||
{
|
||||
public bool IsEnabled => false;
|
||||
|
||||
public void Initialize() { }
|
||||
public void Register(IAccessible accessible) { }
|
||||
public void Unregister(IAccessible accessible) { }
|
||||
public void NotifyFocusChanged(IAccessible? accessible) { }
|
||||
public void NotifyPropertyChanged(IAccessible accessible, AccessibleProperty property) { }
|
||||
public void NotifyStateChanged(IAccessible accessible, AccessibleState state, bool value) { }
|
||||
public void Announce(string text, AnnouncementPriority priority = AnnouncementPriority.Polite) { }
|
||||
public void Shutdown() { }
|
||||
}
|
||||
|
||||
13
Services/ColorDialogResult.cs
Normal file
13
Services/ColorDialogResult.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class ColorDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public float Red { get; init; }
|
||||
public float Green { get; init; }
|
||||
public float Blue { get; init; }
|
||||
public float Alpha { get; init; }
|
||||
}
|
||||
16
Services/DesktopEnvironment.cs
Normal file
16
Services/DesktopEnvironment.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DesktopEnvironment
|
||||
{
|
||||
Unknown,
|
||||
GNOME,
|
||||
KDE,
|
||||
XFCE,
|
||||
MATE,
|
||||
Cinnamon,
|
||||
LXQt,
|
||||
LXDE
|
||||
}
|
||||
@@ -7,20 +7,6 @@ using Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Supported display server types.
|
||||
/// </summary>
|
||||
public enum DisplayServerType
|
||||
{
|
||||
Auto,
|
||||
X11,
|
||||
Wayland
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating display server connections.
|
||||
/// Supports X11 and Wayland display servers.
|
||||
/// </summary>
|
||||
public static class DisplayServerFactory
|
||||
{
|
||||
private static DisplayServerType? _cachedServerType;
|
||||
@@ -139,136 +125,3 @@ public static class DisplayServerFactory
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common interface for display server windows.
|
||||
/// </summary>
|
||||
public interface IDisplayWindow : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
bool IsRunning { get; }
|
||||
void Show();
|
||||
void Hide();
|
||||
void SetTitle(string title);
|
||||
void Resize(int width, int height);
|
||||
void ProcessEvents();
|
||||
void Stop();
|
||||
event EventHandler<KeyEventArgs>? KeyDown;
|
||||
event EventHandler<KeyEventArgs>? KeyUp;
|
||||
event EventHandler<TextInputEventArgs>? TextInput;
|
||||
event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
event EventHandler<ScrollEventArgs>? Scroll;
|
||||
event EventHandler? Exposed;
|
||||
event EventHandler<(int Width, int Height)>? Resized;
|
||||
event EventHandler? CloseRequested;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// X11 display window wrapper implementing the common interface.
|
||||
/// </summary>
|
||||
public class X11DisplayWindow : IDisplayWindow
|
||||
{
|
||||
private readonly X11Window _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
public int Height => _window.Height;
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public X11DisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new X11Window(title, width, height);
|
||||
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
public void Hide() => _window.Hide();
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
public void Stop() => _window.Stop();
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wayland display window wrapper implementing IDisplayWindow.
|
||||
/// Uses the full WaylandWindow implementation with xdg-shell protocol.
|
||||
/// </summary>
|
||||
public class WaylandDisplayWindow : IDisplayWindow
|
||||
{
|
||||
private readonly WaylandWindow _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
public int Height => _window.Height;
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel data pointer for rendering.
|
||||
/// </summary>
|
||||
public IntPtr PixelData => _window.PixelData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stride (bytes per row) of the pixel buffer.
|
||||
/// </summary>
|
||||
public int Stride => _window.Stride;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public WaylandDisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new WaylandWindow(title, width, height);
|
||||
|
||||
// Wire up events
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
public void Hide() => _window.Hide();
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
public void Stop() => _window.Stop();
|
||||
public void CommitFrame() => _window.CommitFrame();
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
|
||||
11
Services/DisplayServerType.cs
Normal file
11
Services/DisplayServerType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DisplayServerType
|
||||
{
|
||||
Auto,
|
||||
X11,
|
||||
Wayland
|
||||
}
|
||||
12
Services/DragAction.cs
Normal file
12
Services/DragAction.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DragAction
|
||||
{
|
||||
None,
|
||||
Copy,
|
||||
Move,
|
||||
Link
|
||||
}
|
||||
13
Services/DragData.cs
Normal file
13
Services/DragData.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DragData
|
||||
{
|
||||
public nint SourceWindow { get; set; }
|
||||
public nint[] SupportedTypes { get; set; } = [];
|
||||
public string? Text { get; set; }
|
||||
public string[]? FilePaths { get; set; }
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
@@ -402,115 +402,3 @@ public class DragDropService : IDisposable
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains data for a drag operation.
|
||||
/// </summary>
|
||||
public class DragData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the source window.
|
||||
/// </summary>
|
||||
public nint SourceWindow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the supported MIME types.
|
||||
/// </summary>
|
||||
public nint[] SupportedTypes { get; set; } = Array.Empty<nint>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text data.
|
||||
/// </summary>
|
||||
public string? Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file paths.
|
||||
/// </summary>
|
||||
public string[]? FilePaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets custom data.
|
||||
/// </summary>
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for drag events.
|
||||
/// </summary>
|
||||
public class DragEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the drag data.
|
||||
/// </summary>
|
||||
public DragData Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X coordinate.
|
||||
/// </summary>
|
||||
public int X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y coordinate.
|
||||
/// </summary>
|
||||
public int Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the drop is accepted.
|
||||
/// </summary>
|
||||
public bool Accepted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the allowed action.
|
||||
/// </summary>
|
||||
public DragAction AllowedAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the accepted action.
|
||||
/// </summary>
|
||||
public DragAction AcceptedAction { get; set; } = DragAction.Copy;
|
||||
|
||||
public DragEventArgs(DragData data, int x, int y)
|
||||
{
|
||||
Data = data;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for drop events.
|
||||
/// </summary>
|
||||
public class DropEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the drag data.
|
||||
/// </summary>
|
||||
public DragData Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dropped data as string.
|
||||
/// </summary>
|
||||
public string? DroppedData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the drop was handled.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
public DropEventArgs(DragData data, string? droppedData)
|
||||
{
|
||||
Data = data;
|
||||
DroppedData = droppedData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drag action types.
|
||||
/// </summary>
|
||||
public enum DragAction
|
||||
{
|
||||
None,
|
||||
Copy,
|
||||
Move,
|
||||
Link
|
||||
}
|
||||
|
||||
21
Services/DragEventArgs.cs
Normal file
21
Services/DragEventArgs.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DragEventArgs : EventArgs
|
||||
{
|
||||
public DragData Data { get; }
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public bool Accepted { get; set; }
|
||||
public DragAction AllowedAction { get; set; }
|
||||
public DragAction AcceptedAction { get; set; } = DragAction.Copy;
|
||||
|
||||
public DragEventArgs(DragData data, int x, int y)
|
||||
{
|
||||
Data = data;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
17
Services/DropEventArgs.cs
Normal file
17
Services/DropEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DropEventArgs : EventArgs
|
||||
{
|
||||
public DragData Data { get; }
|
||||
public string? DroppedData { get; }
|
||||
public bool Handled { get; set; }
|
||||
|
||||
public DropEventArgs(DragData data, string? droppedData)
|
||||
{
|
||||
Data = data;
|
||||
DroppedData = droppedData;
|
||||
}
|
||||
}
|
||||
11
Services/FileDialogResult.cs
Normal file
11
Services/FileDialogResult.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FileDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public string[] SelectedFiles { get; init; } = [];
|
||||
public string? SelectedFile => SelectedFiles.Length > 0 ? SelectedFiles[0] : null;
|
||||
}
|
||||
@@ -200,13 +200,3 @@ public class FilePickerService : IFilePicker
|
||||
return arg.Replace("\"", "\\\"").Replace("'", "\\'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linux-specific FileResult implementation.
|
||||
/// </summary>
|
||||
internal class LinuxFileResult : FileResult
|
||||
{
|
||||
public LinuxFileResult(string fullPath) : base(fullPath)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
10
Services/FolderPickerOptions.cs
Normal file
10
Services/FolderPickerOptions.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderPickerOptions
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public string? InitialDirectory { get; set; }
|
||||
}
|
||||
15
Services/FolderPickerResult.cs
Normal file
15
Services/FolderPickerResult.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderPickerResult
|
||||
{
|
||||
public FolderResult? Folder { get; }
|
||||
public bool WasSuccessful => Folder != null;
|
||||
|
||||
public FolderPickerResult(FolderResult? folder)
|
||||
{
|
||||
Folder = folder;
|
||||
}
|
||||
}
|
||||
15
Services/FolderResult.cs
Normal file
15
Services/FolderResult.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderResult
|
||||
{
|
||||
public string Path { get; }
|
||||
public string Name => System.IO.Path.GetFileName(Path) ?? Path;
|
||||
|
||||
public FolderResult(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
@@ -256,37 +256,6 @@ public class FontFallbackManager
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a run of text with a specific typeface.
|
||||
/// </summary>
|
||||
public class TextRun
|
||||
{
|
||||
/// <summary>
|
||||
/// The text content of this run.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The typeface to use for this run.
|
||||
/// </summary>
|
||||
public SKTypeface Typeface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting character index in the original string.
|
||||
/// </summary>
|
||||
public int StartIndex { get; }
|
||||
|
||||
public TextRun(string text, SKTypeface typeface, int startIndex)
|
||||
{
|
||||
Text = text;
|
||||
Typeface = typeface;
|
||||
StartIndex = startIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StringBuilder for internal use.
|
||||
/// </summary>
|
||||
file class StringBuilder
|
||||
{
|
||||
private readonly List<char> _chars = new();
|
||||
|
||||
@@ -296,98 +296,3 @@ public class GlobalHotkeyService : IDisposable
|
||||
public HotkeyModifiers ModifierKeys { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for hotkey pressed events.
|
||||
/// </summary>
|
||||
public class HotkeyEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the registration ID.
|
||||
/// </summary>
|
||||
public int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key.
|
||||
/// </summary>
|
||||
public HotkeyKey Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the modifier keys.
|
||||
/// </summary>
|
||||
public HotkeyModifiers Modifiers { get; }
|
||||
|
||||
public HotkeyEventArgs(int id, HotkeyKey key, HotkeyModifiers modifiers)
|
||||
{
|
||||
Id = id;
|
||||
Key = key;
|
||||
Modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hotkey modifier keys.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum HotkeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1 << 0,
|
||||
Control = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
Super = 1 << 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hotkey keys (X11 keysyms).
|
||||
/// </summary>
|
||||
public enum HotkeyKey : uint
|
||||
{
|
||||
// Letters
|
||||
A = 0x61, B = 0x62, C = 0x63, D = 0x64, E = 0x65,
|
||||
F = 0x66, G = 0x67, H = 0x68, I = 0x69, J = 0x6A,
|
||||
K = 0x6B, L = 0x6C, M = 0x6D, N = 0x6E, O = 0x6F,
|
||||
P = 0x70, Q = 0x71, R = 0x72, S = 0x73, T = 0x74,
|
||||
U = 0x75, V = 0x76, W = 0x77, X = 0x78, Y = 0x79,
|
||||
Z = 0x7A,
|
||||
|
||||
// Numbers
|
||||
D0 = 0x30, D1 = 0x31, D2 = 0x32, D3 = 0x33, D4 = 0x34,
|
||||
D5 = 0x35, D6 = 0x36, D7 = 0x37, D8 = 0x38, D9 = 0x39,
|
||||
|
||||
// Function keys
|
||||
F1 = 0xFFBE, F2 = 0xFFBF, F3 = 0xFFC0, F4 = 0xFFC1,
|
||||
F5 = 0xFFC2, F6 = 0xFFC3, F7 = 0xFFC4, F8 = 0xFFC5,
|
||||
F9 = 0xFFC6, F10 = 0xFFC7, F11 = 0xFFC8, F12 = 0xFFC9,
|
||||
|
||||
// Special keys
|
||||
Escape = 0xFF1B,
|
||||
Tab = 0xFF09,
|
||||
Return = 0xFF0D,
|
||||
Space = 0x20,
|
||||
BackSpace = 0xFF08,
|
||||
Delete = 0xFFFF,
|
||||
Insert = 0xFF63,
|
||||
Home = 0xFF50,
|
||||
End = 0xFF57,
|
||||
PageUp = 0xFF55,
|
||||
PageDown = 0xFF56,
|
||||
|
||||
// Arrow keys
|
||||
Left = 0xFF51,
|
||||
Up = 0xFF52,
|
||||
Right = 0xFF53,
|
||||
Down = 0xFF54,
|
||||
|
||||
// Media keys
|
||||
AudioPlay = 0x1008FF14,
|
||||
AudioStop = 0x1008FF15,
|
||||
AudioPrev = 0x1008FF16,
|
||||
AudioNext = 0x1008FF17,
|
||||
AudioMute = 0x1008FF12,
|
||||
AudioRaiseVolume = 0x1008FF13,
|
||||
AudioLowerVolume = 0x1008FF11,
|
||||
|
||||
// Print screen
|
||||
Print = 0xFF61
|
||||
}
|
||||
|
||||
@@ -5,86 +5,6 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 dialog response codes.
|
||||
/// </summary>
|
||||
public enum GtkResponseType
|
||||
{
|
||||
None = -1,
|
||||
Reject = -2,
|
||||
Accept = -3,
|
||||
DeleteEvent = -4,
|
||||
Ok = -5,
|
||||
Cancel = -6,
|
||||
Close = -7,
|
||||
Yes = -8,
|
||||
No = -9,
|
||||
Apply = -10,
|
||||
Help = -11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 message dialog types.
|
||||
/// </summary>
|
||||
public enum GtkMessageType
|
||||
{
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Question = 2,
|
||||
Error = 3,
|
||||
Other = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 button layouts for dialogs.
|
||||
/// </summary>
|
||||
public enum GtkButtonsType
|
||||
{
|
||||
None = 0,
|
||||
Ok = 1,
|
||||
Close = 2,
|
||||
Cancel = 3,
|
||||
YesNo = 4,
|
||||
OkCancel = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 file chooser actions.
|
||||
/// </summary>
|
||||
public enum GtkFileChooserAction
|
||||
{
|
||||
Open = 0,
|
||||
Save = 1,
|
||||
SelectFolder = 2,
|
||||
CreateFolder = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result from a file dialog.
|
||||
/// </summary>
|
||||
public class FileDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public string[] SelectedFiles { get; init; } = Array.Empty<string>();
|
||||
public string? SelectedFile => SelectedFiles.Length > 0 ? SelectedFiles[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result from a color dialog.
|
||||
/// </summary>
|
||||
public class ColorDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public float Red { get; init; }
|
||||
public float Green { get; init; }
|
||||
public float Blue { get; init; }
|
||||
public float Alpha { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 interop layer for native Linux dialogs.
|
||||
/// Provides native file pickers, message boxes, and color choosers.
|
||||
/// </summary>
|
||||
public class Gtk4InteropService : IDisposable
|
||||
{
|
||||
#region GTK4 Native Interop
|
||||
|
||||
14
Services/GtkButtonsType.cs
Normal file
14
Services/GtkButtonsType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkButtonsType
|
||||
{
|
||||
None,
|
||||
Ok,
|
||||
Close,
|
||||
Cancel,
|
||||
YesNo,
|
||||
OkCancel
|
||||
}
|
||||
12
Services/GtkFileChooserAction.cs
Normal file
12
Services/GtkFileChooserAction.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkFileChooserAction
|
||||
{
|
||||
Open,
|
||||
Save,
|
||||
SelectFolder,
|
||||
CreateFolder
|
||||
}
|
||||
13
Services/GtkMessageType.cs
Normal file
13
Services/GtkMessageType.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkMessageType
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Question,
|
||||
Error,
|
||||
Other
|
||||
}
|
||||
19
Services/GtkResponseType.cs
Normal file
19
Services/GtkResponseType.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkResponseType
|
||||
{
|
||||
None = -1,
|
||||
Reject = -2,
|
||||
Accept = -3,
|
||||
DeleteEvent = -4,
|
||||
Ok = -5,
|
||||
Cancel = -6,
|
||||
Close = -7,
|
||||
Yes = -8,
|
||||
No = -9,
|
||||
Apply = -10,
|
||||
Help = -11
|
||||
}
|
||||
@@ -6,83 +6,6 @@ using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Supported hardware video acceleration APIs.
|
||||
/// </summary>
|
||||
public enum VideoAccelerationApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically select the best available API.
|
||||
/// </summary>
|
||||
Auto,
|
||||
|
||||
/// <summary>
|
||||
/// VA-API (Video Acceleration API) - Intel, AMD, and some NVIDIA.
|
||||
/// </summary>
|
||||
VaApi,
|
||||
|
||||
/// <summary>
|
||||
/// VDPAU (Video Decode and Presentation API for Unix) - NVIDIA.
|
||||
/// </summary>
|
||||
Vdpau,
|
||||
|
||||
/// <summary>
|
||||
/// Software decoding fallback.
|
||||
/// </summary>
|
||||
Software
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Video codec profiles supported by hardware acceleration.
|
||||
/// </summary>
|
||||
public enum VideoProfile
|
||||
{
|
||||
H264Baseline,
|
||||
H264Main,
|
||||
H264High,
|
||||
H265Main,
|
||||
H265Main10,
|
||||
Vp8,
|
||||
Vp9Profile0,
|
||||
Vp9Profile2,
|
||||
Av1Main
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a decoded video frame.
|
||||
/// </summary>
|
||||
public class VideoFrame : IDisposable
|
||||
{
|
||||
public int Width { get; init; }
|
||||
public int Height { get; init; }
|
||||
public IntPtr DataY { get; init; }
|
||||
public IntPtr DataU { get; init; }
|
||||
public IntPtr DataV { get; init; }
|
||||
public int StrideY { get; init; }
|
||||
public int StrideU { get; init; }
|
||||
public int StrideV { get; init; }
|
||||
public long Timestamp { get; init; }
|
||||
public bool IsKeyFrame { get; init; }
|
||||
|
||||
private bool _disposed;
|
||||
private Action? _releaseCallback;
|
||||
|
||||
internal void SetReleaseCallback(Action callback) => _releaseCallback = callback;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_releaseCallback?.Invoke();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hardware-accelerated video decoding service using VA-API or VDPAU.
|
||||
/// Provides efficient video decode for media playback on Linux.
|
||||
/// </summary>
|
||||
public class HardwareVideoService : IDisposable
|
||||
{
|
||||
#region VA-API Native Interop
|
||||
|
||||
@@ -494,31 +494,3 @@ public class HiDpiService
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for scale change events.
|
||||
/// </summary>
|
||||
public class ScaleChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the old scale factor.
|
||||
/// </summary>
|
||||
public float OldScale { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new scale factor.
|
||||
/// </summary>
|
||||
public float NewScale { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new DPI.
|
||||
/// </summary>
|
||||
public float NewDpi { get; }
|
||||
|
||||
public ScaleChangedEventArgs(float oldScale, float newScale, float newDpi)
|
||||
{
|
||||
OldScale = oldScale;
|
||||
NewScale = newScale;
|
||||
NewDpi = newDpi;
|
||||
}
|
||||
}
|
||||
|
||||
17
Services/HighContrastChangedEventArgs.cs
Normal file
17
Services/HighContrastChangedEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HighContrastChangedEventArgs : EventArgs
|
||||
{
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
public HighContrastTheme Theme { get; }
|
||||
|
||||
public HighContrastChangedEventArgs(bool isEnabled, HighContrastTheme theme)
|
||||
{
|
||||
IsEnabled = isEnabled;
|
||||
Theme = theme;
|
||||
}
|
||||
}
|
||||
35
Services/HighContrastColors.cs
Normal file
35
Services/HighContrastColors.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HighContrastColors
|
||||
{
|
||||
public SKColor Background { get; set; }
|
||||
|
||||
public SKColor Foreground { get; set; }
|
||||
|
||||
public SKColor Accent { get; set; }
|
||||
|
||||
public SKColor Border { get; set; }
|
||||
|
||||
public SKColor Error { get; set; }
|
||||
|
||||
public SKColor Success { get; set; }
|
||||
|
||||
public SKColor Warning { get; set; }
|
||||
|
||||
public SKColor Link { get; set; }
|
||||
|
||||
public SKColor LinkVisited { get; set; }
|
||||
|
||||
public SKColor Selection { get; set; }
|
||||
|
||||
public SKColor SelectionText { get; set; }
|
||||
|
||||
public SKColor DisabledText { get; set; }
|
||||
|
||||
public SKColor DisabledBackground { get; set; }
|
||||
}
|
||||
@@ -348,55 +348,3 @@ public class HighContrastService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// High contrast theme types.
|
||||
/// </summary>
|
||||
public enum HighContrastTheme
|
||||
{
|
||||
None,
|
||||
WhiteOnBlack,
|
||||
BlackOnWhite
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color palette for high contrast mode.
|
||||
/// </summary>
|
||||
public class HighContrastColors
|
||||
{
|
||||
public SKColor Background { get; set; }
|
||||
public SKColor Foreground { get; set; }
|
||||
public SKColor Accent { get; set; }
|
||||
public SKColor Border { get; set; }
|
||||
public SKColor Error { get; set; }
|
||||
public SKColor Success { get; set; }
|
||||
public SKColor Warning { get; set; }
|
||||
public SKColor Link { get; set; }
|
||||
public SKColor LinkVisited { get; set; }
|
||||
public SKColor Selection { get; set; }
|
||||
public SKColor SelectionText { get; set; }
|
||||
public SKColor DisabledText { get; set; }
|
||||
public SKColor DisabledBackground { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for high contrast mode changes.
|
||||
/// </summary>
|
||||
public class HighContrastChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether high contrast mode is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current theme.
|
||||
/// </summary>
|
||||
public HighContrastTheme Theme { get; }
|
||||
|
||||
public HighContrastChangedEventArgs(bool isEnabled, HighContrastTheme theme)
|
||||
{
|
||||
IsEnabled = isEnabled;
|
||||
Theme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
11
Services/HighContrastTheme.cs
Normal file
11
Services/HighContrastTheme.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum HighContrastTheme
|
||||
{
|
||||
None,
|
||||
WhiteOnBlack,
|
||||
BlackOnWhite
|
||||
}
|
||||
18
Services/HotkeyEventArgs.cs
Normal file
18
Services/HotkeyEventArgs.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HotkeyEventArgs : EventArgs
|
||||
{
|
||||
public int Id { get; }
|
||||
public HotkeyKey Key { get; }
|
||||
public HotkeyModifiers Modifiers { get; }
|
||||
|
||||
public HotkeyEventArgs(int id, HotkeyKey key, HotkeyModifiers modifiers)
|
||||
{
|
||||
Id = id;
|
||||
Key = key;
|
||||
Modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
17
Services/HotkeyKey.cs
Normal file
17
Services/HotkeyKey.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum HotkeyKey
|
||||
{
|
||||
None,
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9,
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
Space, Enter, Escape, Tab, Backspace, Delete, Insert,
|
||||
Home, End, PageUp, PageDown,
|
||||
Left, Right, Up, Down,
|
||||
PrintScreen, Pause, NumLock, ScrollLock, CapsLock
|
||||
}
|
||||
14
Services/HotkeyModifiers.cs
Normal file
14
Services/HotkeyModifiers.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum HotkeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Alt = 1,
|
||||
Control = 2,
|
||||
Shift = 4,
|
||||
Super = 8
|
||||
}
|
||||
@@ -64,373 +64,3 @@ public interface IAccessibilityService
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for accessible objects.
|
||||
/// </summary>
|
||||
public interface IAccessible
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for this accessible.
|
||||
/// </summary>
|
||||
string AccessibleId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible name (label for screen readers).
|
||||
/// </summary>
|
||||
string AccessibleName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible description (additional context).
|
||||
/// </summary>
|
||||
string AccessibleDescription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible role.
|
||||
/// </summary>
|
||||
AccessibleRole Role { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible states.
|
||||
/// </summary>
|
||||
AccessibleStates States { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent accessible.
|
||||
/// </summary>
|
||||
IAccessible? Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child accessibles.
|
||||
/// </summary>
|
||||
IReadOnlyList<IAccessible> Children { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding rectangle in screen coordinates.
|
||||
/// </summary>
|
||||
AccessibleRect Bounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the available actions.
|
||||
/// </summary>
|
||||
IReadOnlyList<AccessibleAction> Actions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs an action.
|
||||
/// </summary>
|
||||
/// <param name="actionName">The name of the action to perform.</param>
|
||||
/// <returns>True if the action was performed.</returns>
|
||||
bool DoAction(string actionName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible value (for sliders, progress bars, etc.).
|
||||
/// </summary>
|
||||
double? Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum value.
|
||||
/// </summary>
|
||||
double? MinValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum value.
|
||||
/// </summary>
|
||||
double? MaxValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the accessible value.
|
||||
/// </summary>
|
||||
bool SetValue(double value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for accessible text components.
|
||||
/// </summary>
|
||||
public interface IAccessibleText : IAccessible
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text content.
|
||||
/// </summary>
|
||||
string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the caret offset.
|
||||
/// </summary>
|
||||
int CaretOffset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of selections.
|
||||
/// </summary>
|
||||
int SelectionCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection at the specified index.
|
||||
/// </summary>
|
||||
(int Start, int End) GetSelection(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the selection.
|
||||
/// </summary>
|
||||
bool SetSelection(int index, int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character at the specified offset.
|
||||
/// </summary>
|
||||
char GetCharacterAtOffset(int offset);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text in the specified range.
|
||||
/// </summary>
|
||||
string GetTextInRange(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the character at the specified offset.
|
||||
/// </summary>
|
||||
AccessibleRect GetCharacterBounds(int offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for editable text components.
|
||||
/// </summary>
|
||||
public interface IAccessibleEditableText : IAccessibleText
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the text content.
|
||||
/// </summary>
|
||||
bool SetText(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Inserts text at the specified position.
|
||||
/// </summary>
|
||||
bool InsertText(int position, string text);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes text in the specified range.
|
||||
/// </summary>
|
||||
bool DeleteText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Copies text to clipboard.
|
||||
/// </summary>
|
||||
bool CopyText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Cuts text to clipboard.
|
||||
/// </summary>
|
||||
bool CutText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Pastes text from clipboard.
|
||||
/// </summary>
|
||||
bool PasteText(int position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible roles (based on AT-SPI2 roles).
|
||||
/// </summary>
|
||||
public enum AccessibleRole
|
||||
{
|
||||
Unknown,
|
||||
Window,
|
||||
Application,
|
||||
Panel,
|
||||
Frame,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
ComboBox,
|
||||
Entry,
|
||||
Label,
|
||||
List,
|
||||
ListItem,
|
||||
Menu,
|
||||
MenuBar,
|
||||
MenuItem,
|
||||
ScrollBar,
|
||||
Slider,
|
||||
SpinButton,
|
||||
StatusBar,
|
||||
Tab,
|
||||
TabPanel,
|
||||
Text,
|
||||
ToggleButton,
|
||||
ToolBar,
|
||||
ToolTip,
|
||||
Tree,
|
||||
TreeItem,
|
||||
Image,
|
||||
ProgressBar,
|
||||
Separator,
|
||||
Link,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TableColumnHeader,
|
||||
TableRowHeader,
|
||||
PageTab,
|
||||
PageTabList,
|
||||
Dialog,
|
||||
Alert,
|
||||
Filler,
|
||||
Icon,
|
||||
Canvas
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible states.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum AccessibleStates : long
|
||||
{
|
||||
None = 0,
|
||||
Active = 1L << 0,
|
||||
Armed = 1L << 1,
|
||||
Busy = 1L << 2,
|
||||
Checked = 1L << 3,
|
||||
Collapsed = 1L << 4,
|
||||
Defunct = 1L << 5,
|
||||
Editable = 1L << 6,
|
||||
Enabled = 1L << 7,
|
||||
Expandable = 1L << 8,
|
||||
Expanded = 1L << 9,
|
||||
Focusable = 1L << 10,
|
||||
Focused = 1L << 11,
|
||||
HasToolTip = 1L << 12,
|
||||
Horizontal = 1L << 13,
|
||||
Iconified = 1L << 14,
|
||||
Modal = 1L << 15,
|
||||
MultiLine = 1L << 16,
|
||||
MultiSelectable = 1L << 17,
|
||||
Opaque = 1L << 18,
|
||||
Pressed = 1L << 19,
|
||||
Resizable = 1L << 20,
|
||||
Selectable = 1L << 21,
|
||||
Selected = 1L << 22,
|
||||
Sensitive = 1L << 23,
|
||||
Showing = 1L << 24,
|
||||
SingleLine = 1L << 25,
|
||||
Stale = 1L << 26,
|
||||
Transient = 1L << 27,
|
||||
Vertical = 1L << 28,
|
||||
Visible = 1L << 29,
|
||||
ManagesDescendants = 1L << 30,
|
||||
Indeterminate = 1L << 31,
|
||||
Required = 1L << 32,
|
||||
Truncated = 1L << 33,
|
||||
Animated = 1L << 34,
|
||||
InvalidEntry = 1L << 35,
|
||||
SupportsAutocompletion = 1L << 36,
|
||||
SelectableText = 1L << 37,
|
||||
IsDefault = 1L << 38,
|
||||
Visited = 1L << 39,
|
||||
ReadOnly = 1L << 40
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible state enumeration for notifications.
|
||||
/// </summary>
|
||||
public enum AccessibleState
|
||||
{
|
||||
Active,
|
||||
Armed,
|
||||
Busy,
|
||||
Checked,
|
||||
Collapsed,
|
||||
Defunct,
|
||||
Editable,
|
||||
Enabled,
|
||||
Expandable,
|
||||
Expanded,
|
||||
Focusable,
|
||||
Focused,
|
||||
Horizontal,
|
||||
Iconified,
|
||||
Modal,
|
||||
MultiLine,
|
||||
Opaque,
|
||||
Pressed,
|
||||
Resizable,
|
||||
Selectable,
|
||||
Selected,
|
||||
Sensitive,
|
||||
Showing,
|
||||
SingleLine,
|
||||
Stale,
|
||||
Transient,
|
||||
Vertical,
|
||||
Visible,
|
||||
ManagesDescendants,
|
||||
Indeterminate,
|
||||
Required,
|
||||
InvalidEntry,
|
||||
ReadOnly
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible property for notifications.
|
||||
/// </summary>
|
||||
public enum AccessibleProperty
|
||||
{
|
||||
Name,
|
||||
Description,
|
||||
Role,
|
||||
Value,
|
||||
Parent,
|
||||
Children
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Announcement priority.
|
||||
/// </summary>
|
||||
public enum AnnouncementPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// Low priority - can be interrupted.
|
||||
/// </summary>
|
||||
Polite,
|
||||
|
||||
/// <summary>
|
||||
/// High priority - interrupts current speech.
|
||||
/// </summary>
|
||||
Assertive
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an accessible action.
|
||||
/// </summary>
|
||||
public class AccessibleAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The action name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The action description.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The keyboard shortcut for this action.
|
||||
/// </summary>
|
||||
public string? KeyBinding { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a rectangle in accessible coordinates.
|
||||
/// </summary>
|
||||
public struct AccessibleRect
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
public AccessibleRect(int x, int y, int width, int height)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
23
Services/IAccessible.cs
Normal file
23
Services/IAccessible.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessible
|
||||
{
|
||||
string AccessibleId { get; }
|
||||
string AccessibleName { get; }
|
||||
string AccessibleDescription { get; }
|
||||
AccessibleRole Role { get; }
|
||||
AccessibleStates States { get; }
|
||||
IAccessible? Parent { get; }
|
||||
IReadOnlyList<IAccessible> Children { get; }
|
||||
AccessibleRect Bounds { get; }
|
||||
IReadOnlyList<AccessibleAction> Actions { get; }
|
||||
double? Value { get; }
|
||||
double? MinValue { get; }
|
||||
double? MaxValue { get; }
|
||||
|
||||
bool DoAction(string actionName);
|
||||
bool SetValue(double value);
|
||||
}
|
||||
19
Services/IAccessibleEditableText.cs
Normal file
19
Services/IAccessibleEditableText.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessibleEditableText : IAccessibleText, IAccessible
|
||||
{
|
||||
bool SetText(string text);
|
||||
|
||||
bool InsertText(int position, string text);
|
||||
|
||||
bool DeleteText(int start, int end);
|
||||
|
||||
bool CopyText(int start, int end);
|
||||
|
||||
bool CutText(int start, int end);
|
||||
|
||||
bool PasteText(int position);
|
||||
}
|
||||
23
Services/IAccessibleText.cs
Normal file
23
Services/IAccessibleText.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessibleText : IAccessible
|
||||
{
|
||||
string Text { get; }
|
||||
|
||||
int CaretOffset { get; }
|
||||
|
||||
int SelectionCount { get; }
|
||||
|
||||
(int Start, int End) GetSelection(int index);
|
||||
|
||||
bool SetSelection(int index, int start, int end);
|
||||
|
||||
char GetCharacterAtOffset(int offset);
|
||||
|
||||
string GetTextInRange(int start, int end);
|
||||
|
||||
AccessibleRect GetCharacterBounds(int offset);
|
||||
}
|
||||
45
Services/IDisplayWindow.cs
Normal file
45
Services/IDisplayWindow.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IDisplayWindow : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
|
||||
int Height { get; }
|
||||
|
||||
bool IsRunning { get; }
|
||||
|
||||
event EventHandler<KeyEventArgs>? KeyDown;
|
||||
|
||||
event EventHandler<KeyEventArgs>? KeyUp;
|
||||
|
||||
event EventHandler<TextInputEventArgs>? TextInput;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
|
||||
event EventHandler<ScrollEventArgs>? Scroll;
|
||||
|
||||
event EventHandler? Exposed;
|
||||
|
||||
event EventHandler<(int Width, int Height)>? Resized;
|
||||
|
||||
event EventHandler? CloseRequested;
|
||||
|
||||
void Show();
|
||||
|
||||
void Hide();
|
||||
|
||||
void SetTitle(string title);
|
||||
|
||||
void Resize(int width, int height);
|
||||
|
||||
void ProcessEvents();
|
||||
|
||||
void Stop();
|
||||
}
|
||||
21
Services/IInputContext.cs
Normal file
21
Services/IInputContext.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IInputContext
|
||||
{
|
||||
string Text { get; set; }
|
||||
|
||||
int CursorPosition { get; set; }
|
||||
|
||||
int SelectionStart { get; }
|
||||
|
||||
int SelectionLength { get; }
|
||||
|
||||
void OnTextCommitted(string text);
|
||||
|
||||
void OnPreEditChanged(string preEditText, int cursorPosition);
|
||||
|
||||
void OnPreEditEnded();
|
||||
}
|
||||
@@ -79,153 +79,3 @@ public interface IInputMethodService
|
||||
/// </summary>
|
||||
event EventHandler? PreEditEnded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an input context that can receive IME input.
|
||||
/// </summary>
|
||||
public interface IInputContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current text content.
|
||||
/// </summary>
|
||||
string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cursor position.
|
||||
/// </summary>
|
||||
int CursorPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection start position.
|
||||
/// </summary>
|
||||
int SelectionStart { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection length.
|
||||
/// </summary>
|
||||
int SelectionLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when text is committed from the IME.
|
||||
/// </summary>
|
||||
/// <param name="text">The committed text.</param>
|
||||
void OnTextCommitted(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Called when pre-edit text changes.
|
||||
/// </summary>
|
||||
/// <param name="preEditText">The current pre-edit text.</param>
|
||||
/// <param name="cursorPosition">Cursor position within pre-edit text.</param>
|
||||
void OnPreEditChanged(string preEditText, int cursorPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Called when pre-edit mode ends.
|
||||
/// </summary>
|
||||
void OnPreEditEnded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for text committed events.
|
||||
/// </summary>
|
||||
public class TextCommittedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The committed text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
public TextCommittedEventArgs(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for pre-edit changed events.
|
||||
/// </summary>
|
||||
public class PreEditChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The current pre-edit text.
|
||||
/// </summary>
|
||||
public string PreEditText { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cursor position within the pre-edit text.
|
||||
/// </summary>
|
||||
public int CursorPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Formatting attributes for the pre-edit text.
|
||||
/// </summary>
|
||||
public IReadOnlyList<PreEditAttribute> Attributes { get; }
|
||||
|
||||
public PreEditChangedEventArgs(string preEditText, int cursorPosition, IReadOnlyList<PreEditAttribute>? attributes = null)
|
||||
{
|
||||
PreEditText = preEditText;
|
||||
CursorPosition = cursorPosition;
|
||||
Attributes = attributes ?? Array.Empty<PreEditAttribute>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents formatting for a portion of pre-edit text.
|
||||
/// </summary>
|
||||
public class PreEditAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Start position in the pre-edit text.
|
||||
/// </summary>
|
||||
public int Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the attributed range.
|
||||
/// </summary>
|
||||
public int Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The attribute type.
|
||||
/// </summary>
|
||||
public PreEditAttributeType Type { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of pre-edit text attributes.
|
||||
/// </summary>
|
||||
public enum PreEditAttributeType
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal text (no special formatting).
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Underlined text (typical for composition).
|
||||
/// </summary>
|
||||
Underline,
|
||||
|
||||
/// <summary>
|
||||
/// Highlighted/selected text.
|
||||
/// </summary>
|
||||
Highlighted,
|
||||
|
||||
/// <summary>
|
||||
/// Reverse video (selected clause in some IMEs).
|
||||
/// </summary>
|
||||
Reverse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key modifiers for IME processing.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum KeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1 << 0,
|
||||
Control = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
Super = 1 << 3,
|
||||
CapsLock = 1 << 4,
|
||||
NumLock = 1 << 5
|
||||
}
|
||||
|
||||
@@ -180,24 +180,3 @@ public static class InputMethodServiceFactory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Null implementation of IInputMethodService for when no IME is available.
|
||||
/// </summary>
|
||||
public class NullInputMethodService : IInputMethodService
|
||||
{
|
||||
public bool IsActive => false;
|
||||
public string PreEditText => string.Empty;
|
||||
public int PreEditCursorPosition => 0;
|
||||
|
||||
public event EventHandler<TextCommittedEventArgs>? TextCommitted;
|
||||
public event EventHandler<PreEditChangedEventArgs>? PreEditChanged;
|
||||
public event EventHandler? PreEditEnded;
|
||||
|
||||
public void Initialize(nint windowHandle) { }
|
||||
public void SetFocus(IInputContext? context) { }
|
||||
public void SetCursorLocation(int x, int y, int width, int height) { }
|
||||
public bool ProcessKeyEvent(uint keyCode, KeyModifiers modifiers, bool isKeyDown) => false;
|
||||
public void Reset() { }
|
||||
public void Shutdown() { }
|
||||
}
|
||||
|
||||
16
Services/KeyModifiers.cs
Normal file
16
Services/KeyModifiers.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum KeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1,
|
||||
Control = 2,
|
||||
Alt = 4,
|
||||
Super = 8,
|
||||
CapsLock = 0x10,
|
||||
NumLock = 0x20
|
||||
}
|
||||
14
Services/LinuxFileResult.cs
Normal file
14
Services/LinuxFileResult.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Storage;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
internal class LinuxFileResult : FileResult
|
||||
{
|
||||
public LinuxFileResult(string fullPath)
|
||||
: base(fullPath)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using SkiaSharp;
|
||||
using Svg.Skia;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Generates application icons from MAUI icon metadata.
|
||||
/// Creates PNG icons suitable for use as window icons on Linux.
|
||||
/// Note: SVG overlay support requires Svg.Skia package (optional).
|
||||
/// Uses SVG overlay support via Svg.Skia package.
|
||||
/// </summary>
|
||||
public static class MauiIconGenerator
|
||||
{
|
||||
@@ -28,50 +28,52 @@ public static class MauiIconGenerator
|
||||
string path = Path.GetDirectoryName(metaFilePath) ?? "";
|
||||
var metadata = ParseMetadata(File.ReadAllText(metaFilePath));
|
||||
|
||||
// bg and fg paths (bg not currently used, but available for future)
|
||||
Path.Combine(path, "appicon_bg.svg");
|
||||
string fgPath = Path.Combine(path, "appicon_fg.svg");
|
||||
string outputPath = Path.Combine(path, "appicon.png");
|
||||
|
||||
// Parse size from metadata or use default
|
||||
int size = metadata.TryGetValue("Size", out var sizeStr) && int.TryParse(sizeStr, out var sizeVal)
|
||||
? sizeVal
|
||||
: DefaultIconSize;
|
||||
|
||||
// Parse color from metadata or use default purple
|
||||
SKColor color = metadata.TryGetValue("Color", out var colorStr)
|
||||
? ParseColor(colorStr)
|
||||
: SKColors.Purple;
|
||||
|
||||
// Parse scale from metadata or use default 0.65
|
||||
float scale = metadata.TryGetValue("Scale", out var scaleStr) && float.TryParse(scaleStr, out var scaleVal)
|
||||
? scaleVal
|
||||
: 0.65f;
|
||||
|
||||
Console.WriteLine($"[MauiIconGenerator] Generating {size}x{size} icon");
|
||||
Console.WriteLine($"[MauiIconGenerator] Color: {color}");
|
||||
Console.WriteLine($"[MauiIconGenerator] Scale: {scale}");
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(size, size, SKColorType.Bgra8888, SKAlphaType.Premul));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Draw background with rounded corners
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
float cornerRadius = size * 0.2f;
|
||||
using var paint = new SKPaint { Color = color, IsAntialias = true };
|
||||
canvas.DrawRoundRect(new SKRoundRect(new SKRect(0, 0, size, size), cornerRadius), paint);
|
||||
// Fill background with color
|
||||
canvas.Clear(color);
|
||||
|
||||
// Try to load PNG foreground as fallback (appicon_fg.png)
|
||||
string fgPngPath = Path.Combine(path, "appicon_fg.png");
|
||||
if (File.Exists(fgPngPath))
|
||||
// Load and draw SVG foreground if it exists
|
||||
if (File.Exists(fgPath))
|
||||
{
|
||||
try
|
||||
using var svg = new SKSvg();
|
||||
if (svg.Load(fgPath) != null && svg.Picture != null)
|
||||
{
|
||||
using var fgBitmap = SKBitmap.Decode(fgPngPath);
|
||||
if (fgBitmap != null)
|
||||
{
|
||||
float scale = size * 0.65f / Math.Max(fgBitmap.Width, fgBitmap.Height);
|
||||
float fgWidth = fgBitmap.Width * scale;
|
||||
float fgHeight = fgBitmap.Height * scale;
|
||||
float offsetX = (size - fgWidth) / 2f;
|
||||
float offsetY = (size - fgHeight) / 2f;
|
||||
var cullRect = svg.Picture.CullRect;
|
||||
float svgScale = size * scale / Math.Max(cullRect.Width, cullRect.Height);
|
||||
float offsetX = (size - cullRect.Width * svgScale) / 2f;
|
||||
float offsetY = (size - cullRect.Height * svgScale) / 2f;
|
||||
|
||||
var dstRect = new SKRect(offsetX, offsetY, offsetX + fgWidth, offsetY + fgHeight);
|
||||
canvas.DrawBitmap(fgBitmap, dstRect);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("[MauiIconGenerator] Failed to load foreground PNG: " + ex.Message);
|
||||
canvas.Save();
|
||||
canvas.Translate(offsetX, offsetY);
|
||||
canvas.Scale(svgScale);
|
||||
canvas.DrawPicture(svg.Picture);
|
||||
canvas.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
Services/NotificationAction.cs
Normal file
24
Services/NotificationAction.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NotificationAction
|
||||
{
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
public string Label { get; set; } = "";
|
||||
|
||||
public Action? Callback { get; set; }
|
||||
|
||||
public NotificationAction()
|
||||
{
|
||||
}
|
||||
|
||||
public NotificationAction(string key, string label, Action? callback = null)
|
||||
{
|
||||
Key = key;
|
||||
Label = label;
|
||||
Callback = callback;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user