Browse Source

[X11] Implemented icons

Nikita Tsukanov 6 years ago
parent
commit
ec682e2e1d

+ 0 - 49
src/Avalonia.X11/Stubs.cs

@@ -14,53 +14,4 @@ namespace Avalonia.X11
         public Size DoubleClickSize { get; } = new Size(2, 2);
         public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500);
     }
-
-    class SystemDialogsStub : ISystemDialogImpl
-    {
-        public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
-        {
-            return Task.FromResult((string[])null);
-        }
-
-        public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
-        {
-            return Task.FromResult((string)null);
-        }
-    }
-
-    class IconLoaderStub : IPlatformIconLoader
-    {
-        class FakeIcon : IWindowIconImpl
-        {
-            private readonly byte[] _data;
-
-            public FakeIcon(byte[] data)
-            {
-                _data = data;
-            }
-            public void Save(Stream outputStream)
-            {
-                outputStream.Write(_data, 0, _data.Length);
-            }
-        }
-        
-        public IWindowIconImpl LoadIcon(string fileName)
-        {
-            return new FakeIcon(File.ReadAllBytes(fileName));
-        }
-
-        public IWindowIconImpl LoadIcon(Stream stream)
-        {
-            var ms = new MemoryStream();
-            stream.CopyTo(ms);
-            return new FakeIcon(ms.ToArray());
-        }
-
-        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
-        {
-            var ms = new MemoryStream();
-            bitmap.Save(ms);
-            return new FakeIcon(ms.ToArray());
-        }
-    }
 }

+ 4 - 2
src/Avalonia.X11/X11Framebuffer.cs

@@ -9,12 +9,14 @@ namespace Avalonia.X11
     {
         private readonly IntPtr _display;
         private readonly IntPtr _xid;
+        private readonly int _depth;
         private IUnmanagedBlob _blob;
 
-        public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, double factor)
+        public X11Framebuffer(IntPtr display, IntPtr xid, int depth, int width, int height, double factor)
         {
             _display = display;
             _xid = xid;
+            _depth = depth;
             Size = new PixelSize(width, height);
             RowBytes = width * 4;
             Dpi = new Vector(96, 96) * factor;
@@ -35,7 +37,7 @@ namespace Avalonia.X11
             image.bitmap_unit = bitsPerPixel;
             image.bitmap_bit_order = 0;// LSBFirst;
             image.bitmap_pad = bitsPerPixel;
-            image.depth = 24;
+            image.depth = _depth;
             image.bytes_per_line = RowBytes;
             image.bits_per_pixel = bitsPerPixel;
             XLockDisplay(_display);

+ 1 - 1
src/Avalonia.X11/X11FramebufferSurface.cs

@@ -23,7 +23,7 @@ namespace Avalonia.X11
             XGetGeometry(_display, _xid, out var root, out var x, out var y, out var width, out var height,
                 out var bw, out var d);
             XUnlockDisplay(_display);
-            return new X11Framebuffer(_display, _xid, width, height, _scaling());
+            return new X11Framebuffer(_display, _xid, 24,width, height, _scaling());
         }
     }
 }

+ 85 - 0
src/Avalonia.X11/X11IconLoader.cs

@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using Avalonia.Utilities;
+using Avalonia.Visuals.Media.Imaging;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+    class X11IconLoader : IPlatformIconLoader
+    {
+        private readonly X11Info _x11;
+
+        public X11IconLoader(X11Info x11)
+        {
+            _x11 = x11;
+        }
+        
+        IWindowIconImpl LoadIcon(Bitmap bitmap) => new X11IconData(bitmap);
+
+        public IWindowIconImpl LoadIcon(string fileName) => LoadIcon(new Bitmap(fileName));
+
+        public IWindowIconImpl LoadIcon(Stream stream) => LoadIcon(new Bitmap(stream));
+
+        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            var ms = new MemoryStream();
+            bitmap.Save(ms);
+            ms.Position = 0;
+            return LoadIcon(ms);
+        }
+    }
+    
+    unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
+    {
+        private readonly Bitmap _bitmap;
+        private int _width;
+        private int _height;
+        private uint[] _bdata;
+        public IntPtr[]  Data { get; }
+        
+        public X11IconData(Bitmap bitmap)
+        {
+            _bitmap = bitmap;
+            _width = Math.Min(_bitmap.PixelSize.Width, 128);
+            _height = Math.Min(_bitmap.PixelSize.Height, 128);
+            _bdata = new uint[_width * _height];
+            fixed (void* ptr = _bdata)
+            {
+                var iptr = (int*)ptr;
+                iptr[0] = _width;
+                iptr[1] = _height;
+            }
+            using(var rt = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().CreateRenderTarget(new[]{this}))
+            using (var ctx = rt.CreateDrawingContext(null))
+                ctx.DrawImage(bitmap.PlatformImpl, 1, new Rect(bitmap.Size),
+                    new Rect(0, 0, _width, _height));
+            Data = new IntPtr[_width * _height + 2];
+            Data[0] = new IntPtr(_width);
+            Data[1] = new IntPtr(_height);
+            for (var y = 0; y < _height; y++)
+            {
+                var r = y * _width;
+                for (var x = 0; x < _width; x++)
+                    Data[r + x] = new IntPtr(_bdata[r + x]);
+            }
+        }
+
+        public void Save(Stream outputStream)
+        {
+            _bitmap.Save(outputStream);
+        }
+
+        public ILockedFramebuffer Lock()
+        {
+            var h = GCHandle.Alloc(_bdata, GCHandleType.Pinned);
+            return new LockedFramebuffer(h.AddrOfPinnedObject(), new PixelSize(_width, _height), _width * 4,
+                new Vector(96, 96), PixelFormat.Bgra8888,
+                () => h.Free());
+        }
+    }
+}

+ 1 - 2
src/Avalonia.X11/X11Platform.cs

@@ -43,8 +43,7 @@ namespace Avalonia.X11
                 .Bind<IStandardCursorFactory>().ToConstant(new X11CursorFactory(Display))
                 .Bind<IClipboard>().ToConstant(new X11Clipboard(this))
                 .Bind<IPlatformSettings>().ToConstant(new PlatformSettingsStub())
-                .Bind<ISystemDialogImpl>().ToConstant(new SystemDialogsStub())
-                .Bind<IPlatformIconLoader>().ToConstant(new IconLoaderStub())
+                .Bind<IPlatformIconLoader>().ToConstant(new X11IconLoader(Info))
                 .Bind<ISystemDialogImpl>().ToConstant(new Gtk3ForeignX11SystemDialog());
             
             X11Screens = Avalonia.X11.X11Screens.Init(this);

+ 5 - 1
src/Avalonia.X11/X11Window.cs

@@ -800,7 +800,11 @@ namespace Avalonia.X11
 
         public void SetIcon(IWindowIconImpl icon)
         {
-            //TODO
+            var data = ((X11IconData)icon).Data;
+            fixed (void* pdata = data)
+                XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON,
+                    new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace,
+                    pdata, data.Length);
         }
 
         public void ShowTaskbarIcon(bool value)