]> O.S.I.I.S - jp/crow.git/commitdiff
IBackend instead of IDevice to bind to Interface
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 24 Nov 2021 22:50:38 +0000 (23:50 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 24 Nov 2021 22:50:38 +0000 (23:50 +0100)
22 files changed:
Backends/CairoBackend/src/DefaultBackend.cs [new file with mode: 0644]
Backends/CairoBackend/src/Device.cs
Backends/CairoBackend/src/EGLDevice.cs
Backends/CairoBackend/src/GLSurface.cs
Backends/CairoBackend/src/ImageBackend.cs [new file with mode: 0644]
Crow/src/Fill/BmpPicture.cs
Crow/src/Fill/Gradient.cs
Crow/src/Fill/SvgPicture.cs
Crow/src/Interface.cs
Crow/src/Widgets/DockWindow.cs
Crow/src/Widgets/GroupBase.cs
Crow/src/Widgets/Label.cs
Crow/src/Widgets/PrivateContainer.cs
Crow/src/Widgets/ScrollingStack.cs
Crow/src/Widgets/Shape.cs
Crow/src/Widgets/Widget.cs
Drawing2D/src/Enums.cs
Drawing2D/src/IBackend.cs [new file with mode: 0644]
Drawing2D/src/IDevice.cs
Samples/HelloWorld/main.cs
Samples/PerfTests/Program.cs
Samples/common/src/SampleBase.cs

diff --git a/Backends/CairoBackend/src/DefaultBackend.cs b/Backends/CairoBackend/src/DefaultBackend.cs
new file mode 100644 (file)
index 0000000..9ef04b3
--- /dev/null
@@ -0,0 +1,16 @@
+using System;
+using Crow.CairoBackend;
+
+namespace Crow.Backends
+{
+       public class DefaultBackend : ImageBackend {
+               /// <summary>
+               /// Create a new generic backend bound to the application surface
+               /// </summary>
+               /// <param name="width">backend surface width</param>
+               /// <param name="height">backend surface height</param>
+               public DefaultBackend (IntPtr nativeWindoPointer, int width, int height)
+               : base (nativeWindoPointer, width, height) { }
+       }
+}
+
index c87b494ba34421268bd425c6b637bae57290d792..2efe76ece7a7f280ae33153cc45f95cee942bf18 100644 (file)
@@ -77,18 +77,9 @@ namespace Crow.CairoBackend
        }
        public class Device : IDevice
        {
-               /// <summary> Global font rendering settings for Cairo </summary>
-               FontOptions FontRenderingOptions;
-               /// <summary> Global font rendering settings for Cairo </summary>
-               Antialias Antialias = Antialias.Subpixel;
 
                public Device()
                {
-                       FontRenderingOptions = new FontOptions ();
-                       FontRenderingOptions.Antialias = Antialias.Subpixel;
-                       FontRenderingOptions.HintMetrics = HintMetrics.On;
-                       FontRenderingOptions.HintStyle = HintStyle.Full;
-                       FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
                }
 
                ~Device ()
@@ -106,87 +97,12 @@ namespace Crow.CairoBackend
                {
                        throw new NotImplementedException();
                }
-               public IRegion CreateRegion () => new Region ();
-               public virtual ISurface CreateSurface(int width, int height)
-                       => new ImageSurface (Format.ARGB32, width, height);
-               public virtual ISurface CreateSurface(byte[] data, int width, int height)
-                       => new ImageSurface (data, Format.ARGB32, width, height, 4 * width);
-
-               public virtual ISurface CreateSurface (IntPtr nativeWindoPointer, int width, int height) {
-                       switch (Environment.OSVersion.Platform) {
-                       case PlatformID.Unix:
-                               IntPtr disp = Glfw3.GetX11Display ();
-                               IntPtr nativeWin = Glfw3.GetX11Window (nativeWindoPointer);
-                               Int32 scr = Glfw3.GetX11DefaultScreen (disp);
-                               IntPtr visual = Glfw3.GetX11DefaultVisual (disp, scr);
-                               return new XlibSurface (disp, nativeWin, visual, width, height);
-                       case PlatformID.Win32NT:
-                       case PlatformID.Win32S:
-                       case PlatformID.Win32Windows:
-                               IntPtr hWin32 = Glfw3.GetWin32Window (nativeWindoPointer);
-                               IntPtr hdc = Glfw3.GetWin32DC (hWin32);
-                               return new Win32Surface (hdc);
-                       }
-                       throw new PlatformNotSupportedException ("Unable to create cairo surface.");
-               }
 
-               public virtual IContext CreateContext(ISurface surf)
-               {
-                       Context gr = new Context (surf);
-                       gr.FontOptions = FontRenderingOptions;
-                       gr.Antialias = Antialias;
-                       return gr;
-               }
-               public byte[] LoadBitmap (Stream stream, out Size dimensions) {
-                       byte[] image;
-#if STB_SHARP
-                       StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
-                       image = new byte[stbi.Data.Length];
-                       //rgba to argb for cairo.
-                       for (int i = 0; i < stbi.Data.Length; i += 4) {
-                               image[i] = stbi.Data[i + 2];
-                               image[i + 1] = stbi.Data[i + 1];
-                               image[i + 2] = stbi.Data[i];
-                               image[i + 3] = stbi.Data[i + 3];
-                       }
-                       dimensions = new Size (stbi.Width, stbi.Height);
-#else
-                       using (StbImage stbi = new StbImage (stream)) {
-                               image = new byte [stbi.Size];
-                               for (int i = 0; i < stbi.Size; i+=4) {
-                                       //rgba to argb for cairo. ???? looks like bgra to me.
-                                       image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
-                                       image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
-                                       image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
-                                       image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
-                               }
-                               dimensions = new Size (stbi.Width, stbi.Height);
-                       }
-#endif
-                       return image;
-               }
-               public ISvgHandle LoadSvg(Stream stream)
-               {
-                       using (BinaryReader sr = new BinaryReader (stream))
-                               return new SvgHandle (sr.ReadBytes ((int)stream.Length));
-               }
 
-               public ISvgHandle LoadSvg(string svgFragment) =>
-                       new SvgHandle (System.Text.Encoding.Unicode.GetBytes (svgFragment));
-
-               public IGradient CreateGradient (GradientType gradientType, Rectangle bounds) {
-                       switch (gradientType) {
-                       case GradientType.Vertical:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
-                       case GradientType.Horizontal:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
-                       case GradientType.Oblic:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
-                       case GradientType.Radial:
-                               throw new NotImplementedException ();
-                       }
-                       return null;
-               }
+
+
+
+
                #endregion
 
                #region IDispose implementation
@@ -198,8 +114,10 @@ namespace Crow.CairoBackend
 
                protected virtual void Dispose (bool disposing)
                {
-                       if (disposing)
-                               FontRenderingOptions.Dispose ();
+                       if (disposing){
+                               
+                       }
+                               
                }
                #endregion
        }
index 83629374f90ea0a058d634166a9b26aa2be20ad0..d9296b74e60da1973e3c0c5da157a014ba212aba 100644 (file)
@@ -34,15 +34,16 @@ namespace Crow.CairoBackend
 {
        public class EGLDevice : GLDevice
        {
-               public EGLDevice (IntPtr dpy, IntPtr gl_ctx, bool threadAwayre = false) : base (NativeMethods.cairo_egl_device_create (dpy, gl_ctx), true)
+               public EGLDevice (IntPtr dpy, IntPtr gl_ctx, bool threadAwayre = false)
+                       : base (NativeMethods.cairo_egl_device_create (dpy, gl_ctx), true)
                {
                        SetThreadAware(threadAwayre);
                }
-               public override ISurface CreateSurface(int width, int height)
+               /*public override ISurface CreateSurface(int width, int height)
                        => new ImageSurface (Format.ARGB32, width, height);
                public override ISurface CreateSurface (IntPtr nativeWindoPointer, int width, int height) {
                        return new GLSurface (this, Glfw.Glfw3.GetEGLSurface (nativeWindoPointer), width, height);
-               }
+               }*/
 
        }
 }
