From 75b1d7fbf1c805f3149e2213977efc04e9a149f0 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 3 Jun 2016 21:47:21 -0400 Subject: [PATCH] Implemented icons for the Win32 and GTK. --- .../Avalonia.Controls.csproj | 7 + src/Avalonia.Controls/Icon.cs | 28 ++++ src/Avalonia.Controls/Platform/IIconImpl.cs | 12 ++ .../Platform/IPlatformIconLoader.cs | 15 ++ src/Avalonia.Controls/Platform/IWindowImpl.cs | 5 + src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj | 1 + src/Gtk/Avalonia.Gtk/GtkPlatform.cs | 16 +- src/Gtk/Avalonia.Gtk/IconImpl.cs | 20 +++ src/Gtk/Avalonia.Gtk/WindowImpl.cs | 15 +- .../Avalonia.Win32/Avalonia.Win32.csproj | 9 ++ src/Windows/Avalonia.Win32/IconImpl.cs | 19 +++ .../Interop/UnmanagedMethods.cs | 142 ++++++++++-------- src/Windows/Avalonia.Win32/Win32Platform.cs | 18 ++- src/Windows/Avalonia.Win32/WindowImpl.cs | 9 +- 14 files changed, 240 insertions(+), 76 deletions(-) create mode 100644 src/Avalonia.Controls/Icon.cs create mode 100644 src/Avalonia.Controls/Platform/IIconImpl.cs create mode 100644 src/Avalonia.Controls/Platform/IPlatformIconLoader.cs create mode 100644 src/Gtk/Avalonia.Gtk/IconImpl.cs create mode 100644 src/Windows/Avalonia.Win32/IconImpl.cs diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index fb86bac1f5..27d5390a52 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -56,6 +56,8 @@ + + @@ -64,6 +66,11 @@ + + + + + diff --git a/src/Avalonia.Controls/Icon.cs b/src/Avalonia.Controls/Icon.cs new file mode 100644 index 0000000000..f7a55e0478 --- /dev/null +++ b/src/Avalonia.Controls/Icon.cs @@ -0,0 +1,28 @@ +using Avalonia.Platform; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Controls +{ + /// + /// Represents an icon for a window. + /// + public class Icon + { + public Icon(string fileName) + { + PlatformImpl = AvaloniaLocator.Current.GetService().LoadIcon(fileName); + } + + public Icon(Stream stream) + { + PlatformImpl = AvaloniaLocator.Current.GetService().LoadIcon(stream); + } + + public IIconImpl PlatformImpl { get; } + } +} diff --git a/src/Avalonia.Controls/Platform/IIconImpl.cs b/src/Avalonia.Controls/Platform/IIconImpl.cs new file mode 100644 index 0000000000..a109d82673 --- /dev/null +++ b/src/Avalonia.Controls/Platform/IIconImpl.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Platform +{ + public interface IIconImpl + { + } +} diff --git a/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs b/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs new file mode 100644 index 0000000000..4a22c3e7a8 --- /dev/null +++ b/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Platform +{ + public interface IPlatformIconLoader + { + IIconImpl LoadIcon(string fileName); + IIconImpl LoadIcon(Stream stream); + } +} diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 857c31ad5e..9000b8abfc 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -39,5 +39,10 @@ namespace Avalonia.Platform /// Enables of disables system window decorations (title bar, buttons, etc) /// void SetSystemDecorations(bool enabled); + + /// + /// Sets the icon of this window. + /// + void SetIcon(IIconImpl icon); } } diff --git a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj index 831ee23265..fe075bca77 100644 --- a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj +++ b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj @@ -46,6 +46,7 @@ + diff --git a/src/Gtk/Avalonia.Gtk/GtkPlatform.cs b/src/Gtk/Avalonia.Gtk/GtkPlatform.cs index b09f1c9ea6..27216c3f58 100644 --- a/src/Gtk/Avalonia.Gtk/GtkPlatform.cs +++ b/src/Gtk/Avalonia.Gtk/GtkPlatform.cs @@ -25,9 +25,10 @@ namespace Avalonia namespace Avalonia.Gtk { + using System.IO; using Gtk = global::Gtk; - public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform + public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader { private static readonly GtkPlatform s_instance = new GtkPlatform(); private static Thread _uiThread; @@ -53,7 +54,8 @@ namespace Avalonia.Gtk .Bind().ToConstant(GtkMouseDevice.Instance) .Bind().ToConstant(s_instance) .Bind().ToConstant(s_instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(s_instance); SharedPlatform.Register(); _uiThread = Thread.CurrentThread; } @@ -112,5 +114,15 @@ namespace Avalonia.Gtk { return new PopupImpl(); } + + public IIconImpl LoadIcon(string fileName) + { + return new IconImpl(new Gdk.Pixbuf(fileName)); + } + + public IIconImpl LoadIcon(Stream stream) + { + return new IconImpl(new Gdk.Pixbuf(stream)); + } } } \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/IconImpl.cs b/src/Gtk/Avalonia.Gtk/IconImpl.cs new file mode 100644 index 0000000000..d505e4d236 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/IconImpl.cs @@ -0,0 +1,20 @@ +using Avalonia.Platform; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Gdk; + +namespace Avalonia.Gtk +{ + class IconImpl : IIconImpl + { + public IconImpl(Pixbuf pixbuf) + { + Pixbuf = pixbuf; + } + + public Pixbuf Pixbuf { get; } + } +} diff --git a/src/Gtk/Avalonia.Gtk/WindowImpl.cs b/src/Gtk/Avalonia.Gtk/WindowImpl.cs index 3b8065ce57..fd6bbb7c61 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImpl.cs @@ -53,11 +53,11 @@ namespace Avalonia.Gtk Realize(); } - protected override void OnRealized () - { - base.OnRealized (); - _imContext.ClientWindow = this.GdkWindow; - } + protected override void OnRealized () + { + base.OnRealized (); + _imContext.ClientWindow = this.GdkWindow; + } public Size ClientSize { @@ -383,5 +383,10 @@ namespace Avalonia.Gtk Input(e); return true; } + + public void SetIcon(IIconImpl icon) + { + Icon = ((IconImpl)icon).Pixbuf; + } } } diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index 7a0578975c..6a80be28a7 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -43,6 +43,14 @@ ..\..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll True + + + + + ..\..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll ..\..\..\packages\System.Reactive.Interfaces.3.0.0\lib\net45\System.Reactive.Interfaces.dll @@ -56,6 +64,7 @@ Properties\SharedAssemblyInfo.cs + diff --git a/src/Windows/Avalonia.Win32/IconImpl.cs b/src/Windows/Avalonia.Win32/IconImpl.cs new file mode 100644 index 0000000000..56ab659800 --- /dev/null +++ b/src/Windows/Avalonia.Win32/IconImpl.cs @@ -0,0 +1,19 @@ +using Avalonia.Platform; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Win32 +{ + class IconImpl : IIconImpl + { + public IconImpl(System.Drawing.Icon icon) + { + Icon = icon; + } + + public System.Drawing.Icon Icon { get; } + } +} diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 6635882d4a..648126a20f 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -541,72 +541,72 @@ namespace Avalonia.Win32.Interop WM_DISPATCH_WORK_ITEM = WM_USER, } - public enum BitmapCompressionMode : uint - { - BI_RGB = 0, - BI_RLE8 = 1, - BI_RLE4 = 2, - BI_BITFIELDS = 3, - BI_JPEG = 4, - BI_PNG = 5 - } - - public enum DIBColorTable - { - DIB_RGB_COLORS = 0, /* color table in RGBs */ - DIB_PAL_COLORS /* color table in palette indices */ - }; - - [StructLayout(LayoutKind.Sequential)] - public struct RGBQUAD - { - public byte rgbBlue; - public byte rgbGreen; - public byte rgbRed; - public byte rgbReserved; - } - - [StructLayout(LayoutKind.Sequential)] - public struct BITMAPINFO - { - // C# cannot inlay structs in structs so must expand directly here - // - //[StructLayout(LayoutKind.Sequential)] - //public struct BITMAPINFOHEADER - //{ - public uint biSize; - public int biWidth; - public int biHeight; - public ushort biPlanes; - public ushort biBitCount; - public BitmapCompressionMode biCompression; - public uint biSizeImage; - public int biXPelsPerMeter; - public int biYPelsPerMeter; - public uint biClrUsed; - public uint biClrImportant; - //} - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] - public uint[] cols; - } - - public const int SizeOf_BITMAPINFOHEADER = 40; - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("gdi32.dll")] - public static extern int SetDIBitsToDevice(IntPtr hdc, int XDest, int YDest, - uint dwWidth, uint dwHeight, - int XSrc, int YSrc, - uint uStartScan, uint cScanLines, - IntPtr lpvBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse); - - [DllImport("user32.dll")] - public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("user32.dll", SetLastError = true)] + public enum BitmapCompressionMode : uint + { + BI_RGB = 0, + BI_RLE8 = 1, + BI_RLE4 = 2, + BI_BITFIELDS = 3, + BI_JPEG = 4, + BI_PNG = 5 + } + + public enum DIBColorTable + { + DIB_RGB_COLORS = 0, /* color table in RGBs */ + DIB_PAL_COLORS /* color table in palette indices */ + }; + + [StructLayout(LayoutKind.Sequential)] + public struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BITMAPINFO + { + // C# cannot inlay structs in structs so must expand directly here + // + //[StructLayout(LayoutKind.Sequential)] + //public struct BITMAPINFOHEADER + //{ + public uint biSize; + public int biWidth; + public int biHeight; + public ushort biPlanes; + public ushort biBitCount; + public BitmapCompressionMode biCompression; + public uint biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public uint biClrUsed; + public uint biClrImportant; + //} + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public uint[] cols; + } + + public const int SizeOf_BITMAPINFOHEADER = 40; + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("gdi32.dll")] + public static extern int SetDIBitsToDevice(IntPtr hdc, int XDest, int YDest, + uint dwWidth, uint dwHeight, + int XSrc, int YSrc, + uint uStartScan, uint cScanLines, + IntPtr lpvBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse); + + [DllImport("user32.dll")] + public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport("user32.dll", SetLastError = true)] public static extern bool AdjustWindowRectEx(ref RECT lpRect, uint dwStyle, bool bMenu, uint dwExStyle); [DllImport("user32.dll")] @@ -845,6 +845,10 @@ namespace Avalonia.Win32.Interop [DllImport("user32.dll")] public static extern IntPtr MonitorFromWindow(IntPtr hwnd, MONITOR dwFlags); + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + public enum MONITOR { MONITOR_DEFAULTTONULL = 0x00000000, @@ -1008,6 +1012,12 @@ namespace Avalonia.Win32.Interop E_OUTOFMEMORY = 0x8007000E } + public enum Icons + { + ICON_SMALL = 0, + ICON_BIG = 1 + } + public const uint SIGDN_FILESYSPATH = 0x80058000; [Flags] diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index c1e0260596..48c100df33 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -16,6 +16,7 @@ using Avalonia.Shared.PlatformSupport; using Avalonia.Win32.Input; using Avalonia.Win32.Interop; using Avalonia.Controls; +using System.IO; namespace Avalonia { @@ -31,7 +32,7 @@ namespace Avalonia namespace Avalonia.Win32 { - public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform + public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader { private static readonly Win32Platform s_instance = new Win32Platform(); private static Thread _uiThread; @@ -66,7 +67,8 @@ namespace Avalonia.Win32 .Bind().ToConstant(s_instance) .Bind().ToConstant(s_instance) .Bind().ToSingleton() - .Bind().ToConstant(s_instance); + .Bind().ToConstant(s_instance) + .Bind().ToConstant(s_instance); SharedPlatform.Register(); _uiThread = Thread.CurrentThread; @@ -186,5 +188,17 @@ namespace Avalonia.Win32 { return new PopupImpl(); } + + public IIconImpl LoadIcon(string fileName) + { + var icon = new System.Drawing.Icon(fileName); + return new IconImpl(icon); + } + + public IIconImpl LoadIcon(Stream stream) + { + var icon = new System.Drawing.Icon(stream); + return new IconImpl(icon); + } } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 55c6048b1f..67f1beb0f8 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -604,7 +604,7 @@ namespace Avalonia.Win32 hInstance = Marshal.GetHINSTANCE(GetType().Module), hCursor = DefaultCursor, hbrBackground = IntPtr.Zero, - lpszClassName = _className, + lpszClassName = _className }; ushort atom = UnmanagedMethods.RegisterClassEx(ref wndClassEx); @@ -681,5 +681,12 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, command); } + public void SetIcon(IIconImpl icon) + { + var impl = (IconImpl)icon; + var nativeIcon = impl.Icon; + UnmanagedMethods.PostMessage(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_SETICON, + new IntPtr((int)UnmanagedMethods.Icons.ICON_BIG), nativeIcon.Handle); + } } }