BrowserTopLevelImpl.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Runtime.Versioning;
  6. using Avalonia.Browser.Skia;
  7. using Avalonia.Browser.Storage;
  8. using Avalonia.Controls;
  9. using Avalonia.Controls.Platform;
  10. using Avalonia.Input;
  11. using Avalonia.Input.Platform;
  12. using Avalonia.Input.Raw;
  13. using Avalonia.Input.TextInput;
  14. using Avalonia.Platform;
  15. using Avalonia.Platform.Storage;
  16. using Avalonia.Rendering;
  17. using Avalonia.Rendering.Composition;
  18. [assembly: SupportedOSPlatform("browser")]
  19. namespace Avalonia.Browser
  20. {
  21. internal class BrowserTopLevelImpl : ITopLevelImpl
  22. {
  23. private Size _clientSize;
  24. private IInputRoot? _inputRoot;
  25. private readonly Stopwatch _sw = Stopwatch.StartNew();
  26. private readonly AvaloniaView _avaloniaView;
  27. private readonly TouchDevice _touchDevice;
  28. private readonly PenDevice _penDevice;
  29. private string _currentCursor = CssCursor.Default;
  30. private readonly INativeControlHostImpl _nativeControlHost;
  31. private readonly IStorageProvider _storageProvider;
  32. private readonly ISystemNavigationManagerImpl _systemNavigationManager;
  33. private readonly ClipboardImpl _clipboard;
  34. private readonly IInsetsManager? _insetsManager;
  35. public BrowserTopLevelImpl(AvaloniaView avaloniaView)
  36. {
  37. Surfaces = Enumerable.Empty<object>();
  38. _avaloniaView = avaloniaView;
  39. TransparencyLevel = WindowTransparencyLevel.None;
  40. AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1);
  41. _touchDevice = new TouchDevice();
  42. _penDevice = new PenDevice();
  43. _insetsManager = new BrowserInsetsManager();
  44. _nativeControlHost = _avaloniaView.GetNativeControlHostImpl();
  45. _storageProvider = new BrowserStorageProvider();
  46. _systemNavigationManager = new BrowserSystemNavigationManagerImpl();
  47. _clipboard = new ClipboardImpl();
  48. }
  49. public ulong Timestamp => (ulong)_sw.ElapsedMilliseconds;
  50. public void SetClientSize(Size newSize, double dpi)
  51. {
  52. if (Math.Abs(RenderScaling - dpi) > 0.0001)
  53. {
  54. if (Surfaces.FirstOrDefault() is BrowserSkiaSurface surface)
  55. {
  56. surface.Scaling = dpi;
  57. }
  58. ScalingChanged?.Invoke(dpi);
  59. }
  60. if (newSize != _clientSize)
  61. {
  62. _clientSize = newSize;
  63. if (Surfaces.FirstOrDefault() is BrowserSkiaSurface surface)
  64. {
  65. surface.Size = new PixelSize((int)newSize.Width, (int)newSize.Height);
  66. }
  67. Resized?.Invoke(newSize, WindowResizeReason.User);
  68. (_insetsManager as BrowserInsetsManager)?.NotifySafeAreaPaddingChanged();
  69. }
  70. }
  71. public bool RawPointerEvent(
  72. RawPointerEventType eventType, string pointerType,
  73. RawPointerPoint p, RawInputModifiers modifiers, long touchPointId,
  74. Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints = null)
  75. {
  76. if (_inputRoot is { }
  77. && Input is { } input)
  78. {
  79. var device = GetPointerDevice(pointerType);
  80. var args = device is TouchDevice ?
  81. new RawTouchEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers, touchPointId)
  82. {
  83. IntermediatePoints = intermediatePoints
  84. } :
  85. new RawPointerEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers)
  86. {
  87. RawPointerId = touchPointId,
  88. IntermediatePoints = intermediatePoints
  89. };
  90. input.Invoke(args);
  91. return args.Handled;
  92. }
  93. return false;
  94. }
  95. private IPointerDevice GetPointerDevice(string pointerType)
  96. {
  97. return pointerType switch
  98. {
  99. "touch" => _touchDevice,
  100. "pen" => _penDevice,
  101. _ => MouseDevice
  102. };
  103. }
  104. public bool RawMouseWheelEvent(Point p, Vector v, RawInputModifiers modifiers)
  105. {
  106. if (_inputRoot is { })
  107. {
  108. var args = new RawMouseWheelEventArgs(MouseDevice, Timestamp, _inputRoot, p, v, modifiers);
  109. Input?.Invoke(args);
  110. return args.Handled;
  111. }
  112. return false;
  113. }
  114. public bool RawKeyboardEvent(RawKeyEventType type, string code, string key, RawInputModifiers modifiers)
  115. {
  116. if (Keycodes.KeyCodes.TryGetValue(code, out var avkey))
  117. {
  118. if (_inputRoot is { })
  119. {
  120. var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers);
  121. Input?.Invoke(args);
  122. return args.Handled;
  123. }
  124. }
  125. else if (Keycodes.KeyCodes.TryGetValue(key, out avkey))
  126. {
  127. if (_inputRoot is { })
  128. {
  129. var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers);
  130. Input?.Invoke(args);
  131. return args.Handled;
  132. }
  133. }
  134. return false;
  135. }
  136. public bool RawTextEvent(string text)
  137. {
  138. if (_inputRoot is { })
  139. {
  140. var args = new RawTextInputEventArgs(KeyboardDevice, Timestamp, _inputRoot, text);
  141. Input?.Invoke(args);
  142. return args.Handled;
  143. }
  144. return false;
  145. }
  146. public DragDropEffects RawDragEvent(RawDragEventType eventType, Point position, RawInputModifiers modifiers, BrowserDataObject dataObject, DragDropEffects dropEffect)
  147. {
  148. var device = AvaloniaLocator.Current.GetRequiredService<IDragDropDevice>();
  149. var eventArgs = new RawDragEvent(device, eventType, _inputRoot!, position, dataObject, dropEffect, modifiers);
  150. Console.WriteLine($"{eventArgs.Location} {eventArgs.Effects} {eventArgs.Type} {eventArgs.KeyModifiers}");
  151. Input?.Invoke(eventArgs);
  152. return eventArgs.Effects;
  153. }
  154. public void Dispose()
  155. {
  156. }
  157. public IRenderer CreateRenderer(IRenderRoot root)
  158. {
  159. var loop = AvaloniaLocator.Current.GetRequiredService<IRenderLoop>();
  160. return new CompositingRenderer(root,
  161. new Compositor(loop, AvaloniaLocator.Current.GetRequiredService<IPlatformGraphics>()), () => Surfaces);
  162. }
  163. public void Invalidate(Rect rect)
  164. {
  165. //Console.WriteLine("invalidate rect called");
  166. }
  167. public void SetInputRoot(IInputRoot inputRoot)
  168. {
  169. _inputRoot = inputRoot;
  170. }
  171. public Point PointToClient(PixelPoint point) => new Point(point.X, point.Y);
  172. public PixelPoint PointToScreen(Point point) => new PixelPoint((int)point.X, (int)point.Y);
  173. public void SetCursor(ICursorImpl? cursor)
  174. {
  175. var val = (cursor as CssCursor)?.Value ?? CssCursor.Default;
  176. if (_currentCursor != val)
  177. {
  178. SetCssCursor?.Invoke(val);
  179. _currentCursor = val;
  180. }
  181. }
  182. public IPopupImpl? CreatePopup()
  183. {
  184. return null;
  185. }
  186. public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel)
  187. {
  188. }
  189. public Size ClientSize => _clientSize;
  190. public Size? FrameSize => null;
  191. public double RenderScaling => (Surfaces.FirstOrDefault() as BrowserSkiaSurface)?.Scaling ?? 1;
  192. public IEnumerable<object> Surfaces { get; set; }
  193. public Action<string>? SetCssCursor { get; set; }
  194. public Action<RawInputEventArgs>? Input { get; set; }
  195. public Action<Rect>? Paint { get; set; }
  196. public Action<Size, WindowResizeReason>? Resized { get; set; }
  197. public Action<double>? ScalingChanged { get; set; }
  198. public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
  199. public Action? Closed { get; set; }
  200. public Action? LostFocus { get; set; }
  201. public IMouseDevice MouseDevice { get; } = new MouseDevice();
  202. public IKeyboardDevice KeyboardDevice { get; } = BrowserWindowingPlatform.Keyboard;
  203. public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
  204. public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
  205. {
  206. // not in the standard, but we potentially can use "apple-mobile-web-app-status-bar-style" for iOS and "theme-color" for android.
  207. }
  208. public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; }
  209. public object? TryGetFeature(Type featureType)
  210. {
  211. if (featureType == typeof(IStorageProvider))
  212. {
  213. return _storageProvider;
  214. }
  215. if (featureType == typeof(ITextInputMethodImpl))
  216. {
  217. return _avaloniaView;
  218. }
  219. if (featureType == typeof(ISystemNavigationManagerImpl))
  220. {
  221. return _systemNavigationManager;
  222. }
  223. if (featureType == typeof(INativeControlHostImpl))
  224. {
  225. return _nativeControlHost;
  226. }
  227. if (featureType == typeof(IInsetsManager))
  228. {
  229. return _insetsManager;
  230. }
  231. if (featureType == typeof(IClipboard))
  232. {
  233. return _clipboard;
  234. }
  235. return null;
  236. }
  237. }
  238. }