index c7959dc3f2dd76777d0d5126fabca67774ffc1a2..1f486c50a2fa910b0a589e169251144d49784c1a 100644 (file)
@@ -54,7 +54,7 @@ namespace Crow.CairoBackend {
                {}
                public override void Flush ()
                {
-                       base.Flush ();
+                       //base.Flush ();
                        SwapBuffers ();
                }
                public override int Width => NativeMethods.cairo_gl_surface_get_width (handle);
diff --git a/Backends/CairoBackend/src/ImageBackend.cs b/Backends/CairoBackend/src/ImageBackend.cs
new file mode 100644 (file)
index 0000000..e390ca9
--- /dev/null
@@ -0,0 +1,179 @@
+using System;
+using System.IO;
+using Drawing2D;
+using Glfw;
+
+namespace Crow.CairoBackend
+{
+       public class ImageBackend : IBackend {
+               ISurface surf;
+               /// <summary> Global font rendering settings for Cairo </summary>
+               FontOptions FontRenderingOptions;
+               /// <summary> Global font rendering settings for Cairo </summary>
+               Antialias Antialias = Antialias.Subpixel;
+               protected ImageBackend ()
+               {
+                       FontRenderingOptions = new FontOptions ();
+                       FontRenderingOptions.Antialias = Antialias.Subpixel;
+                       FontRenderingOptions.HintMetrics = HintMetrics.On;
+                       FontRenderingOptions.HintStyle = HintStyle.Full;
+                       FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
+               }
+               /// <summary>
+               /// Create a new generic backend bound to the application surface
+               /// </summary>
+               /// <param name="width">backend surface width</param>
+               /// <param name="height">backend surface height</param>
+               public ImageBackend (IntPtr nativeWindoPointer, int width, int height) : this () {
+
+                       switch (Environment.OSVersion.Platform) {
+                       case PlatformID.Unix:
+                               IntPtr disp = Glfw3.GetX11Display ();
+                               IntPtr nativeWin = Glfw3.GetX11Window (nativeWindoPointer);
+                               Int32 scr = Glfw3.GetX11DefaultScreen (disp);
+                               IntPtr visual = Glfw3.GetX11DefaultVisual (disp, scr);
+                               surf = new XlibSurface (disp, nativeWin, visual, width, height);
+                               break;
+                       case PlatformID.Win32NT:
+                       case PlatformID.Win32S:
+                       case PlatformID.Win32Windows:
+                               IntPtr hWin32 = Glfw3.GetWin32Window (nativeWindoPointer);
+                               IntPtr hdc = Glfw3.GetWin32DC (hWin32);
+                               surf = new Win32Surface (hdc);
+                               break;
+                       default:
+                               throw new PlatformNotSupportedException ("Unable to create cairo image backend.");
+                       }
+               }
+               /// <summary>
+               /// Create a new offscreen backend, used in perfTests
+               /// </summary>
+               /// <param name="width">backend surface width</param>
+               /// <param name="height">backend surface height</param>
+               public ImageBackend (int width, int height) : this () {
+                       surf = new ImageSurface (Format.ARGB32, width, height);
+               }
+               ~ImageBackend ()
+               {
+                       Dispose (false);
+               }
+               public virtual ISurface CreateSurface(int width, int height)
+                       => new ImageSurface (Format.ARGB32, width, height);
+               public virtual ISurface CreateSurface(byte[] data, int width, int height)
+                       => new ImageSurface (data, Format.ARGB32, width, height, 4 * width);
+               public ISurface MainSurface => surf;
+               public IRegion CreateRegion () => new Region ();
+               public IContext CreateContext (ISurface surf)
+               {
+                       Context gr = new Context (surf);
+                       gr.FontOptions = FontRenderingOptions;
+                       gr.Antialias = Antialias;
+                       return gr;
+               }
+               //IPattern CreatePattern (PatternType patternType);
+               public IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
+               {
+                       switch (gradientType) {
+                       case GradientType.Vertical:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
+                       case GradientType.Horizontal:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
+                       case GradientType.Oblic:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
+                       case GradientType.Radial:
+                               throw new NotImplementedException ();
+                       }
+                       return null;
+               }
+               public byte[] LoadBitmap (Stream stream, out Size dimensions)
+               {
+                       byte[] image;
+#if STB_SHARP
+                       StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
+                       image = new byte[stbi.Data.Length];
+                       //rgba to argb for cairo.
+                       for (int i = 0; i < stbi.Data.Length; i += 4) {
+                               image[i] = stbi.Data[i + 2];
+                               image[i + 1] = stbi.Data[i + 1];
+                               image[i + 2] = stbi.Data[i];
+                               image[i + 3] = stbi.Data[i + 3];
+                       }
+                       dimensions = new Size (stbi.Width, stbi.Height);
+#else
+                       using (StbImage stbi = new StbImage (stream)) {
+                               image = new byte [stbi.Size];
+                               for (int i = 0; i < stbi.Size; i+=4) {
+                                       //rgba to argb for cairo. ???? looks like bgra to me.
+                                       image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
+                                       image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
+                                       image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
+                                       image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
+                               }
+                               dimensions = new Size (stbi.Width, stbi.Height);
+                       }
+#endif
+                       return image;
+               }
+               public ISvgHandle LoadSvg(Stream stream)
+               {
+                       using (BinaryReader sr = new BinaryReader (stream))
+                               return new SvgHandle (sr.ReadBytes ((int)stream.Length));
+               }
+               public ISvgHandle LoadSvg(string svgFragment) =>
+                       new SvgHandle (System.Text.Encoding.Unicode.GetBytes (svgFragment));
+               bool disposeContextOnFlush;
+               IRegion clipping;
+               protected void clear(IContext ctx) {
+                       for (int i = 0; i < clipping.NumRectangles; i++)
+                               ctx.Rectangle (clipping.GetRectangle (i));
+
+                       ctx.ClipPreserve ();
+                       ctx.Operator = Operator.Clear;
+                       ctx.Fill ();
+                       ctx.Operator = Operator.Over;
+               }
+               public IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+               {
+                       this.clipping = clipping;
+                       IContext ctx = existingContext;
+                       if (ctx == null) {
+                               disposeContextOnFlush = true;
+                               ctx = new Context (MainSurface);
+                       } else
+                               disposeContextOnFlush = false;
+
+                       clear (ctx);
+                       ctx.PushGroup ();
+
+                       return ctx;
+               }
+               public void FlushUIFrame(IContext ctx)
+               {
+                       ctx.PopGroupToSource ();
+                       ctx.Paint ();
+
+                       if (disposeContextOnFlush)
+                               ctx.Dispose ();
+                       clipping = null;
+               }
+
+
+               #region IDispose implementation
+               bool isDisposed;
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+               protected virtual void Dispose (bool disposing)
+               {
+                       if (!isDisposed && disposing) {
+                               surf.Dispose ();
+                               FontRenderingOptions.Dispose ();
+                       }
+                       isDisposed = true;
+               }
+               #endregion
+       }
+}
+
index 72cc36b84cfcee259d2b4859fd4f8cda957cf31c..813e8dec23c540c2502c4a2f4eaa38fc2a81b841 100644 (file)
@@ -40,7 +40,7 @@ namespace Crow
                                return;
                        }
                        using (Stream stream = iFace.GetStreamFromPath (Path)) {
-                               image = iFace.Device.LoadBitmap (stream, out Size dimensions);
+                               image = iFace.Backend.LoadBitmap (stream, out Size dimensions);
                                Dimensions = dimensions;
                                iFace.sharedPictures[Path] = new sharedPicture (image, Dimensions);
                        }
@@ -89,13 +89,13 @@ namespace Crow
                                        widthRatio = heightRatio;
                        }
 
