A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

100 lines
3.4 KiB

using System;
using Avalonia.Platform;
using Avalonia.Win32.Interop;
using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Win32
{
public class WindowFramebuffer : ILockedFramebuffer
{
private readonly IntPtr _handle;
private IUnmanagedBlob _bitmapBlob;
private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo;
public WindowFramebuffer(IntPtr handle, PixelSize size)
{
if (size.Width <= 0)
throw new ArgumentException("Width is less than zero");
if (size.Height <= 0)
throw new ArgumentException("Height is less than zero");
_handle = handle;
_bmpInfo.Init();
_bmpInfo.biPlanes = 1;
_bmpInfo.biBitCount = 32;
_bmpInfo.Init();
_bmpInfo.biWidth = size.Width;
_bmpInfo.biHeight = -size.Height;
_bitmapBlob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(size.Width * size.Height * 4);
}
~WindowFramebuffer()
{
Deallocate();
}
public IntPtr Address => _bitmapBlob.Address;
public int RowBytes => Size.Width * 4;
public PixelFormat Format => PixelFormat.Bgra8888;
public Vector Dpi
{
get
{
if (UnmanagedMethods.ShCoreAvailable)
{
uint dpix, dpiy;
var monitor = UnmanagedMethods.MonitorFromWindow(_handle,
UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
if (UnmanagedMethods.GetDpiForMonitor(
monitor,
UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI,
out dpix,
out dpiy) == 0)
{
return new Vector(dpix, dpiy);
}
}
return new Vector(96, 96);
}
}
public PixelSize Size => new PixelSize(_bmpInfo.biWidth, -_bmpInfo.biHeight);
public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if (width == -1)
width = Size.Width;
if (height == -1)
height = Size.Height;
UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY,
0, (uint)Size.Height, _bitmapBlob.Address, ref _bmpInfo, 0);
}
public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if (_bitmapBlob.IsDisposed)
throw new ObjectDisposedException("Framebuffer");
if (hWnd == IntPtr.Zero)
return false;
IntPtr hDC = UnmanagedMethods.GetDC(hWnd);
if (hDC == IntPtr.Zero)
return false;
DrawToDevice(hDC, destX, destY, srcX, srcY, width, height);
UnmanagedMethods.ReleaseDC(hWnd, hDC);
return true;
}
public void Dispose()
{
//It's not an *actual* dispose. This call means "We are done drawing"
DrawToWindow(_handle);
}
public void Deallocate() => _bitmapBlob.Dispose();
}
}