source/SkiaSharp.Views/SkiaSharp.Views.Gtk3/SKDrawingArea.cs (76 lines of code) (raw):

using System; using System.ComponentModel; using Cairo; using SkiaSharp.Views.Desktop; namespace SkiaSharp.Views.Gtk { [ToolboxItem(true)] public class SKDrawingArea : global::Gtk.DrawingArea { private ImageSurface pix; private SKSurface surface; public SKDrawingArea() { } public SKSize CanvasSize => pix == null ? SKSize.Empty : new SKSize(pix.Width, pix.Height); [Category("Appearance")] public event EventHandler<SKPaintSurfaceEventArgs> PaintSurface; protected override bool OnDrawn(Context cr) { // get the pixbuf var imgInfo = CreateDrawingObjects(); if (imgInfo.Width == 0 || imgInfo.Height == 0) return true; // start drawing using (new SKAutoCanvasRestore(surface.Canvas, true)) { OnPaintSurface(new SKPaintSurfaceEventArgs(surface, imgInfo)); } surface.Canvas.Flush(); pix.MarkDirty(); // swap R and B if (imgInfo.ColorType == SKColorType.Rgba8888) { using (var pixmap = surface.PeekPixels()) { SKSwizzle.SwapRedBlue(pixmap.GetPixels(), imgInfo.Width * imgInfo.Height); } } // write the pixbuf to the graphics cr.SetSourceSurface(pix, 0, 0); cr.Paint(); return true; } protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e) { // invoke the event PaintSurface?.Invoke(this, e); } protected override void Dispose(bool disposing) { if (disposing) { FreeDrawingObjects(); } } private SKImageInfo CreateDrawingObjects() { var alloc = Allocation; var w = alloc.Width; var h = alloc.Height; var imgInfo = new SKImageInfo(w, h, SKImageInfo.PlatformColorType, SKAlphaType.Premul); if (pix == null || pix.Width != imgInfo.Width || pix.Height != imgInfo.Height) { FreeDrawingObjects(); if (imgInfo.Width != 0 && imgInfo.Height != 0) { pix = new ImageSurface(Format.Argb32, imgInfo.Width, imgInfo.Height); // (re)create the SkiaSharp drawing objects surface = SKSurface.Create(imgInfo, pix.DataPtr, imgInfo.RowBytes); } } return imgInfo; } private void FreeDrawingObjects() { pix?.Dispose(); pix = null; // SkiaSharp objects should only exist if the Pixbuf is set as well surface?.Dispose(); surface = null; } } }