// 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.Handlers;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Platform;
using SkiaSharp;
namespace Microsoft.Maui.Platform.Linux.Handlers;
///
/// Handler for Window on Linux.
/// Maps IWindow to the Linux display window system.
///
public partial class WindowHandler : ElementHandler
{
public static IPropertyMapper Mapper =
new PropertyMapper(ElementHandler.ElementMapper)
{
[nameof(IWindow.Title)] = MapTitle,
[nameof(IWindow.Content)] = MapContent,
[nameof(IWindow.X)] = MapX,
[nameof(IWindow.Y)] = MapY,
[nameof(IWindow.Width)] = MapWidth,
[nameof(IWindow.Height)] = MapHeight,
[nameof(IWindow.MinimumWidth)] = MapMinimumWidth,
[nameof(IWindow.MinimumHeight)] = MapMinimumHeight,
[nameof(IWindow.MaximumWidth)] = MapMaximumWidth,
[nameof(IWindow.MaximumHeight)] = MapMaximumHeight,
};
public static CommandMapper CommandMapper =
new(ElementHandler.ElementCommandMapper)
{
};
public WindowHandler() : base(Mapper, CommandMapper)
{
}
public WindowHandler(IPropertyMapper? mapper, CommandMapper? commandMapper = null)
: base(mapper ?? Mapper, commandMapper ?? CommandMapper)
{
}
protected override SkiaWindow CreatePlatformElement()
{
return new SkiaWindow();
}
protected override void ConnectHandler(SkiaWindow platformView)
{
base.ConnectHandler(platformView);
platformView.CloseRequested += OnCloseRequested;
platformView.SizeChanged += OnSizeChanged;
}
protected override void DisconnectHandler(SkiaWindow platformView)
{
platformView.CloseRequested -= OnCloseRequested;
platformView.SizeChanged -= OnSizeChanged;
base.DisconnectHandler(platformView);
}
private void OnCloseRequested(object? sender, EventArgs e)
{
VirtualView?.Destroying();
}
private void OnSizeChanged(object? sender, SizeChangedEventArgs e)
{
VirtualView?.FrameChanged(new Rect(0, 0, e.Width, e.Height));
}
public static void MapTitle(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.Title = window.Title ?? "MAUI Application";
}
public static void MapContent(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
var content = window.Content;
if (content?.Handler?.PlatformView is SkiaView skiaContent)
{
handler.PlatformView.Content = skiaContent;
}
}
public static void MapX(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.X = (int)window.X;
}
public static void MapY(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.Y = (int)window.Y;
}
public static void MapWidth(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.Width = (int)window.Width;
}
public static void MapHeight(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.Height = (int)window.Height;
}
public static void MapMinimumWidth(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.MinWidth = (int)window.MinimumWidth;
}
public static void MapMinimumHeight(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.MinHeight = (int)window.MinimumHeight;
}
public static void MapMaximumWidth(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.MaxWidth = (int)window.MaximumWidth;
}
public static void MapMaximumHeight(WindowHandler handler, IWindow window)
{
if (handler.PlatformView is null) return;
handler.PlatformView.MaxHeight = (int)window.MaximumHeight;
}
}
///
/// Skia window wrapper for Linux display servers.
///
public class SkiaWindow
{
private SkiaView? _content;
private string _title = "MAUI Application";
private int _x, _y;
private int _width = 800;
private int _height = 600;
private int _minWidth = 100;
private int _minHeight = 100;
private int _maxWidth = int.MaxValue;
private int _maxHeight = int.MaxValue;
public SkiaView? Content
{
get => _content;
set
{
_content = value;
ContentChanged?.Invoke(this, EventArgs.Empty);
}
}
public string Title
{
get => _title;
set
{
_title = value;
TitleChanged?.Invoke(this, EventArgs.Empty);
}
}
public int X
{
get => _x;
set { _x = value; PositionChanged?.Invoke(this, EventArgs.Empty); }
}
public int Y
{
get => _y;
set { _y = value; PositionChanged?.Invoke(this, EventArgs.Empty); }
}
public int Width
{
get => _width;
set
{
_width = Math.Clamp(value, _minWidth, _maxWidth);
SizeChanged?.Invoke(this, new SizeChangedEventArgs(_width, _height));
}
}
public int Height
{
get => _height;
set
{
_height = Math.Clamp(value, _minHeight, _maxHeight);
SizeChanged?.Invoke(this, new SizeChangedEventArgs(_width, _height));
}
}
public int MinWidth
{
get => _minWidth;
set { _minWidth = value; }
}
public int MinHeight
{
get => _minHeight;
set { _minHeight = value; }
}
public int MaxWidth
{
get => _maxWidth;
set { _maxWidth = value; }
}
public int MaxHeight
{
get => _maxHeight;
set { _maxHeight = value; }
}
public event EventHandler? ContentChanged;
public event EventHandler? TitleChanged;
public event EventHandler? PositionChanged;
public event EventHandler? SizeChanged;
public event EventHandler? CloseRequested;
public void Close()
{
CloseRequested?.Invoke(this, EventArgs.Empty);
}
}
///
/// Event args for window size changes.
///
public class SizeChangedEventArgs : EventArgs
{
public int Width { get; }
public int Height { get; }
public SizeChangedEventArgs(int width, int height)
{
Width = width;
Height = height;
}
}