Update with recovered code from VM binaries (Jan 1)

Recovered from decompiled OpenMaui.Controls.Linux.dll:
- SkiaShell.cs: FlyoutHeader, FlyoutFooter, scroll support (918 -> 1325 lines)
- X11Window.cs: Cursor support (XCreateFontCursor, XDefineCursor)
- All handlers with dark mode support
- All services with latest implementations
- LinuxApplication with theme change handling
This commit is contained in:
2026-01-01 06:22:48 -05:00
parent 1e84c6168a
commit 1f096c38dc
254 changed files with 49359 additions and 38457 deletions

View File

@@ -1,232 +1,254 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using SkiaSharp;
namespace Microsoft.Maui.Platform.Linux.Rendering;
/// <summary>
/// Manages dirty rectangles for optimized rendering.
/// Only redraws areas that have been invalidated.
/// </summary>
public class DirtyRectManager
{
private readonly List<SKRect> _dirtyRects = new();
private readonly object _lock = new();
private bool _fullRedrawNeeded = true;
private SKRect _bounds;
private int _maxDirtyRects = 10;
private readonly List<SKRect> _dirtyRects = new List<SKRect>();
/// <summary>
/// Gets or sets the maximum number of dirty rectangles to track before
/// falling back to a full redraw.
/// </summary>
public int MaxDirtyRects
{
get => _maxDirtyRects;
set => _maxDirtyRects = Math.Max(1, value);
}
private readonly object _lock = new object();
/// <summary>
/// Gets whether a full redraw is needed.
/// </summary>
public bool NeedsFullRedraw => _fullRedrawNeeded;
private bool _fullRedrawNeeded = true;
/// <summary>
/// Gets the current dirty rectangles.
/// </summary>
public IReadOnlyList<SKRect> DirtyRects
{
get
{
lock (_lock)
{
return _dirtyRects.ToList();
}
}
}
private SKRect _bounds;
/// <summary>
/// Gets whether there are any dirty regions.
/// </summary>
public bool HasDirtyRegions
{
get
{
lock (_lock)
{
return _fullRedrawNeeded || _dirtyRects.Count > 0;
}
}
}
private int _maxDirtyRects = 10;
/// <summary>
/// Sets the rendering bounds.
/// </summary>
public void SetBounds(SKRect bounds)
{
if (_bounds != bounds)
{
_bounds = bounds;
InvalidateAll();
}
}
public int MaxDirtyRects
{
get
{
return _maxDirtyRects;
}
set
{
_maxDirtyRects = Math.Max(1, value);
}
}
/// <summary>
/// Invalidates a specific region.
/// </summary>
public void Invalidate(SKRect rect)
{
if (rect.IsEmpty) return;
public bool NeedsFullRedraw => _fullRedrawNeeded;
lock (_lock)
{
if (_fullRedrawNeeded) return;
public IReadOnlyList<SKRect> DirtyRects
{
get
{
lock (_lock)
{
return _dirtyRects.ToList();
}
}
}
// Clamp to bounds
rect = SKRect.Intersect(rect, _bounds);
if (rect.IsEmpty) return;
public bool HasDirtyRegions
{
get
{
lock (_lock)
{
return _fullRedrawNeeded || _dirtyRects.Count > 0;
}
}
}
// Try to merge with existing dirty rects
for (int i = 0; i < _dirtyRects.Count; i++)
{
if (_dirtyRects[i].Contains(rect))
{
// Already covered
return;
}
public void SetBounds(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
if (_bounds != bounds)
{
_bounds = bounds;
InvalidateAll();
}
}
if (rect.Contains(_dirtyRects[i]))
{
// New rect covers existing
_dirtyRects[i] = rect;
MergeDirtyRects();
return;
}
public void Invalidate(SKRect rect)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
if (((SKRect)(ref rect)).IsEmpty)
{
return;
}
lock (_lock)
{
if (_fullRedrawNeeded)
{
return;
}
rect = SKRect.Intersect(rect, _bounds);
if (((SKRect)(ref rect)).IsEmpty)
{
return;
}
for (int i = 0; i < _dirtyRects.Count; i++)
{
SKRect val = _dirtyRects[i];
if (((SKRect)(ref val)).Contains(rect))
{
return;
}
if (((SKRect)(ref rect)).Contains(_dirtyRects[i]))
{
_dirtyRects[i] = rect;
MergeDirtyRects();
return;
}
SKRect val2 = SKRect.Intersect(_dirtyRects[i], rect);
if (!((SKRect)(ref val2)).IsEmpty)
{
float num = ((SKRect)(ref val2)).Width * ((SKRect)(ref val2)).Height;
val = _dirtyRects[i];
float width = ((SKRect)(ref val)).Width;
val = _dirtyRects[i];
float num2 = Math.Min(width * ((SKRect)(ref val)).Height, ((SKRect)(ref rect)).Width * ((SKRect)(ref rect)).Height);
if (num > num2 * 0.5f)
{
_dirtyRects[i] = SKRect.Union(_dirtyRects[i], rect);
MergeDirtyRects();
return;
}
}
}
_dirtyRects.Add(rect);
if (_dirtyRects.Count > _maxDirtyRects)
{
_fullRedrawNeeded = true;
_dirtyRects.Clear();
}
}
}
// Check if they overlap significantly (50% overlap)
var intersection = SKRect.Intersect(_dirtyRects[i], rect);
if (!intersection.IsEmpty)
{
float intersectArea = intersection.Width * intersection.Height;
float smallerArea = Math.Min(
_dirtyRects[i].Width * _dirtyRects[i].Height,
rect.Width * rect.Height);
public void InvalidateAll()
{
lock (_lock)
{
_fullRedrawNeeded = true;
_dirtyRects.Clear();
}
}
if (intersectArea > smallerArea * 0.5f)
{
// Merge the rectangles
_dirtyRects[i] = SKRect.Union(_dirtyRects[i], rect);
MergeDirtyRects();
return;
}
}
}
public void Clear()
{
lock (_lock)
{
_fullRedrawNeeded = false;
_dirtyRects.Clear();
}
}
// Add as new dirty rect
_dirtyRects.Add(rect);
public SKRect GetCombinedDirtyRect()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
lock (_lock)
{
if (_fullRedrawNeeded || _dirtyRects.Count == 0)
{
return _bounds;
}
SKRect val = _dirtyRects[0];
for (int i = 1; i < _dirtyRects.Count; i++)
{
val = SKRect.Union(val, _dirtyRects[i]);
}
return val;
}
}
// Check if we have too many dirty rects
if (_dirtyRects.Count > _maxDirtyRects)
{
// Fall back to full redraw
_fullRedrawNeeded = true;
_dirtyRects.Clear();
}
}
}
public void ApplyClipping(SKCanvas canvas)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
lock (_lock)
{
if (_fullRedrawNeeded || _dirtyRects.Count == 0)
{
return;
}
SKPath val = new SKPath();
try
{
foreach (SKRect dirtyRect in _dirtyRects)
{
val.AddRect(dirtyRect, (SKPathDirection)0);
}
canvas.ClipPath(val, (SKClipOperation)1, false);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
}
/// <summary>
/// Invalidates the entire rendering area.
/// </summary>
public void InvalidateAll()
{
lock (_lock)
{
_fullRedrawNeeded = true;
_dirtyRects.Clear();
}
}
/// <summary>
/// Clears all dirty regions after rendering.
/// </summary>
public void Clear()
{
lock (_lock)
{
_fullRedrawNeeded = false;
_dirtyRects.Clear();
}
}
/// <summary>
/// Gets the combined dirty region as a single rectangle.
/// </summary>
public SKRect GetCombinedDirtyRect()
{
lock (_lock)
{
if (_fullRedrawNeeded || _dirtyRects.Count == 0)
{
return _bounds;
}
var combined = _dirtyRects[0];
for (int i = 1; i < _dirtyRects.Count; i++)
{
combined = SKRect.Union(combined, _dirtyRects[i]);
}
return combined;
}
}
/// <summary>
/// Applies dirty region clipping to a canvas.
/// </summary>
public void ApplyClipping(SKCanvas canvas)
{
lock (_lock)
{
if (_fullRedrawNeeded || _dirtyRects.Count == 0)
{
// No clipping needed for full redraw
return;
}
// Create a path from all dirty rects
using var path = new SKPath();
foreach (var rect in _dirtyRects)
{
path.AddRect(rect);
}
canvas.ClipPath(path);
}
}
private void MergeDirtyRects()
{
// Simple merge pass - could be optimized
bool merged;
do
{
merged = false;
for (int i = 0; i < _dirtyRects.Count - 1; i++)
{
for (int j = i + 1; j < _dirtyRects.Count; j++)
{
var intersection = SKRect.Intersect(_dirtyRects[i], _dirtyRects[j]);
if (!intersection.IsEmpty)
{
_dirtyRects[i] = SKRect.Union(_dirtyRects[i], _dirtyRects[j]);
_dirtyRects.RemoveAt(j);
merged = true;
break;
}
}
if (merged) break;
}
} while (merged);
}
private void MergeDirtyRects()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
bool flag;
do
{
flag = false;
for (int i = 0; i < _dirtyRects.Count - 1; i++)
{
for (int j = i + 1; j < _dirtyRects.Count; j++)
{
SKRect val = SKRect.Intersect(_dirtyRects[i], _dirtyRects[j]);
if (!((SKRect)(ref val)).IsEmpty)
{
_dirtyRects[i] = SKRect.Union(_dirtyRects[i], _dirtyRects[j]);
_dirtyRects.RemoveAt(j);
flag = true;
break;
}
}
if (flag)
{
break;
}
}
}
while (flag);
}
}