-                       using (ISurface tmp = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
-                               using (IContext gr = iFace.Device.CreateContext (tmp)) {
+                       using (ISurface tmp = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
+                               using (IContext gr = iFace.Backend.CreateContext (tmp)) {
                                        gr.Translate (bounds.Left, bounds.Top);
                                        gr.Scale (widthRatio, heightRatio);
                                        gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
 
-                                       using (ISurface imgSurf = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
+                                       using (ISurface imgSurf = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
                                                gr.SetSource (imgSurf, 0,0);
                                                gr.Paint ();
                                        }
@@ -138,7 +138,7 @@ namespace Crow
                        gr.Scale (widthRatio, heightRatio);
                        gr.Translate ((rect.Width/widthRatio - Dimensions.Width)/2, (rect.Height/heightRatio - Dimensions.Height)/2);
 
-                       using (ISurface imgSurf = iFace.Device.CreateSurface (image, Dimensions.Width, Dimensions.Height)) {
+                       using (ISurface imgSurf = iFace.Backend.CreateSurface (image, Dimensions.Width, Dimensions.Height)) {
                                gr.SetSource (imgSurf, 0,0);
                                gr.Paint ();
                        }
index d161eba8dc369922b91ebd40460dbd6e8f2c56af..abf841e363f2d0aa103669586e92abefb64e211d 100644 (file)
@@ -54,7 +54,7 @@ namespace Crow
 
                public override void SetAsSource (Interface iFace, IContext ctx, Rectangle bounds = default(Rectangle))
                {
-                       IGradient grad = iFace.Device.CreateGradient (Type, bounds);
+                       IGradient grad = iFace.Backend.CreateGradient (Type, bounds);
                        foreach (ColorStop cs in Stops) {
                                if (cs == null)
                                        continue;
index d562b3429fa07025ffa0cee67d08da94a2660eb9..e6e54aff23049619efacb0692b55bc8dddc892e4 100644 (file)
@@ -38,13 +38,13 @@ namespace Crow
                                return;
                        }
                        using (Stream stream = iFace.GetStreamFromPath (Path))
-                               hSVG = iFace.Device.LoadSvg (stream);
+                               hSVG = iFace.Backend.LoadSvg (stream);
                        Dimensions = hSVG.Dimensions;
                        iFace.sharedPictures [Path] = new sharedPicture (hSVG, Dimensions);
                }
 
                public void LoadSvgFragment (Interface iface, string fragment) {
-                       hSVG = iface.Device.LoadSvg (fragment);
+                       hSVG = iface.Backend.LoadSvg (fragment);
                        Dimensions = hSVG.Dimensions;
                }
 
@@ -70,8 +70,8 @@ namespace Crow
                                        widthRatio = heightRatio;
                        }
 
-                       using (ISurface tmp = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
-                               using (IContext gr = iFace.Device.CreateContext (tmp)) {
+                       using (ISurface tmp = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
+                               using (IContext gr = iFace.Backend.CreateContext (tmp)) {
                                        gr.Translate (bounds.Left, bounds.Top);
                                        gr.Scale (widthRatio, heightRatio);
                                        gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
index e0c00ede1325009dfa0601a00add6727ec711671..19d12f3f26d67975edf852d7433a4418b8d06a0c 100644 (file)
@@ -50,6 +50,54 @@ namespace Crow
                }
                #endregion
 
+               #region Static and constants
+               //initial capacity for layouting and clipping queues.
+               const int INIT_QUEUE_CAPACITY = 512;
+               /// <summary>Time interval in milisecond between Updates of the interface</summary>
+               public static int UPDATE_INTERVAL = 5;
+               /// <summary>
+               /// Time interval in milisecond between Glfw polling for devices. Wait is done in
+               /// the 'UpdateFrame' method in the 'Run' cycle and may be overriden.
+               /// </summary>
+               public static int POLLING_INTERVAL = 1;
+               /// <summary>Crow configuration root path</summary>
+               public static string CROW_CONFIG_ROOT;
+               /// <summary>If true, mouse focus is given when mouse is over control</summary>
+               public static bool FOCUS_ON_HOVER = false;
+               /// <summary>If true, newly focused window will be put on top</summary>
+               public static bool RAISE_WIN_ON_FOCUS = true;
+               /// <summary> Threshold to catch borders for sizing </summary>
+               public static int BorderThreshold = 3;
+               /// <summary> delay before tooltip appears </summary>
+               public static int TOOLTIP_DELAY = 500;
+               /// <summary>Double click threshold in milisecond</summary>
+               public static int DOUBLECLICK_TRESHOLD = 320;//max duration between two mouse_down evt for a dbl clk in milisec.
+               /// <summary> Time to wait in millisecond before starting repeat loop</summary>
+               public static int DEVICE_REPEAT_DELAY = 600;
+               /// <summary> Time interval in millisecond between device event repeat</summary>
+               public static int DEVICE_REPEAT_INTERVAL = 100;
+               public static float WheelIncrement = 1;
+               /// <summary>Tabulation size in Text controls</summary>
+               public static int TAB_SIZE = 4;
+               [Obsolete]public static string LineBreak = "\n";
+               /// <summary> Allow rendering of interface in development environment </summary>
+               public static bool DesignerMode = false;
+               /// <summary> Disable caching for a widget if this threshold is reached </summary>
+               public const int MaxCacheSize = 2048;
+               /// <summary> Above this count, the layouting is discard from the current
+               /// update cycle and requeued for the next</summary>
+               public static int MaxLayoutingTries = 30;
+               /// <summary> Above this count, the layouting is discard for the widget and it
+               /// will not be rendered on screen </summary>
+               public static int MaxDiscardCount = 5;
+
+               /// <summary>
+               /// Each control need a ref to the root interface containing it, if not set in Widget.currentInterface,
+               /// the ref of this one will be stored in Widget.currentInterface
+               /// </summary>
+               //protected static Interface CurrentInterface;
+               #endregion
+
                internal static List<Assembly> crowAssemblies = new List<Assembly> ();
                /// <summary>
                /// Add Assembly that may contains CROW ui ressources like custom widget classes, IML, images, ...
@@ -78,8 +126,6 @@ namespace Crow
                                init_internal ();
                        }
                }
-               static void nativeHelpMessage () {
-               }
                static IntPtr resolveUnmanaged(Assembly assembly, String libraryName)
                {
                        try {
@@ -171,33 +217,31 @@ namespace Crow
                /// <param name="height">the height of the window</param>
                /// <param name="glfwWindowHandle">A valid GLFW window handle</param>
                /// <returns></returns>
-               public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, false, false)
+               public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, true, false)
                {
                        hWin = glfwWindowHandle;
                        PerformanceMeasure.InitMeasures ();
                }
-               IDevice dev;
-               public IDevice Device => dev;
-
                /// <summary>
                /// Create a standard Crow interface.
                /// </summary>
                /// <param name="width">the width of the native window</param>
                /// <param name="height">the height of the native window</param>
-               /// <param name="startUIThread">If 'yes' start the ui update (InterfaceThread method) in a dedicated thread</param>
+               /// <param name="singleThreaded">If 'false' start the ui update (InterfaceThread method) in a dedicated thread</param>
                /// <param name="createSurface">If 'yes', create the main rendering surface on the native window</param>
-               public Interface (int width = 800, int height = 600, bool startUIThread = true, bool createSurface = true)
+               public Interface (int width = 800, int height = 600, bool singleThreaded = false, bool createSurface = true)
                {
                        CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
                        //CurrentInterface = this;
                        clientRectangle = new Rectangle (0, 0, width, height);
+                       SingleThreaded = singleThreaded;
 
                        if (createSurface)
                                initSurface ();
 
                        PerformanceMeasure.InitMeasures ();
 
-                       if (startUIThread) {
+                       if (!SingleThreaded) {
                                Thread t = new Thread (InterfaceThread) {
                                        IsBackground = true
                                };
@@ -206,6 +250,57 @@ namespace Crow
                }
                #endregion
 
+               #region IDisposable Support
+               private bool disposedValue = false; // To detect redundant calls
+
+               protected virtual void Dispose(bool disposing)
+               {
+                       if (!disposedValue)
+                       {
+                               if (disposing)
+                               {
+                                       disposeContextMenus ();
+                                       Backend.Dispose ();
+                               }
+
+                               currentCursor?.Dispose ();
+
+                               if (ownWindow) {
+                                       Glfw3.DestroyWindow (hWin);
+                                       Glfw3.Terminate ();
+                               }
+
+                               disposedValue = true;
+                       }
+               }
+               ~Interface() {
+                       Dispose(false);
+               }
+               public void Dispose()
+               {
+                       Dispose(true);
+                       GC.SuppressFinalize(this);
+               }
+               #endregion
+
+
+               /// <summary>
+               /// Cache already searched extension methods to prevent searching again and again for
+               /// missing method or to speedup loading once a method is found.
+               /// </summary>
+               /// <remarks>
+               /// This cache is reseted when a crow assembly is removed, or the theme is changed.
+               /// </remarks>
+               protected Dictionary<string, MethodInfo> knownExtMethods;
+               /// <summary>
+               /// Cache already searched widget types.
+               /// </summary>
+               /// <remarks>
+               /// This cache is reseted when a crow assembly is removed, or the theme is changed.
+               /// </remarks>
+               protected Dictionary<string, Type> knownCrowWidgetTypes;
+               /// <summary>Client rectangle in the host context</summary>
+               protected Rectangle clientRectangle;
 #if MEASURE_TIME
                public PerformanceMeasure[] PerfMeasures => PerformanceMeasure.Measures;
 #endif
@@ -214,12 +309,77 @@ namespace Crow
                static Dictionary<IntPtr, Interface> windows = new Dictionary<IntPtr, Interface> ();
                /** GLFW window native pointer and current native handle for mouse cursor */
                IntPtr hWin;
+               protected IBackend backend;//backend device
+               /// <summary>Clipping rectangles on the root context</summary>
+               protected IRegion clipping;
+               static string backendDeviceTypeString = "Crow.CairoBackend.Device";
                Cursor currentCursor;
                bool ownWindow;
                /// <summary>
+               /// If `true`, UI updates will be handle in the `Run()` method, so in the main thread of the application along with GLFW events polling.
+               /// If `false`, A dedicated thread will be started for the UI updates.
+               /// </summary>
+               public readonly bool SingleThreaded;
+               /// <summary>
                /// Native GLFW window handle bound to this interface.
                /// </summary>
                public IntPtr WindowHandle => hWin;
+               public IBackend Backend => backend;
+               /// <summary>Main backend surface</summary>
+               public ISurface MainSurface => backend.MainSurface;
+               public IntPtr SurfacePointer {
+                       get {
+                               lock(UpdateMutex)
+                                       return MainSurface.Handle;
+                       }
+               }
+
+               #region Public Fields
+               /// <summary>Graphic Tree of this interface</summary>
+               public List<Widget> GraphicTree = new List<Widget>();
+               /// <summary>Interface's resulting bitmap</summary>
+               public byte[] bmp;
+               /// <summary>resulting bitmap limited to last redrawn part</summary>
+               public byte[] dirtyBmp;
+               /// <summary>True when host has to repaint Interface</summary>
+               public bool IsDirty;
+               /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
+               public Rectangle DirtyRect;
+               /// <summary>Locked for each layouting operation</summary>
+               public object LayoutMutex = new object();
+               /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
+               public object RenderMutex = new object();
+               /// <summary>Global lock of the update cycle</summary>
+               public object UpdateMutex = new object();
+               /// <summary>Global lock of the clipping queue</summary>
+               public object ClippingMutex = new object();
+               //TODO:share resource instances
+               /// <summary>
+               /// Store loaded resources instances shared among controls to reduce memory footprint
+               /// </summary>
+               public Dictionary<string,object> Ressources = new Dictionary<string, object>();
+               /// <summary>The Main layouting queue.</summary>
+               public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> (INIT_QUEUE_CAPACITY);
+               /// <summary>Store discarded lqi between two updates</summary>
+               public Queue<LayoutingQueueItem> DiscardQueue;
+               /// <summary>Main drawing queue, holding layouted controls</summary>
+               public Queue<Widget> ClippingQueue = new Queue<Widget>(INIT_QUEUE_CAPACITY);
+               //TODO:use object instead for complex copy paste
+               public string Clipboard {
+                       get => Glfw3.GetClipboardString (hWin);
+                       set => Glfw3.SetClipboardString (hWin, value);
+               }
+               /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
+               /// on the first instance creation of a IML item.
+               /// </summary>
+               public Dictionary<String, Instantiator> Instantiators;
+               /// <summary>
+               /// Item templates stored with their index
+               /// </summary>
+               public Dictionary<String, ItemTemplate> ItemTemplates;
+
+               public List<CrowThread> CrowThreads = new List<CrowThread>();//used to monitor thread finished
+               #endregion
 
                /// <summary>
                /// Register GLFW window callbacs (mouse, keyboard, sizing, refresh).
@@ -240,19 +400,10 @@ namespace Crow
 #endif
                        Glfw3.SetWindowRefreshCallback (hWin, HandleWindowRefreshDelegate);
                }
-#if VKVG
-               protected VulkanContextBase vkCtx;
-               internal Device vkvgDevice => vkCtx.VkvgDevice;
 
-               /// <summary>
-               /// Create the VulkanContext with swapchain support. Override it to use another vulkan backend.
-               /// </summary>
-#endif
-               static string backendDeviceTypeString = "Crow.CairoBackend.Device";
-               protected void initBackend (bool offscreen = false) {
-
-                       dev = new Crow.CairoBackend.Device ();
-                       clipping = dev.CreateRegion ();
+               protected virtual void initBackend () {
+                       backend = new Crow.CairoBackend.ImageBackend (hWin, clientRectangle.Width, clientRectangle.Height);
+                       clipping = Backend.CreateRegion ();
                }
                /// <summary>
                /// Create the main rendering surface. The default is a GLFW window with a cairo surface bound to it.
@@ -261,88 +412,23 @@ namespace Crow
                {
                        Glfw3.Init ();
 
-                       Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
+                       Glfw3.WindowHint (WindowAttribute.ClientApi, Constants.OpenglEsApi);
+                       Glfw3.WindowHint (WindowAttribute.ContextVersionMajor, 3);
+                       //Glfw3.WindowHint (WindowAttribute.ContextVersionMajor, 0);
+                       Glfw3.WindowHint (WindowAttribute.ContextCreationApi, Constants.EglContextApi);
+
                        Glfw3.WindowHint (WindowAttribute.Resizable, 1);
                        Glfw3.WindowHint (WindowAttribute.Decorated, 1);
 
                        hWin = Glfw3.CreateWindow (clientRectangle.Width, clientRectangle.Height, "win name", MonitorHandle.Zero, IntPtr.Zero);
                        if (hWin == IntPtr.Zero)
-                               throw new Exception ("[GLFW3] Unable to create vulkan Window");
+                               throw new Exception ("[GLFW3] Unable to create Window");
                        ownWindow = true;
 
                        registerGlfwCallbacks ();
 
                        initBackend ();
-
-                       CreateMainSurface (ref clientRectangle);
-               }
-               /// <summary>
-               /// ??
-               /// </summary>
-               /// <param name="r"></param>
-               public void CreateMainSurface (ref Rectangle r) {
-                       surf?.Dispose();
-                       surf = Device.CreateSurface (hWin, r.Width, r.Height);
-               }
-               public IntPtr SurfacePointer {
-                       get {
-                               lock(UpdateMutex)
-                                       return surf.Handle;
-                       }
-               }
-               /// <summary>
-               /// Set the main GLFW window icon.
-               /// </summary>
-               /// <param name="path"></param>
-               public void SetWindowIcon (string path) {
-                       using (Stream stream = GetStreamFromPath (path)) {
-#if STB_SHARP
-                               StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
-                               byte[] image = new byte[stbi.Data.Length];
-                               //rgba to argb for cairo.
-                               for (int i = 0; i < stbi.Data.Length; i += 4) {
-                                       image[i] = stbi.Data[i + 2];
-                                       image[i + 1] = stbi.Data[i + 1];
-                                       image[i + 2] = stbi.Data[i];
-                                       image[i + 3] = stbi.Data[i + 3];
-                               }
-                               Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
-                               Glfw3.SetWindowIcon (hWin, 1, ref icon);
-                               icon.Dispose();
-
-#else
-                               using (StbImage stbi = new StbImage (stream)) {
-                                       byte[] image = new byte [stbi.Size];
-                                       //rgba to argb for cairo.
-                                       for (int i = 0; i < stbi.Size; i+=4) {
-                                               image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
-                                               image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
-                                               image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
-                                               image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
-                                       }
-                                       Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
-                                       Glfw3.SetWindowIcon (hWin, 1, ref icon);
-                                       icon.Dispose();
-                               }
-#endif
-                       }
                }
-               /// <summary>
-               /// Cache already searched extension methods to prevent searching again and again for
-               /// missing method or to speedup loading once a method is found.
-               /// </summary>
-               /// <remarks>
-               /// This cache is reseted when a crow assembly is removed, or the theme is changed.
-               /// </remarks>
-               protected Dictionary<string, MethodInfo> knownExtMethods;
-               /// <summary>
-               /// Cache already searched widget types.
-               /// </summary>
-               /// <remarks>
-               /// This cache is reseted when a crow assembly is removed, or the theme is changed.
-               /// </remarks>
-               protected Dictionary<string, Type> knownCrowWidgetTypes;
-
                /// <summary>
                /// search for graphic object type in crow assembly, if not found,
                /// search for type independently of namespace in all the loaded assemblies
@@ -403,17 +489,34 @@ namespace Crow
                        return mi;
                }
 
-               #region events delegates
+               #region Events
+               //public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
+               ////public event EventHandler Quit;
+               public event EventHandler Initialized;
 
+               public event EventHandler StartDragOperation;
+               public event EventHandler EndDragOperation;
+               public event EventHandler<KeyEventArgs> KeyDown;
+               public event EventHandler<KeyEventArgs> KeyUp;
+
+               //public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
+               //public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
+               //public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
+               //public event EventHandler<MouseButtonEventArgs> MouseClick;
+               //public event EventHandler<MouseMoveEventArgs> MouseMove;
+               //public event EventHandler<KeyEventArgs> KeyDown;
+               //public event EventHandler<KeyPressEventArgs> KeyPress;
+               /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
+               public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
+               #region events delegates
                static CursorPosDelegate HandleCursorPosDelegate = (window, xPosition, yPosition) => {
-                       windows [window].OnMouseMove ((int)(xPosition / windows [window].ZoomFactor), (int)(yPosition / windows [window].ZoomFactor));
+                       windows [window].OnMouseMove ((int)(xPosition), (int)(yPosition));
                };
                static MouseButtonDelegate HandleMouseButtonDelegate = (IntPtr window, MouseButton button, InputAction action, Modifier mods) => {
                        if (action == InputAction.Release)
                                windows [window].OnMouseButtonUp (button);
                        else//press and repeat
                                windows [window].OnMouseButtonDown (button);
-
                };
                static ScrollDelegate HandleScrollDelegate = (IntPtr window, double xOffset, double yOffset) => {
                        windows [window].OnMouseWheelChanged ((int)yOffset);
@@ -438,24 +541,53 @@ namespace Crow
                static WindowDelegate HandleWindowRefreshDelegate = (IntPtr window) => {
                        windows [window].registerRefreshClientRectangle ();
                };
-
+               #endregion
                #endregion
 
                public string WindowTitle {
                        set => Glfw3.SetWindowTitle (hWin, value);
                }
+               /// <summary>
+               /// Set the main GLFW window icon.
+               /// </summary>
+               /// <param name="path"></param>
+               public void SetWindowIcon (string path) {
+                       using (Stream stream = GetStreamFromPath (path)) {
+#if STB_SHARP
+                               StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
+                               byte[] image = new byte[stbi.Data.Length];
+                               //rgba to argb for cairo.
+                               for (int i = 0; i < stbi.Data.Length; i += 4) {
+                                       image[i] = stbi.Data[i + 2];
+                                       image[i + 1] = stbi.Data[i + 1];
+                                       image[i + 2] = stbi.Data[i];
+                                       image[i + 3] = stbi.Data[i + 3];
+                               }
+                               Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
+                               Glfw3.SetWindowIcon (hWin, 1, ref icon);
+                               icon.Dispose();
 
+#else
+                               using (StbImage stbi = new StbImage (stream)) {
+                                       byte[] image = new byte [stbi.Size];
+                                       //rgba to argb for cairo.
+                                       for (int i = 0; i < stbi.Size; i+=4) {
+                                               image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
+                                               image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
+                                               image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
+                                               image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
+                                       }
+                                       Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
+                                       Glfw3.SetWindowIcon (hWin, 1, ref icon);
+                                       icon.Dispose();
+                               }
+#endif
+                       }
+               }
                public bool Running {
                        get => !Glfw3.WindowShouldClose (hWin);
                        set => Glfw3.SetWindowShouldClose (hWin, value == true ? 0 : 1);
                }
-               public virtual void InterfaceThread ()
-               {
-                       while (!Glfw3.WindowShouldClose (hWin)) {
-                               Update ();
-                               Thread.Sleep (UPDATE_INTERVAL);
-                       }
-               }
                protected virtual void OnInitialized ()
                {
                        /*try {
@@ -484,29 +616,38 @@ namespace Crow
                        loadThemeFiles ();
                        initContextMenus ();
                }
+               public virtual void InterfaceThread ()
+               {
+                       while (!Glfw3.WindowShouldClose (hWin)) {
+                               Update ();
+                               Thread.Sleep (UPDATE_INTERVAL);
+                       }
+               }
                /// <summary>
                /// call Init() then enter the running loop performing ProcessEvents until running==false.
                /// </summary>
                public virtual void Run () {
                        Init ();
 
-                       while (!Glfw3.WindowShouldClose (hWin)) {
-                               Glfw3.PollEvents ();
-                               UpdateFrame ();
+                       if (SingleThreaded) {
+                               while (!Glfw3.WindowShouldClose (WindowHandle)) {
+                                       Glfw3.PollEvents ();
+                                       Update();
+                                       UpdateFrame ();
+                                       Thread.Sleep (UPDATE_INTERVAL);
+                               }
+                       } else {
+                               while (!Glfw3.WindowShouldClose (hWin)) {
+                                       Glfw3.PollEvents ();
+                                       UpdateFrame ();
+                                       Thread.Sleep (POLLING_INTERVAL);
+                               }
                        }
 
                        Terminate ();
                }
                public virtual void Terminate () {}
-               public virtual void UpdateFrame () {
-#if VKVG
-                       Update ();
-                       Thread.Sleep (UPDATE_INTERVAL);
-#else
-                       Thread.Sleep (POLLING_INTERVAL);
-#endif
-               }
-
+               public virtual void UpdateFrame () {}
                public virtual void Quit () => Glfw3.SetWindowShouldClose (hWin, 1);
 
                public bool Shift => Glfw3.GetKey(hWin, Key.LeftShift) == InputAction.Press ||
@@ -532,164 +673,18 @@ namespace Crow
                }
 #endif
 
-               #region IDisposable Support
-               private bool disposedValue = false; // To detect redundant calls
-
-               protected virtual void Dispose(bool disposing)
-               {
-                       if (!disposedValue)
-                       {
-                               if (disposing)
-                               {
-                                       disposeContextMenus ();
-                                       dev.Dispose ();
-                               }
-
-                               currentCursor?.Dispose ();
-
-                               if (ownWindow) {
-                                       Glfw3.DestroyWindow (hWin);
-                                       Glfw3.Terminate ();
-                               }
-
-                               disposedValue = true;
-                       }
-               }
-               ~Interface() {
-                       Dispose(false);
-               }
-
-               public void Dispose()
-               {
-                       Dispose(true);
-                       GC.SuppressFinalize(this);
-               }
-               #endregion
-
-               #region Static and constants
-               //initial capacity for layouting and clipping queues.
-               const int INIT_QUEUE_CAPACITY = 512;
-               /// <summary>Time interval in milisecond between Updates of the interface</summary>
-               public static int UPDATE_INTERVAL = 5;
-               /// <summary>
-               /// Time interval in milisecond between Glfw polling for devices. Wait is done in
-               /// the 'UpdateFrame' method in the 'Run' cycle and may be overriden.
-               /// </summary>
-               public static int POLLING_INTERVAL = 1;
-               /// <summary>Crow configuration root path</summary>
-               public static string CROW_CONFIG_ROOT;
-               /// <summary>If true, mouse focus is given when mouse is over control</summary>
-               public static bool FOCUS_ON_HOVER = false;
-               /// <summary>If true, newly focused window will be put on top</summary>
-               public static bool RAISE_WIN_ON_FOCUS = true;
-               /// <summary> Threshold to catch borders for sizing </summary>
-               public static int BorderThreshold = 3;
-               /// <summary> delay before tooltip appears </summary>
-               public static int TOOLTIP_DELAY = 500;
-               /// <summary>Double click threshold in milisecond</summary>
-               public static int DOUBLECLICK_TRESHOLD = 320;//max duration between two mouse_down evt for a dbl clk in milisec.
-               /// <summary> Time to wait in millisecond before starting repeat loop</summary>
-               public static int DEVICE_REPEAT_DELAY = 600;
-               /// <summary> Time interval in millisecond between device event repeat</summary>
-               public static int DEVICE_REPEAT_INTERVAL = 100;
-               public static float WheelIncrement = 1;
-               /// <summary>Tabulation size in Text controls</summary>
-               public static int TAB_SIZE = 4;
-               [Obsolete]public static string LineBreak = "\n";
-               /// <summary> Allow rendering of interface in development environment </summary>
-               public static bool DesignerMode = false;
-               /// <summary> Disable caching for a widget if this threshold is reached </summary>
-               public const int MaxCacheSize = 2048;
-               /// <summary> Above this count, the layouting is discard from the current
-               /// update cycle and requeued for the next</summary>
-               public static int MaxLayoutingTries = 30;
-               /// <summary> Above this count, the layouting is discard for the widget and it
-               /// will not be rendered on screen </summary>
-               public static int MaxDiscardCount = 5;
-
-               /// <summary>
-               /// Each control need a ref to the root interface containing it, if not set in Widget.currentInterface,
-               /// the ref of this one will be stored in Widget.currentInterface
-               /// </summary>
-               //protected static Interface CurrentInterface;
-               #endregion
 
-               #region Events
-               //public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
-               ////public event EventHandler Quit;
-               public event EventHandler Initialized;
 
-               public event EventHandler StartDragOperation;
-               public event EventHandler EndDragOperation;
-               public event EventHandler<KeyEventArgs> KeyDown;
-               public event EventHandler<KeyEventArgs> KeyUp;
 
-               //public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
-               //public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
-               //public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
-               //public event EventHandler<MouseButtonEventArgs> MouseClick;
-               //public event EventHandler<MouseMoveEventArgs> MouseMove;
-               //public event EventHandler<KeyEventArgs> KeyDown;
-               //public event EventHandler<KeyPressEventArgs> KeyPress;
-               /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
-               public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
-               #endregion
 
-               /// <summary>Main backend surface</summary>
-               public ISurface surf;
 
-               #region Public Fields
-               /// <summary>Graphic Tree of this interface</summary>
-               public List<Widget> GraphicTree = new List<Widget>();
-               /// <summary>Interface's resulting bitmap</summary>
-               public byte[] bmp;
-               /// <summary>resulting bitmap limited to last redrawn part</summary>
-               public byte[] dirtyBmp;
-               /// <summary>True when host has to repaint Interface</summary>
-               public bool IsDirty;
-               /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
-               public Rectangle DirtyRect;
-               /// <summary>Locked for each layouting operation</summary>
-               public object LayoutMutex = new object();
-               /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
-               public object RenderMutex = new object();
-               /// <summary>Global lock of the update cycle</summary>
-               public object UpdateMutex = new object();
-               /// <summary>Global lock of the clipping queue</summary>
-               public object ClippingMutex = new object();
-               //TODO:share resource instances
-               /// <summary>
-               /// Store loaded resources instances shared among controls to reduce memory footprint
-               /// </summary>
-               public Dictionary<string,object> Ressources = new Dictionary<string, object>();
-               /// <summary>The Main layouting queue.</summary>
-               public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> (INIT_QUEUE_CAPACITY);
-               /// <summary>Store discarded lqi between two updates</summary>
-               public Queue<LayoutingQueueItem> DiscardQueue;
-               /// <summary>Main drawing queue, holding layouted controls</summary>
-               public Queue<Widget> ClippingQueue = new Queue<Widget>(INIT_QUEUE_CAPACITY);
-               //TODO:use object instead for complex copy paste
-               public string Clipboard {
-                       get => Glfw3.GetClipboardString (hWin);
-                       set => Glfw3.SetClipboardString (hWin, value);
-               }
-               /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
-               /// on the first instance creation of a IML item.
-               /// </summary>
-               public Dictionary<String, Instantiator> Instantiators;
-               /// <summary>
-               /// Item templates stored with their index
-               /// </summary>
-               public Dictionary<String, ItemTemplate> ItemTemplates;
 
-               public List<CrowThread> CrowThreads = new List<CrowThread>();//used to monitor thread finished
 
+               #region DragAndDrop
                public bool DragAndDropInProgress => DragAndDropOperation != null;
                public Widget DropTarget => DragAndDropOperation?.DropTarget;
-
                public DragDropEventArgs DragAndDropOperation = null;
                internal Widget dragndropHover;
-
                public ISurface DragImage = null;
                public Rectangle DragImageBounds, lastDragImageBounds;
                public bool DragImageFolowMouse;//prevent dragImg to be moved by mouse
@@ -715,15 +710,6 @@ namespace Crow
                }
                #endregion
 
-               #region Private Fields
-               /// <summary>Client rectangle in the host context</summary>
-               protected Rectangle clientRectangle;
-               /// <summary>Clipping rectangles on the root context</summary>
-               IRegion clipping;
-               /// <summary>Main Cairo context</summary>
-               //Context ctx;
-               #endregion
-
                #region Default values and Style loading
                /// Default values of properties from Widgets are retrieve from XML Attributes.
                /// The reflexion process used to retrieve those values being very slow, it is compiled in MSIL
@@ -816,10 +802,10 @@ namespace Crow
                                                        string resId = $"#{pic.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}";
                                                        using (Stream s = new FileStream (pic, FileMode.Open, FileAccess.Read)) {
                                                                if (resId.EndsWith (".svg", StringComparison.OrdinalIgnoreCase)) {
-                                                                       ISvgHandle hSVG = Device.LoadSvg (s);
+                                                                       ISvgHandle hSVG = Backend.LoadSvg (s);
                                                                        sharedPictures[resId] = new sharedPicture (hSVG, hSVG.Dimensions);
                                                                } else {
-                                                                       byte[] image = Device.LoadBitmap (s, out Size dimensions);
+                                                                       byte[] image = Backend.LoadBitmap (s, out Size dimensions);
                                                                        sharedPictures[resId] = new sharedPicture (image, dimensions);
                                                                }
                                                        }
@@ -1151,11 +1137,9 @@ namespace Crow
                                }
 
                                if (!clipping.IsEmpty || shouldDrawTextCursor) {
-                                       if (ctx == null) {
-                                               using (ctx =  Device.CreateContext (surf))
-                                                       processDrawing (ctx);
-                                       }else
-                                               processDrawing (ctx);
+                                       ctx = Backend.PrepareUIFrame (ctx, clipping);
+                                       processDrawing (ctx);
+                                       Backend.FlushUIFrame (ctx);
                                }
                        } finally {
 
@@ -1217,40 +1201,7 @@ namespace Crow
                        PerformanceMeasure.End (PerformanceMeasure.Kind.Clipping);
                        DbgLogger.EndEvent (DbgEvtType.ClippingRegistration, true);
                }
-               void clear(IContext ctx) {
-                       for (int i = 0; i < clipping.NumRectangles; i++)
-                               ctx.Rectangle (clipping.GetRectangle (i));
 
-                       ctx.ClipPreserve ();
-                       ctx.Operator = Operator.Clear;
-                       ctx.Fill ();
-                       ctx.Operator = Operator.Over;
-               }
-               bool solidBackground = false;
-               public bool SolidBackground {
-                       get => solidBackground;
-                       set {
-                               if (Environment.OSVersion.Platform == PlatformID.Unix)
-                                       solidBackground = value;
-                               else
-                                       Debug.WriteLine ("SolidBackground property only available on unix.");
-                       }
-               }
-               double zoomFactor = 1.0;
-               public double ZoomFactor {
-                       get => zoomFactor;
-                       set {
-                               if (zoomFactor == value)
-                                       return;
-                               zoomFactor = value;
-                               NotifyValueChanged (zoomFactor);
-                               lock (UpdateMutex) {
-                                       foreach (Widget g in GraphicTree)
-                                               g.RegisterForLayouting (LayoutingType.All);
-                                       registerRefreshClientRectangle ();
-                               }
-                       }
-               }
 
                /// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
                /// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place</summary>
@@ -1258,18 +1209,8 @@ namespace Crow
                        DbgLogger.StartEvent (DbgEvtType.ProcessDrawing);
 
                        PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing);
-                       if (!clipping.IsEmpty) {
-                               ctx.Scale (zoomFactor,zoomFactor);
-
-#if VKVG
-                               clear (ctx);
-#else
-                               ctx.PushGroup ();
-
-                               if (SolidBackground)
-                                       clear (ctx);
-#endif
 
+                       if (!clipping.IsEmpty) {
                                for (int i = GraphicTree.Count -1; i >= 0 ; i--){
                                        Widget p = GraphicTree[i];
                                        if (!p.IsVisible)
@@ -1282,7 +1223,6 @@ namespace Crow
                                        ctx.Restore ();
                                }
 
-
                                if (lastDragImageBounds != DragImageBounds) {
                                        DirtyRect += lastDragImageBounds;
                                        ctx.Save ();
@@ -1304,28 +1244,13 @@ namespace Crow
 
 #endif
 
-#if VKVG
-                               ctx.Flush();
-#else
-                               ctx.PopGroupToSource ();
-
-                               if (!SolidBackground)
-                                       clear (ctx);
-
-                               ctx.Paint ();
-
-                               surf.Flush ();
-#endif
-
                                clipping.Reset ();
 
                                PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing);
                                IsDirty = true;
                        }
 
-#if !VKVG
                        drawTextCursor (ctx);
-#endif
 
                        debugHighlightFocus (ctx);
 
@@ -1354,7 +1279,7 @@ namespace Crow
                        /*if (DragAndDropInProgress) {
 
                        }*/
-                       surf.Flush ();
+                       MainSurface.Flush ();
                }
 
                #region Blinking text cursor
@@ -1372,7 +1297,7 @@ namespace Crow
                                                if (textCursor != null && c != textCursor.Value)
                                                        RegisterClip (textCursor.Value);
                                                textCursor = c;
-                                               surf.Flush ();
+                                               MainSurface.Flush ();
                                        } else if (textCursor != null)
                                                RegisterClip (textCursor.Value);
                                }
@@ -1386,7 +1311,7 @@ namespace Crow
                                if (blinkingCursor.ElapsedMilliseconds > TEXT_CURSOR_BLINK_FREQUENCY) {
                                        if (lab.DrawCursor (ctx, out Rectangle c)) {
                                                textCursor = c;
-                                               surf.Flush ();
+                                               MainSurface.Flush ();
                                                blinkingCursor.Restart ();
                                        }
                                }
@@ -1506,7 +1431,7 @@ namespace Crow
                public virtual void ProcessResize(Rectangle bounds){
                        lock (UpdateMutex) {
                                clientRectangle = bounds;
-                               surf.Resize (clientRectangle.Width, clientRectangle.Height);
+                               MainSurface.Resize (clientRectangle.Width, clientRectangle.Height);
                                foreach (Widget g in GraphicTree)
                                        g.RegisterForLayouting (LayoutingType.All);
 
@@ -1514,7 +1439,7 @@ namespace Crow
                        }
                }
 
-               internal void registerRefreshClientRectangle () => RegisterClip (clientRectangle);
+               protected void registerRefreshClientRectangle () => RegisterClip (clientRectangle);
 
                #region Mouse and Keyboard Handling
                MouseCursor cursor = MouseCursor.top_left_arrow;
@@ -1646,7 +1571,7 @@ namespace Crow
                /// Ask OS to force the mouse position to the actual coordinate of Interface.MousePosition
                /// </summary>
                public virtual void ForceMousePosition () {
-                       Glfw3.SetCursorPosition (hWin, MousePosition.X * ZoomFactor, MousePosition.Y * ZoomFactor);
+                       Glfw3.SetCursorPosition (hWin, MousePosition.X, MousePosition.Y);
                }
 
                /// <summary>Processes mouse move events from the root container, this function
@@ -2123,7 +2048,7 @@ namespace Crow
                        set { throw new NotImplementedException (); }
                }
 
-               public Rectangle ClientRectangle => clientRectangle.Scaled (1.0/zoomFactor);
+               public Rectangle ClientRectangle => clientRectangle;
                public Rectangle GetClientRectangleForChild (ILayoutable child) => ClientRectangle;
                public Interface HostContainer => this;
 
index 6c6c49f9c21a24dc6ef83de2fe94b5046618dd09..620d31f32b54250ba113df097e4016b1bb4eb739 100644 (file)
@@ -200,8 +200,8 @@ namespace Crow
                                        r.Inflate (r.Width / -3, r.Height / -3);
                                        break;
                                }
-                   ISurface dragImg = IFace.Device.CreateSurface (r.Width, r.Height);
-                               using (IContext gr = IFace.Device.CreateContext (dragImg)) {
+                   ISurface dragImg = IFace.Backend.CreateSurface (r.Width, r.Height);
+                               using (IContext gr = IFace.Backend.CreateContext (dragImg)) {
                                        gr.LineWidth = 1;
                                        gr.Rectangle (0,0,r.Width,r.Height);
                                        gr.SetSource (0.2,0.3,0.9,0.5);
index 1f62eb902eafd292ac56357af90e6b8a6d9e30b1..e99b176ef932fa8228a8319b0e0340e790ee75a6 100644 (file)
@@ -251,7 +251,7 @@ namespace Crow
                {
                        DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
                        if (!Clipping.IsEmpty) {
-                               using (IContext gr = IFace.Device.CreateContext (bmp)) {
+                               using (IContext gr = IFace.Backend.CreateContext (bmp)) {
                                        for (int i = 0; i < Clipping.NumRectangles; i++)
                                                gr.Rectangle(Clipping.GetRectangle(i));
                                        gr.ClipPreserve();
index 5ef0952387c2dadb345f074174f21a41f1ea4349..330cbe55b4969a29cd98e4fe0e7921aa9345b863 100644 (file)
@@ -514,7 +514,7 @@ namespace Crow
                        int hoverLine = _multiline ?
                                (int)Math.Min (Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent + fe.Descent))), lines.Count - 1) : 0;
                        hoverLoc = new CharLocation (hoverLine, -1, mouseLocalPos.X);
-                       using (IContext gr = IFace.Device.CreateContext (IFace.surf)) {
+                       using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
                                gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
                                gr.SetFontSize (Font.Size);
                                updateLocation (gr, ClientRectangle.Width, ref hoverLoc);
@@ -650,7 +650,7 @@ namespace Crow
                                getLines ();
 
                        if (!textMeasureIsUpToDate) {
-                               using (IContext gr = IFace.Device.CreateContext (IFace.surf)) {
+                               using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
                                        gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
                                        gr.SetFontSize (Font.Size);
                                        measureTextBounds (gr);
index 3b705ea51ef0050a1fdee63a2b8e102e600030d6..f5345523794d4d9c47032ac285a7721ec2bd6a0f 100644 (file)
@@ -215,7 +215,7 @@ namespace Crow
 
                        Rectangle rb = Slot + Parent.ClientRectangle.Position;
                        if (!Clipping.IsEmpty) {
-                               using (IContext gr = IFace.Device.CreateContext (bmp)) {
+                               using (IContext gr = IFace.Backend.CreateContext (bmp)) {
                                        for (int i = 0; i < Clipping.NumRectangles; i++)
                                                gr.Rectangle(Clipping.GetRectangle(i));
                                        gr.ClipPreserve();
index c67bf7d1dbaec49e7be92644017e2de9d3c6dbfd..55535ded3909d97bc9a1587457f0589f701ed18d 100644 (file)
@@ -136,7 +136,7 @@ namespace Crow {
                {
                        DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
                        if (!Clipping.IsEmpty) {
-                               using (IContext gr = IFace.Device.CreateContext (bmp)) {
+                               using (IContext gr = IFace.Backend.CreateContext (bmp)) {
                                        for (int i = 0; i < Clipping.NumRectangles; i++)
                                                gr.Rectangle(Clipping.GetRectangle(i));
                                        gr.ClipPreserve();
index efa8b45b45bc4ba67b4147ef2f2b38db4dc2cc98..8322543e2051795c842c0561a2a1276f3fb16ae7 100644 (file)
@@ -242,7 +242,7 @@ namespace Crow
                                if (size != default (Size))
                                        contentSize = size;
                                else {
-                                       using (IContext ctx = IFace.Device.CreateContext (IFace.surf)) {
+                                       using (IContext ctx = IFace.Backend.CreateContext (IFace.MainSurface)) {
                                                using (PathParser parser = new PathParser (path))
                                                        parser.Draw (ctx, true);
                                                Rectangle r = ctx.StrokeExtents ();
index 57b65aab243b8ceba9acee5f56b505ef9151b08d..5d3e4c457ae9a4204d38dce8fb74d12371791c93 100644 (file)
@@ -1168,7 +1168,7 @@ namespace Crow
                {
                        DbgLogger.StartEvent (DbgEvtType.GOInitialization, this);
 
-                       Clipping = IFace.Device.CreateRegion ();
+                       Clipping = IFace.Backend.CreateRegion ();
                        Type thisType = this.GetType ();
 
                        if (!string.IsNullOrEmpty (style)) {
@@ -1954,12 +1954,13 @@ namespace Crow
                        else if (LastPaintedSlot.Width != Slot.Width || LastPaintedSlot.Height != Slot.Height)
                                bmp.SetSize (Slot.Width, Slot.Height);*/
                        bmp?.Dispose ();
-                       bmp = IFace.Device.CreateSurface (Slot.Width, Slot.Height);
+                       //bmp = IFace.Device.CreateSurface (Slot.Width, Slot.Height);
+                       bmp = IFace.Backend.CreateSurface (Slot.Width, Slot.Height);
 
                        //bmp = new ImageSurface(Format.Argb32, Slot.Width, Slot.Height);
 
                        DbgLogger.StartEvent (DbgEvtType.GOCreateContext, this);
-                       using (IContext gr = IFace.Device.CreateContext (bmp)) {
+                       using (IContext gr = IFace.Backend.CreateContext (bmp)) {
                                DbgLogger.EndEvent (DbgEvtType.GOCreateContext);
                                onDraw (gr);
                        }
index 12a6f035e0423593576a5bec621e3e35ab0085a0..bf20a432b19ca6853df3b7652cae896efe8279cf 100644 (file)
@@ -6,6 +6,12 @@ using System;
 
 namespace Drawing2D
 {
+       public enum BackendType {
+               Native,
+               OpenGL,
+               EGL,
+               Vulkan
+       }
        public enum Status
        {
                Success = 0,
diff --git a/Drawing2D/src/IBackend.cs b/Drawing2D/src/IBackend.cs
new file mode 100644 (file)
index 0000000..811b95d
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2018-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.IO;
+
+namespace Drawing2D
+{
+       public interface IBackend: IDisposable
+       {
+               ISurface CreateSurface (int width, int height);
+               ISurface CreateSurface (byte[] data, int width, int height);
+               //ISurface CreateMainSurface (IntPtr glfwWinHandle, int width, int height);
+               ISurface MainSurface { get; }
+               IRegion CreateRegion ();
+               IContext CreateContext (ISurface surf);
+               //IPattern CreatePattern (PatternType patternType);
+               IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+               byte[] LoadBitmap (Stream stream, out Size dimensions);
+               ISvgHandle LoadSvg (Stream stream);
+               ISvgHandle LoadSvg (string svgFragment);
+               IContext PrepareUIFrame (IContext existingContext, IRegion clipping);
+               void FlushUIFrame (IContext ctx);
+               /*IRegion CreateRegion ();
+               ISurface CreateSurface (int width, int height);
+               ISurface CreateSurface (byte[] data, int width, int height);
+               ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
+               IContext CreateContext (ISurface surf);
+               //IPattern CreatePattern (PatternType patternType);
+               IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+               byte[] LoadBitmap (Stream stream, out Size dimensions);
+               ISvgHandle LoadSvg (Stream stream);
+               ISvgHandle LoadSvg (string svgFragment);*/
+       }
+}
+
index 891f8b2ec6ee77587634bb2414120e3cb89c4f19..14846271646f99d3f7aabaee95df0e8af6f800ed 100644 (file)
@@ -13,16 +13,6 @@ namespace Drawing2D
 
                void GetDpy (out int hdpy, out int vdpy);
                void SetDpy (int hdpy, int vdpy);
-               IRegion CreateRegion ();
-               ISurface CreateSurface (int width, int height);
-               ISurface CreateSurface (byte[] data, int width, int height);
-               ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
-               IContext CreateContext (ISurface surf);
-               //IPattern CreatePattern (PatternType patternType);
-               IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
-               byte[] LoadBitmap (Stream stream, out Size dimensions);
-               ISvgHandle LoadSvg (Stream stream);
-               ISvgHandle LoadSvg (string svgFragment);
        }
 }
 
index e60b97820a0e6809a6dce508fa106e3136539fab..e84607b9dc99876cc44708409c8ff0f05ab9383f 100644 (file)
@@ -1,13 +1,15 @@
 using System;
 using Crow;
+using Glfw;
 using Samples;
 
 namespace HelloWorld
 {
-       class Program {
+       class Program : Interface {
+               Program() : base (800, 600, true, true) {}
                static void Main (string[] args) {
-                       using (Interface app = new Interface ()) {
-                               app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Label Text='Hello World'/>");
+                       using (Program app = new Program ()) {
+                               app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Window Caption='Hello World'/>");
                                app.Run ();
                        }
                }
index d7f6a9be423f27279c3c15f9d39970e265d8f5ce..cbe6273889c8e5a5038288981e6e33b699a56d70 100644 (file)
@@ -64,7 +64,7 @@ namespace PerfTests
                }
 
                public TestInterface (string[] args, int width = 800, int height = 600)
-                       : base (width, height, false, false)
+                       : base (width, height, true, false)
                {
                        string outDir = null;
 
@@ -141,15 +141,10 @@ namespace PerfTests
                                writer.WriteLine ("Path;MinEllapsed;MaxEllapsed;MeanEllapsed;MedianEllapsed;sigmaEllapsed;MinMem;MaxMem;MeanMem;MedianMem;sigmaMem;MinAlloc;MaxAlloc;MeanAlloc;MedianAlloc;sigmaAlloc");
                        }
 
-                       if (screenOutput) {
-                               initBackend ();
+                       if (screenOutput)
                                initSurface ();
-                       } else {
-                               SolidBackground = false;
-                               initBackend (true);
-
-                               CreateMainSurface (ref clientRectangle);
-                       }
+                       else
+                               initBackend ();
 
                        initDictionaries ();
                        loadStyling ();
@@ -163,6 +158,15 @@ namespace PerfTests
                                outStream.Dispose ();
             }
         }
+               protected override void initBackend()
+               {
+                       if (screenOutput)
+                               backend = new Crow.CairoBackend.ImageBackend (WindowHandle, clientRectangle.Width, clientRectangle.Height);
+                       else
+                               backend = new Crow.CairoBackend.ImageBackend (clientRectangle.Width, clientRectangle.Height);
+
+                       clipping = Backend.CreateRegion ();
+               }
 
                struct Measures
         {
index 2d773af46749063e8fd50cff51f383f74106eefc..2e7440a1ae7ebfcdc8ffa0472fa4b2c00eb4b417 100644 (file)
@@ -20,11 +20,6 @@ namespace Samples
        {
                public SampleBase(IntPtr hWin) : base(800, 600, hWin) { }
                public SampleBase() : base(800, 600, true, true) { }
-               public SampleBase(int width, int height, bool startUIThread, bool createSurface) :
-                       base(width, height, startUIThread, createSurface)
-               {
-
-               }
 
                public Version CrowVersion => Assembly.GetAssembly(typeof(Widget)).GetName().Version;