Browse Source

Merge branch 'master' into more-skia-caching

pull/10303/head
DJGosnell 4 years ago
committed by GitHub
parent
commit
3f577d1654
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  2. 2
      native/Avalonia.Native/src/OSX/PopupImpl.mm
  3. 5
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  4. 29
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  5. 6
      native/Avalonia.Native/src/OSX/WindowImpl.h
  6. 101
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  7. 1
      samples/IntegrationTestApp/MainWindow.axaml
  8. 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  9. 4
      samples/MobileSandbox/MainView.xaml
  10. 42
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  11. 1
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  12. 127
      src/Android/Avalonia.Android/InputEditable.cs
  13. 2
      src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
  14. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  15. 141
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  16. 4
      src/Android/Avalonia.Android/PlatformIconLoader.cs
  17. 6
      src/Android/Avalonia.Android/Stubs.cs
  18. 60
      src/Avalonia.Base/AvaloniaObject.cs
  19. 50
      src/Avalonia.Base/AvaloniaProperty.cs
  20. 23
      src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
  21. 5
      src/Avalonia.Base/DirectPropertyBase.cs
  22. 23
      src/Avalonia.Base/Input/TextInput/ITextEditable.cs
  23. 11
      src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs
  24. 6
      src/Avalonia.Base/PropertyStore/EffectiveValue.cs
  25. 36
      src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
  26. 50
      src/Avalonia.Base/PropertyStore/ValueStore.cs
  27. 4
      src/Avalonia.Base/StyledElement.cs
  28. 46
      src/Avalonia.Base/StyledProperty.cs
  29. 7
      src/Avalonia.Controls/ItemsControl.cs
  30. 33
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  31. 117
      src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
  32. 2
      src/Avalonia.FreeDesktop/DBusHelper.cs
  33. 2
      src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs
  34. 2
      src/Avalonia.FreeDesktop/DBusMenuExporter.cs
  35. 6
      src/Avalonia.FreeDesktop/IX11InputMethod.cs
  36. 2
      src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs
  37. 2
      src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs
  38. 2
      src/Avalonia.Native/CallbackBase.cs
  39. 2
      src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs
  40. 2
      src/Avalonia.Native/MenuActionCallback.cs
  41. 2
      src/Avalonia.Native/PredicateCallback.cs
  42. 2
      src/Avalonia.Native/ScreenImpl.cs
  43. 2
      src/Avalonia.X11/Glx/Glx.cs
  44. 2
      src/Avalonia.X11/Glx/GlxConsts.cs
  45. 6
      src/Avalonia.X11/Glx/GlxContext.cs
  46. 8
      src/Avalonia.X11/Glx/GlxDisplay.cs
  47. 8
      src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
  48. 2
      src/Avalonia.X11/Glx/GlxPlatformFeature.cs
  49. 2
      src/Avalonia.X11/Keysyms.cs
  50. 29
      src/Avalonia.X11/NativeDialogs/Gtk.cs
  51. 2
      src/Avalonia.X11/TransparencyHelper.cs
  52. 16
      src/Avalonia.X11/X11Clipboard.cs
  53. 4
      src/Avalonia.X11/X11CursorFactory.cs
  54. 8
      src/Avalonia.X11/X11Enums.cs
  55. 2
      src/Avalonia.X11/X11Exception.cs
  56. 2
      src/Avalonia.X11/X11Framebuffer.cs
  57. 2
      src/Avalonia.X11/X11FramebufferSurface.cs
  58. 12
      src/Avalonia.X11/X11Globals.cs
  59. 8
      src/Avalonia.X11/X11IconLoader.cs
  60. 2
      src/Avalonia.X11/X11Info.cs
  61. 2
      src/Avalonia.X11/X11KeyTransform.cs
  62. 10
      src/Avalonia.X11/X11NativeControlHost.cs
  63. 8
      src/Avalonia.X11/X11Platform.cs
  64. 32
      src/Avalonia.X11/X11PlatformThreading.cs
  65. 20
      src/Avalonia.X11/X11Screens.cs
  66. 9
      src/Avalonia.X11/X11Structs.cs
  67. 32
      src/Avalonia.X11/X11Window.Ime.cs
  68. 4
      src/Avalonia.X11/X11Window.Xim.cs
  69. 46
      src/Avalonia.X11/X11Window.cs
  70. 5
      src/Avalonia.X11/XError.cs
  71. 16
      src/Avalonia.X11/XI2Manager.cs
  72. 54
      src/Avalonia.X11/XIStructs.cs
  73. 10
      src/Avalonia.X11/XLib.cs
  74. 27
      src/Browser/Avalonia.Browser/AvaloniaView.cs
  75. 2
      src/Browser/Avalonia.Browser/Interop/InputHelper.cs
  76. 2
      src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
  77. 20
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts
  78. 4
      src/Shared/RawEventGrouping.cs
  79. 5
      src/Skia/Avalonia.Skia/GlyphRunImpl.cs
  80. 4
      src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
  81. 2
      src/Skia/Avalonia.Skia/SKTypefaceCollection.cs
  82. 2
      src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs
  83. 22
      src/Skia/Avalonia.Skia/readme.md
  84. 6
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  85. 2
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  86. 33
      src/Windows/Avalonia.Direct2D1/Disposable.cs
  87. 2
      src/Windows/Avalonia.Direct2D1/ILayerFactory.cs
  88. 4
      src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs
  89. 4
      src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs
  90. 2
      src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs
  91. 4
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  92. 4
      src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs
  93. 4
      src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
  94. 4
      src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
  95. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs
  96. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs
  97. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
  98. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
  99. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs
  100. 2
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs

17
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -223,6 +223,19 @@
}
}
// From chromium:
//
// > The delegate or the window class should implement this method so that
// > -[NSWindow isZoomed] can be then determined by whether or not the current
// > window frame is equal to the zoomed frame.
//
// If we don't implement this, then isZoomed always returns true for a non-
// resizable window ¯\_(ツ)_/¯
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
defaultFrame:(NSRect)newFrame {
return newFrame;
}
-(BOOL)canBecomeKeyWindow
{
if(_canBecomeKeyWindow)
@ -261,10 +274,6 @@
-(void) setEnabled:(bool)enable
{
_isEnabled = enable;
[[self standardWindowButton:NSWindowCloseButton] setEnabled:enable];
[[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:enable];
[[self standardWindowButton:NSWindowZoomButton] setEnabled:enable];
}
-(void)becomeKeyWindow

2
native/Avalonia.Native/src/OSX/PopupImpl.mm

@ -29,7 +29,7 @@ private:
[Window setLevel:NSPopUpMenuWindowLevel];
}
protected:
virtual NSWindowStyleMask GetStyle() override
virtual NSWindowStyleMask CalculateStyleMask() override
{
return NSWindowStyleMaskBorderless;
}

5
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@ -105,9 +105,8 @@ BEGIN_INTERFACE_MAP()
virtual void BringToFront ();
protected:
virtual NSWindowStyleMask GetStyle();
void UpdateStyle();
virtual NSWindowStyleMask CalculateStyleMask() = 0;
virtual void UpdateStyle();
private:
void CreateNSWindow (bool isDialog);

29
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@ -35,18 +35,14 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl,
lastSize = NSSize { 100, 100 };
lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX};
lastMinSize = NSSize { 0, 0 };
lastMenu = nullptr;
CreateNSWindow(usePanel);
[Window setContentView:StandardContainer];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];
[Window setContentMinSize:lastMinSize];
[Window setContentMaxSize:lastMaxSize];
[Window setOpaque:false];
}
@ -564,12 +560,8 @@ bool WindowBaseImpl::IsModal() {
return false;
}
NSWindowStyleMask WindowBaseImpl::GetStyle() {
return NSWindowStyleMaskBorderless;
}
void WindowBaseImpl::UpdateStyle() {
[Window setStyleMask:GetStyle()];
[Window setStyleMask:CalculateStyleMask()];
}
void WindowBaseImpl::CleanNSWindow() {
@ -580,21 +572,12 @@ void WindowBaseImpl::CleanNSWindow() {
}
}
void WindowBaseImpl::CreateNSWindow(bool isDialog) {
if (isDialog) {
if (![Window isKindOfClass:[AvnPanel class]]) {
CleanNSWindow();
Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()];
[Window setHidesOnDeactivate:false];
}
void WindowBaseImpl::CreateNSWindow(bool usePanel) {
if (usePanel) {
Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:NSWindowStyleMaskBorderless];
[Window setHidesOnDeactivate:false];
} else {
if (![Window isKindOfClass:[AvnWindow class]]) {
CleanNSWindow();
Window = [[AvnWindow alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()];
}
Window = [[AvnWindow alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:NSWindowStyleMaskBorderless];
}
}

6
native/Avalonia.Native/src/OSX/WindowImpl.h

@ -41,8 +41,6 @@ BEGIN_INTERFACE_MAP()
WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl);
void HideOrShowTrafficLights ();
virtual HRESULT Show (bool activate, bool isDialog) override;
virtual HRESULT SetEnabled (bool enable) override;
@ -100,9 +98,11 @@ BEGIN_INTERFACE_MAP()
bool CanBecomeKeyWindow ();
protected:
virtual NSWindowStyleMask GetStyle() override;
virtual NSWindowStyleMask CalculateStyleMask() override;
void UpdateStyle () override;
private:
void ZOrderChildWindows();
void OnInitialiseNSWindow();
NSString *_lastTitle;
};

101
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -30,19 +30,6 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase
OnInitialiseNSWindow();
}
void WindowImpl::HideOrShowTrafficLights() {
if (Window == nil) {
return;
}
bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations == SystemDecorationsFull;
[[Window standardWindowButton:NSWindowCloseButton] setHidden:!hasTrafficLights];
[[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:!hasTrafficLights];
[[Window standardWindowButton:NSWindowZoomButton] setHidden:!hasTrafficLights];
}
void WindowImpl::OnInitialiseNSWindow(){
[GetWindowProtocol() setCanBecomeKeyWindow:true];
@ -67,8 +54,6 @@ HRESULT WindowImpl::Show(bool activate, bool isDialog) {
WindowBaseImpl::Show(activate, isDialog);
GetWindowState(&_actualWindowState);
HideOrShowTrafficLights();
return SetWindowState(_lastWindowState);
}
}
@ -134,14 +119,19 @@ void WindowImpl::BringToFront()
}
[Window invalidateShadow];
ZOrderChildWindows();
}
}
void WindowImpl::ZOrderChildWindows()
{
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
auto window = (*iterator)->Window;
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
auto window = (*iterator)->Window;
// #9565: Only bring window to front if it's on the currently active space
if ([window isOnActiveSpace])
(*iterator)->BringToFront();
// #9565: Only bring window to front if it's on the currently active space
if ([window isOnActiveSpace]) {
(*iterator)->BringToFront();
}
}
}
@ -161,13 +151,15 @@ bool WindowImpl::CanBecomeKeyWindow()
void WindowImpl::StartStateTransition() {
_transitioningWindowState = true;
UpdateStyle();
}
void WindowImpl::EndStateTransition() {
_transitioningWindowState = false;
UpdateStyle();
// Ensure correct order of child windows after fullscreen transition.
BringToFront();
ZOrderChildWindows();
}
SystemDecorations WindowImpl::Decorations() {
@ -225,16 +217,12 @@ bool WindowImpl::IsZoomed() {
}
void WindowImpl::DoZoom() {
switch (_decorations) {
case SystemDecorationsNone:
case SystemDecorationsBorderOnly:
[Window setFrame:[Window screen].visibleFrame display:true];
break;
case SystemDecorationsFull:
[Window performZoom:Window];
break;
if (_decorations == SystemDecorationsNone ||
_decorations == SystemDecorationsBorderOnly ||
_canResize == false) {
[Window setFrame:[Window screen].visibleFrame display:true];
} else {
[Window performZoom:Window];
}
}
@ -261,8 +249,6 @@ HRESULT WindowImpl::SetDecorations(SystemDecorations value) {
UpdateStyle();
HideOrShowTrafficLights();
switch (_decorations) {
case SystemDecorationsNone:
[Window setHasShadow:NO];
@ -419,9 +405,6 @@ HRESULT WindowImpl::SetExtendClientArea(bool enable) {
}
[GetWindowProtocol() setIsExtended:enable];
HideOrShowTrafficLights();
UpdateStyle();
}
@ -577,14 +560,16 @@ bool WindowImpl::IsOwned() {
return _parent != nullptr;
}
NSWindowStyleMask WindowImpl::GetStyle() {
unsigned long s = NSWindowStyleMaskBorderless;
NSWindowStyleMask WindowImpl::CalculateStyleMask() {
// Use the current style mask and only clear the flags we're going to be modifying.
unsigned long s = [Window styleMask] &
~(NSWindowStyleMaskFullSizeContentView |
NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskResizable |
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskTexturedBackground);
if(_actualWindowState == FullScreen)
{
s |= NSWindowStyleMaskFullScreen;
}
switch (_decorations) {
case SystemDecorationsNone:
s = s | NSWindowStyleMaskFullSizeContentView;
@ -597,7 +582,7 @@ NSWindowStyleMask WindowImpl::GetStyle() {
case SystemDecorationsFull:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
if (_canResize && _isEnabled) {
if ((_canResize && _isEnabled) || _transitioningWindowState) {
s = s | NSWindowStyleMaskResizable;
}
break;
@ -612,3 +597,25 @@ NSWindowStyleMask WindowImpl::GetStyle() {
}
return s;
}
void WindowImpl::UpdateStyle() {
WindowBaseImpl::UpdateStyle();
if (Window == nil) {
return;
}
bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations == SystemDecorationsFull;
NSButton* closeButton = [Window standardWindowButton:NSWindowCloseButton];
NSButton* miniaturizeButton = [Window standardWindowButton:NSWindowMiniaturizeButton];
NSButton* zoomButton = [Window standardWindowButton:NSWindowZoomButton];
[closeButton setHidden:!hasTrafficLights];
[closeButton setEnabled:_isEnabled];
[miniaturizeButton setHidden:!hasTrafficLights];
[miniaturizeButton setEnabled:_isEnabled];
[zoomButton setHidden:!hasTrafficLights];
[zoomButton setEnabled:_isEnabled && _canResize];
}

1
samples/IntegrationTestApp/MainWindow.axaml

@ -140,6 +140,7 @@
<ComboBoxItem Name="ShowWindowStateMaximized">Maximized</ComboBoxItem>
<ComboBoxItem Name="ShowWindowStateFullScreen">FullScreen</ComboBoxItem>
</ComboBox>
<CheckBox Name="ShowWindowCanResize" IsChecked="True">Can Resize</CheckBox>
<Button Name="ShowWindow">Show Window</Button>
<Button Name="SendToBack">Send to Back</Button>
<Button Name="EnterFullscreen">Enter Fullscreen</Button>

2
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -66,11 +66,13 @@ namespace IntegrationTestApp
var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation");
var stateComboBox = this.GetControl<ComboBox>("ShowWindowState");
var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null;
var canResizeCheckBox = this.GetControl<CheckBox>("ShowWindowCanResize");
var owner = (Window)this.GetVisualRoot()!;
var window = new ShowWindowTest
{
WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex,
CanResize = canResizeCheckBox.IsChecked.Value,
};
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)

4
samples/MobileSandbox/MainView.xaml

@ -5,8 +5,8 @@
x:DataType="mobileSandbox:MainView">
<StackPanel Margin="100 50" Spacing="50">
<TextBlock Text="Login" Foreground="White" />
<TextBox Watermark="Text" />
<TextBox Watermark="Username" TextInputOptions.ContentType="Email" AcceptsReturn="True" TextInputOptions.ReturnKeyType="Search" />
<TextBox TextInputOptions.Multiline="True" AcceptsReturn="True" Watermark="Text" Height="200" TextWrapping="Wrap"/>
<TextBox Watermark="Username" TextInputOptions.ContentType="Email" TextInputOptions.ReturnKeyType="Done" />
<TextBox Watermark="Password" PasswordChar="*" TextInputOptions.ContentType="Password" />
<TextBox Watermark="Pin" PasswordChar="*" TextInputOptions.ContentType="Digits" />
<Button Content="Login" Command="{Binding ButtonCommand}" />

42
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -5,8 +5,10 @@ using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Controls.Presenters;
using Avalonia.Input;
using Avalonia.Input.TextInput;
using Avalonia.Reactive;
namespace Avalonia.Android
{
@ -32,7 +34,7 @@ namespace Avalonia.Android
ActionPrevious = 0x00000007,
}
class AndroidInputMethod<TView> : ITextInputMethodImpl, IAndroidInputMethod
internal class AndroidInputMethod<TView> : ITextInputMethodImpl, IAndroidInputMethod
where TView : View, IInitEditorInfo
{
private readonly TView _host;
@ -68,23 +70,10 @@ namespace Avalonia.Android
public void SetClient(ITextInputMethodClient client)
{
if (_client != null)
{
_client.SurroundingTextChanged -= SurroundingTextChanged;
}
if(_inputConnection != null)
{
_inputConnection.ComposingText = null;
_inputConnection.ComposingRegion = default;
}
_client = client;
if (IsActive)
{
_client.SurroundingTextChanged += SurroundingTextChanged;
_host.RequestFocus();
_imm.RestartInput(View);
@ -101,24 +90,6 @@ namespace Avalonia.Android
}
}
private void SurroundingTextChanged(object sender, EventArgs e)
{
if (IsActive && _inputConnection != null)
{
var surroundingText = Client.SurroundingText;
_inputConnection.SurroundingText = surroundingText;
_imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
if (_inputConnection.ComposingText != null && !_inputConnection.IsCommiting && surroundingText.AnchorOffset == surroundingText.CursorOffset)
{
_inputConnection.CommitText(_inputConnection.ComposingText, 0);
_inputConnection.SetSelection(surroundingText.AnchorOffset, surroundingText.CursorOffset);
}
}
}
public void SetCursorRect(Rect rect)
{
@ -157,17 +128,20 @@ namespace Avalonia.Android
TextInputReturnKeyType.Search => (ImeFlags)CustomImeFlags.ActionSearch,
TextInputReturnKeyType.Next => (ImeFlags)CustomImeFlags.ActionNext,
TextInputReturnKeyType.Previous => (ImeFlags)CustomImeFlags.ActionPrevious,
_ => (ImeFlags)CustomImeFlags.ActionDone
TextInputReturnKeyType.Done => (ImeFlags)CustomImeFlags.ActionDone,
_ => options.Multiline ? ImeFlags.NoEnterAction : (ImeFlags)CustomImeFlags.ActionDone
};
outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi;
_client.TextEditable = _inputConnection.InputEditable;
return _inputConnection;
});
}
}
public readonly record struct ComposingRegion
internal readonly record struct ComposingRegion
{
private readonly int _start = -1;
private readonly int _end = -1;

1
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -5,6 +5,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<DebugType>portable</DebugType>
<AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />

127
src/Android/Avalonia.Android/InputEditable.cs

@ -0,0 +1,127 @@
using System;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Controls.Presenters;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Java.Lang;
using static System.Net.Mime.MediaTypeNames;
namespace Avalonia.Android
{
internal class InputEditable : SpannableStringBuilder, ITextEditable
{
private readonly TopLevelImpl _topLevel;
private readonly IAndroidInputMethod _inputMethod;
private readonly AvaloniaInputConnection _avaloniaInputConnection;
private int _currentBatchLevel;
private string _previousText;
private int _previousSelectionStart;
private int _previousSelectionEnd;
public event EventHandler TextChanged;
public event EventHandler SelectionChanged;
public event EventHandler CompositionChanged;
public InputEditable(TopLevelImpl topLevel, IAndroidInputMethod inputMethod, AvaloniaInputConnection avaloniaInputConnection)
{
_topLevel = topLevel;
_inputMethod = inputMethod;
_avaloniaInputConnection = avaloniaInputConnection;
}
public InputEditable(ICharSequence text) : base(text)
{
}
public InputEditable(string text) : base(text)
{
}
public InputEditable(ICharSequence text, int start, int end) : base(text, start, end)
{
}
public InputEditable(string text, int start, int end) : base(text, start, end)
{
}
protected InputEditable(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public int SelectionStart
{
get => Selection.GetSelectionStart(this); set
{
var end = SelectionEnd < 0 ? 0 : SelectionEnd;
_avaloniaInputConnection.SetSelection(value, end);
_inputMethod.IMM.UpdateSelection(_topLevel.View, value, end, value, end);
}
}
public int SelectionEnd
{
get => Selection.GetSelectionEnd(this); set
{
var start = SelectionStart < 0 ? 0 : SelectionStart;
_avaloniaInputConnection.SetSelection(start, value);
_inputMethod.IMM.UpdateSelection(_topLevel.View, start, value, start, value);
}
}
public string? Text
{
get => ToString(); set
{
if (Text != value)
{
Clear();
Insert(0, value ?? "");
}
}
}
public int CompositionStart => BaseInputConnection.GetComposingSpanStart(this);
public int CompositionEnd => BaseInputConnection.GetComposingSpanEnd(this);
public void BeginBatchEdit()
{
_currentBatchLevel++;
if (_currentBatchLevel == 1)
{
_previousText = ToString();
_previousSelectionStart = SelectionStart;
_previousSelectionEnd = SelectionEnd;
}
}
public void EndBatchEdit()
{
if (_currentBatchLevel == 1)
{
if(_previousText != Text)
{
TextChanged?.Invoke(this, EventArgs.Empty);
}
if (_previousSelectionStart != SelectionStart || _previousSelectionEnd != SelectionEnd)
{
SelectionChanged?.Invoke(this, EventArgs.Empty);
}
}
_currentBatchLevel--;
}
public void RaiseCompositionChanged()
{
CompositionChanged?.Invoke(this, EventArgs.Empty);
}
}
}

2
src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs

@ -5,7 +5,7 @@ using Avalonia.Input;
namespace Avalonia.Android.Platform.Input
{
public class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
{
// { Keycode.Cancel?, Key.Cancel },

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -10,7 +10,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
{
bool _invalidateQueued;
readonly object _lock = new object();

141
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -28,6 +28,7 @@ using Math = System.Math;
using AndroidRect = Android.Graphics.Rect;
using Window = Android.Views.Window;
using Android.Graphics.Drawables;
using Java.Util;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@ -410,159 +411,73 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
private readonly TopLevelImpl _topLevel;
private readonly IAndroidInputMethod _inputMethod;
private readonly InputEditable _editable;
public AvaloniaInputConnection(TopLevelImpl topLevel, IAndroidInputMethod inputMethod) : base(inputMethod.View, true)
{
_topLevel = topLevel;
_inputMethod = inputMethod;
_editable = new InputEditable(_topLevel, _inputMethod, this);
}
public TextInputMethodSurroundingText SurroundingText { get; set; }
public override IEditable Editable => _editable;
public string ComposingText { get; internal set; }
public ComposingRegion? ComposingRegion { get; internal set; }
public bool IsComposing => !string.IsNullOrEmpty(ComposingText);
public bool IsCommiting { get; private set; }
internal InputEditable InputEditable => _editable;
public override bool SetComposingRegion(int start, int end)
{
//System.Diagnostics.Debug.WriteLine($"Composing Region: [{start}|{end}] {SurroundingText.Text?.Substring(start, end - start)}");
var ret = base.SetComposingRegion(start, end);
ComposingRegion = new ComposingRegion(start, end);
InputEditable.RaiseCompositionChanged();
return base.SetComposingRegion(start, end);
return ret;
}
public override bool SetComposingText(ICharSequence text, int newCursorPosition)
{
var composingText = text.ToString();
ComposingText = composingText;
_inputMethod.Client?.SetPreeditText(ComposingText);
return base.SetComposingText(text, newCursorPosition);
}
public override bool FinishComposingText()
{
if (!string.IsNullOrEmpty(ComposingText))
if (string.IsNullOrEmpty(composingText))
{
CommitText(ComposingText, ComposingText.Length);
return CommitText(text, newCursorPosition);
}
else
{
ComposingRegion = new ComposingRegion(SurroundingText.CursorOffset, SurroundingText.CursorOffset);
}
return base.FinishComposingText();
}
public override ICharSequence GetTextBeforeCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
{
if (!string.IsNullOrEmpty(SurroundingText.Text) && length > 0)
{
var start = System.Math.Max(SurroundingText.CursorOffset - length, 0);
var ret = base.SetComposingText(text, newCursorPosition);
var end = System.Math.Min(start + length - 1, SurroundingText.CursorOffset);
InputEditable.RaiseCompositionChanged();
var text = SurroundingText.Text.Substring(start, end - start);
//System.Diagnostics.Debug.WriteLine($"Text Before: {text}");
return new Java.Lang.String(text);
return ret;
}
return null;
}
public override ICharSequence GetTextAfterCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
public override bool BeginBatchEdit()
{
if (!string.IsNullOrEmpty(SurroundingText.Text))
{
var start = SurroundingText.CursorOffset;
var end = System.Math.Min(start + length, SurroundingText.Text.Length);
var text = SurroundingText.Text.Substring(start, end - start);
_editable.BeginBatchEdit();
//System.Diagnostics.Debug.WriteLine($"Text After: {text}");
return new Java.Lang.String(text);
}
return null;
return base.BeginBatchEdit();
}
public override bool CommitText(ICharSequence text, int newCursorPosition)
public override bool EndBatchEdit()
{
IsCommiting = true;
var committedText = text.ToString();
_inputMethod.Client.SetPreeditText(null);
var ret = base.EndBatchEdit();
_editable.EndBatchEdit();
int? start, end;
if(SurroundingText.CursorOffset != SurroundingText.AnchorOffset)
{
start = Math.Min(SurroundingText.CursorOffset, SurroundingText.AnchorOffset);
end = Math.Max(SurroundingText.CursorOffset, SurroundingText.AnchorOffset);
}
else if (ComposingRegion != null)
{
start = ComposingRegion?.Start;
end = ComposingRegion?.End;
ComposingRegion = null;
}
else
{
start = end = _inputMethod.Client.SurroundingText.CursorOffset;
}
_inputMethod.Client.SelectInSurroundingText((int)start, (int)end);
var time = DateTime.Now.TimeOfDay;
var rawTextEvent = new RawTextInputEventArgs(KeyboardDevice.Instance, (ulong)time.Ticks, _topLevel.InputRoot, committedText);
_topLevel.Input(rawTextEvent);
ComposingText = null;
ComposingRegion = new ComposingRegion(newCursorPosition, newCursorPosition);
return base.CommitText(text, newCursorPosition);
return ret;
}
public override bool DeleteSurroundingText(int beforeLength, int afterLength)
public override bool FinishComposingText()
{
var surroundingText = _inputMethod.Client.SurroundingText;
var selectionStart = surroundingText.CursorOffset;
_inputMethod.Client.SelectInSurroundingText(selectionStart - beforeLength, selectionStart + afterLength);
_inputMethod.View.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.ForwardDel));
surroundingText = _inputMethod.Client.SurroundingText;
selectionStart = surroundingText.CursorOffset;
ComposingRegion = new ComposingRegion(selectionStart, selectionStart);
return base.DeleteSurroundingText(beforeLength, afterLength);
var ret = base.FinishComposingText();
InputEditable.RaiseCompositionChanged();
return ret;
}
public override bool SetSelection(int start, int end)
public override bool CommitText(ICharSequence text, int newCursorPosition)
{
_inputMethod.Client.SelectInSurroundingText(start, end);
ComposingRegion = new ComposingRegion(start, end);
return base.SetSelection(start, end);
var ret = base.CommitText(text, newCursorPosition);
InputEditable.RaiseCompositionChanged();
return ret;
}
public override bool PerformEditorAction([GeneratedEnum] ImeAction actionCode)

4
src/Android/Avalonia.Android/PlatformIconLoader.cs

@ -3,7 +3,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
class PlatformIconLoader : IPlatformIconLoader
internal class PlatformIconLoader : IPlatformIconLoader
{
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
{
@ -29,7 +29,7 @@ namespace Avalonia.Android
}
// Stores the icon created as a stream to support saving even though an icon is never shown
public class FakeIcon : IWindowIconImpl
internal class FakeIcon : IWindowIconImpl
{
private Stream stream = new MemoryStream();

6
src/Android/Avalonia.Android/Stubs.cs

@ -4,7 +4,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
class WindowingPlatformStub : IWindowingPlatform
internal class WindowingPlatformStub : IWindowingPlatform
{
public IWindowImpl CreateWindow() => throw new NotSupportedException();
@ -13,7 +13,7 @@ namespace Avalonia.Android
public ITrayIconImpl CreateTrayIcon() => null;
}
class PlatformIconLoaderStub : IPlatformIconLoader
internal class PlatformIconLoaderStub : IPlatformIconLoader
{
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
{
@ -38,7 +38,7 @@ namespace Avalonia.Android
}
}
public class IconStub : IWindowIconImpl
internal class IconStub : IWindowIconImpl
{
private readonly MemoryStream _ms;

60
src/Avalonia.Base/AvaloniaObject.cs

@ -118,7 +118,7 @@ namespace Avalonia
{
_ = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
/// <summary>
@ -152,7 +152,7 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
/// <summary>
@ -329,7 +329,7 @@ namespace Avalonia
if (value is UnsetValueType)
{
if (priority == BindingPriority.LocalValue)
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
else if (value is not DoNothingType)
{
@ -355,6 +355,57 @@ namespace Avalonia
SetDirectValueUnchecked(property, value);
}
/// <summary>
/// Sets the value of a dependency property without changing its value source.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <remarks>
/// This method is used by a component that programmatically sets the value of one of its
/// own properties without disabling an application's declared use of the property. The
/// method changes the effective value of the property, but existing data bindings and
/// styles will continue to work.
///
/// The new value will have the property's current <see cref="BindingPriority"/>, even if
/// that priority is <see cref="BindingPriority.Unset"/> or
/// <see cref="BindingPriority.Inherited"/>.
/// </remarks>
public void SetCurrentValue(AvaloniaProperty property, object? value) =>
property.RouteSetCurrentValue(this, value);
/// <summary>
/// Sets the value of a dependency property without changing its value source.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <remarks>
/// This method is used by a component that programmatically sets the value of one of its
/// own properties without disabling an application's declared use of the property. The
/// method changes the effective value of the property, but existing data bindings and
/// styles will continue to work.
///
/// The new value will have the property's current <see cref="BindingPriority"/>, even if
/// that priority is <see cref="BindingPriority.Unset"/> or
/// <see cref="BindingPriority.Inherited"/>.
/// </remarks>
public void SetCurrentValue<T>(StyledProperty<T> property, T value)
{
_ = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
LogPropertySet(property, value, BindingPriority.LocalValue);
if (value is UnsetValueType)
{
_values.ClearValue(property);
}
else if (value is not DoNothingType)
{
_values.SetCurrentValue(property, value);
}
}
/// <summary>
/// Binds a <see cref="AvaloniaProperty"/> to an observable.
/// </summary>
@ -547,7 +598,8 @@ namespace Avalonia
property,
GetValue(property),
BindingPriority.LocalValue,
null);
null,
false);
}
return _values.GetDiagnostic(property);

50
src/Avalonia.Base/AvaloniaProperty.cs

@ -225,13 +225,8 @@ namespace Avalonia
/// <param name="defaultValue">The default value of the property.</param>
/// <param name="inherits">Whether the property inherits its value.</param>
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <param name="validate">A value validation callback.</param>
/// <param name="validate">A value validation callback.</param>
/// <param name="coerce">A value coercion callback.</param>
/// <param name="notifying">
/// A method that gets called before and after the property starts being notified on an
/// object; the bool argument will be true before and false afterwards. This callback is
/// intended to support IsDataContextChanging.
/// </param>
/// <returns>A <see cref="StyledProperty{TValue}"/></returns>
public static StyledProperty<TValue> Register<TOwner, TValue>(
string name,
@ -239,8 +234,40 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<AvaloniaObject, TValue, TValue>? coerce = null,
Action<AvaloniaObject, bool>? notifying = null)
Func<AvaloniaObject, TValue, TValue>? coerce = null)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
var metadata = new StyledPropertyMetadata<TValue>(
defaultValue,
defaultBindingMode: defaultBindingMode,
coerce: coerce);
var result = new StyledProperty<TValue>(
name,
typeof(TOwner),
metadata,
inherits,
validate);
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
}
/// <inheritdoc cref="Register{TOwner, TValue}" />
/// <param name="notifying">
/// A method that gets called before and after the property starts being notified on an
/// object; the bool argument will be true before and false afterwards. This callback is
/// intended to support IsDataContextChanging.
/// </param>
internal static StyledProperty<TValue> Register<TOwner, TValue>(
string name,
TValue defaultValue,
bool inherits,
BindingMode defaultBindingMode,
Func<TValue, bool>? validate,
Func<AvaloniaObject, TValue, TValue>? coerce,
Action<AvaloniaObject, bool>? notifying)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -496,6 +523,13 @@ namespace Avalonia
object? value,
BindingPriority priority);
/// <summary>
/// Routes an untyped SetCurrentValue call to a typed call.
/// </summary>
/// <param name="o">The object instance.</param>
/// <param name="value">The value.</param>
internal abstract void RouteSetCurrentValue(AvaloniaObject o, object? value);
/// <summary>
/// Routes an untyped Bind call to a typed call.
/// </summary>

23
src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs

@ -3,28 +3,23 @@ using Avalonia.Data;
namespace Avalonia.Diagnostics
{
/// <summary>
/// Holds diagnostic-related information about the value of a <see cref="AvaloniaProperty"/>
/// on a <see cref="AvaloniaObject"/>.
/// Holds diagnostic-related information about the value of an <see cref="AvaloniaProperty"/>
/// on an <see cref="AvaloniaObject"/>.
/// </summary>
public class AvaloniaPropertyValue
{
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaPropertyValue"/> class.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The current property value.</param>
/// <param name="priority">The priority of the current value.</param>
/// <param name="diagnostic">A diagnostic string.</param>
public AvaloniaPropertyValue(
internal AvaloniaPropertyValue(
AvaloniaProperty property,
object? value,
BindingPriority priority,
string? diagnostic)
string? diagnostic,
bool isOverriddenCurrentValue)
{
Property = property;
Value = value;
Priority = priority;
Diagnostic = diagnostic;
IsOverriddenCurrentValue = isOverriddenCurrentValue;
}
/// <summary>
@ -46,5 +41,11 @@ namespace Avalonia.Diagnostics
/// Gets a diagnostic string.
/// </summary>
public string? Diagnostic { get; }
/// <summary>
/// Gets a value indicating whether the <see cref="Value"/> was overridden by a call to
/// <see cref="AvaloniaObject.SetCurrentValue{T}"/>.
/// </summary>
public bool IsOverriddenCurrentValue { get; }
}
}

5
src/Avalonia.Base/DirectPropertyBase.cs

@ -152,6 +152,11 @@ namespace Avalonia
return null;
}
internal override void RouteSetCurrentValue(AvaloniaObject o, object? value)
{
RouteSetValue(o, value, BindingPriority.LocalValue);
}
/// <summary>
/// Routes an untyped Bind call to a typed call.
/// </summary>

23
src/Avalonia.Base/Input/TextInput/ITextEditable.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Metadata;
namespace Avalonia.Input.TextInput
{
[NotClientImplementable]
public interface ITextEditable
{
event EventHandler TextChanged;
event EventHandler SelectionChanged;
event EventHandler CompositionChanged;
int SelectionStart { get; set; }
int SelectionEnd { get; set; }
int CompositionStart { get; }
int CompositionEnd { get; }
string? Text { get; set; }
}
}

11
src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Media.TextFormatting;
using Avalonia.VisualTree;
namespace Avalonia.Input.TextInput
@ -30,6 +31,11 @@ namespace Avalonia.Input.TextInput
/// </summary>
void SetPreeditText(string? text);
/// <summary>
/// Sets the current composing region. This doesn't remove the composing text from the commited text.
/// </summary>
void SetComposingRegion(TextRange? region);
/// <summary>
/// Indicates if text input client is capable of providing the text around the cursor
/// </summary>
@ -43,6 +49,11 @@ namespace Avalonia.Input.TextInput
/// </summary>
event EventHandler? SurroundingTextChanged;
/// <summary>
/// Gets or sets a platform editable. Text and selection changes made in the editable are forwarded to the IM client.
/// </summary>
ITextEditable? TextEditable { get; set; }
void SelectInSurroundingText(int start, int end);
}

6
src/Avalonia.Base/PropertyStore/EffectiveValue.cs

@ -29,6 +29,12 @@ namespace Avalonia.PropertyStore
/// </summary>
public BindingPriority BasePriority { get; protected set; }
/// <summary>
/// Gets a value indicating whether the <see cref="Value"/> was overridden by a call to
/// <see cref="AvaloniaObject.SetCurrentValue{T}"/>.
/// </summary>
public bool IsOverridenCurrentValue { get; set; }
/// <summary>
/// Begins a reevaluation pass on the effective value.
/// </summary>

36
src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs

@ -19,13 +19,16 @@ namespace Avalonia.PropertyStore
private T? _baseValue;
private UncommonFields? _uncommon;
public EffectiveValue(AvaloniaObject owner, StyledProperty<T> property)
public EffectiveValue(
AvaloniaObject owner,
StyledProperty<T> property,
EffectiveValue<T>? inherited)
{
Priority = BindingPriority.Unset;
BasePriority = BindingPriority.Unset;
_metadata = property.GetMetadata(owner.GetType());
var value = _metadata.DefaultValue;
var value = inherited is null ? _metadata.DefaultValue : inherited.Value;
if (property.HasCoercion && _metadata.CoerceValue is { } coerce)
{
@ -57,7 +60,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(priority != BindingPriority.LocalValue);
UpdateValueEntry(value, priority);
SetAndRaiseCore(owner, (StyledProperty<T>)value.Property, GetValue(value), priority);
SetAndRaiseCore(owner, (StyledProperty<T>)value.Property, GetValue(value), priority, false);
}
public void SetLocalValueAndRaise(
@ -65,7 +68,16 @@ namespace Avalonia.PropertyStore
StyledProperty<T> property,
T value)
{
SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue);
SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue, false);
}
public void SetCurrentValueAndRaise(
ValueStore owner,
StyledProperty<T> property,
T value)
{
IsOverridenCurrentValue = true;
SetAndRaiseCore(owner, property, value, Priority, true);
}
public bool TryGetBaseValue([MaybeNullWhen(false)] out T value)
@ -98,7 +110,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(Priority != BindingPriority.Animation);
Debug.Assert(BasePriority != BindingPriority.Unset);
UpdateValueEntry(null, BindingPriority.Animation);
SetAndRaiseCore(owner, (StyledProperty<T>)property, _baseValue!, BasePriority);
SetAndRaiseCore(owner, (StyledProperty<T>)property, _baseValue!, BasePriority, false);
}
public override void CoerceValue(ValueStore owner, AvaloniaProperty property)
@ -158,15 +170,16 @@ namespace Avalonia.PropertyStore
ValueStore owner,
StyledProperty<T> property,
T value,
BindingPriority priority)
BindingPriority priority,
bool isOverriddenCurrentValue)
{
Debug.Assert(priority < BindingPriority.Inherited);
var oldValue = Value;
var valueChanged = false;
var baseValueChanged = false;
var v = value;
IsOverridenCurrentValue = isOverriddenCurrentValue;
if (_uncommon?._coerce is { } coerce)
v = coerce(owner.Owner, value);
@ -209,7 +222,6 @@ namespace Avalonia.PropertyStore
T baseValue,
BindingPriority basePriority)
{
Debug.Assert(priority < BindingPriority.Inherited);
Debug.Assert(basePriority > BindingPriority.Animation);
Debug.Assert(priority <= basePriority);
@ -225,7 +237,7 @@ namespace Avalonia.PropertyStore
bv = coerce(owner.Owner, baseValue);
}
if (priority != BindingPriority.Unset && !EqualityComparer<T>.Default.Equals(Value, v))
if (!EqualityComparer<T>.Default.Equals(Value, v))
{
Value = v;
valueChanged = true;
@ -233,9 +245,7 @@ namespace Avalonia.PropertyStore
_uncommon._uncoercedValue = value;
}
if (priority != BindingPriority.Unset &&
(BasePriority == BindingPriority.Unset ||
!EqualityComparer<T>.Default.Equals(_baseValue, bv)))
if (!EqualityComparer<T>.Default.Equals(_baseValue, bv))
{
_baseValue = v;
baseValueChanged = true;

50
src/Avalonia.Base/PropertyStore/ValueStore.cs

@ -7,7 +7,6 @@ using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Styling;
using Avalonia.Utilities;
using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
namespace Avalonia.PropertyStore
{
@ -156,11 +155,12 @@ namespace Avalonia.PropertyStore
return observer;
}
public void ClearLocalValue(AvaloniaProperty property)
public void ClearValue(AvaloniaProperty property)
{
if (TryGetEffectiveValue(property, out var effective) &&
effective.Priority == BindingPriority.LocalValue)
(effective.Priority == BindingPriority.LocalValue || effective.IsOverridenCurrentValue))
{
effective.IsOverridenCurrentValue = false;
ReevaluateEffectiveValue(property, effective, ignoreLocalValue: true);
}
}
@ -184,7 +184,7 @@ namespace Avalonia.PropertyStore
}
else
{
var effectiveValue = new EffectiveValue<T>(Owner, property);
var effectiveValue = CreateEffectiveValue(property);
AddEffectiveValue(property, effectiveValue);
effectiveValue.SetAndRaise(this, result, priority);
}
@ -200,7 +200,7 @@ namespace Avalonia.PropertyStore
}
else
{
var effectiveValue = new EffectiveValue<T>(Owner, property);
var effectiveValue = CreateEffectiveValue(property);
AddEffectiveValue(property, effectiveValue);
effectiveValue.SetLocalValueAndRaise(this, property, value);
}
@ -209,6 +209,20 @@ namespace Avalonia.PropertyStore
}
}
public void SetCurrentValue<T>(StyledProperty<T> property, T value)
{
if (TryGetEffectiveValue(property, out var v))
{
((EffectiveValue<T>)v).SetCurrentValueAndRaise(this, property, value);
}
else
{
var effectiveValue = CreateEffectiveValue(property);
AddEffectiveValue(property, effectiveValue);
effectiveValue.SetCurrentValueAndRaise(this, property, value);
}
}
public object? GetValue(AvaloniaProperty property)
{
if (_effectiveValues.TryGetValue(property, out var v))
@ -235,12 +249,7 @@ namespace Avalonia.PropertyStore
return false;
}
public bool IsSet(AvaloniaProperty property)
{
if (_effectiveValues.TryGetValue(property, out var v))
return v.Priority < BindingPriority.Inherited;
return false;
}
public bool IsSet(AvaloniaProperty property) => _effectiveValues.TryGetValue(property, out _);
public void CoerceValue(AvaloniaProperty property)
{
@ -278,6 +287,16 @@ namespace Avalonia.PropertyStore
return false;
}
public EffectiveValue<T> CreateEffectiveValue<T>(StyledProperty<T> property)
{
EffectiveValue<T>? inherited = null;
if (property.Inherits && TryGetInheritedValue(property, out var v))
inherited = (EffectiveValue<T>)v;
return new EffectiveValue<T>(Owner, property, inherited);
}
public void SetInheritanceParent(AvaloniaObject? newParent)
{
var values = AvaloniaPropertyDictionaryPool<OldNewValue>.Get();
@ -490,7 +509,7 @@ namespace Avalonia.PropertyStore
if (existing == observer)
{
_localValueBindings?.Remove(property.Id);
ClearLocalValue(property);
ClearValue(property);
}
}
}
@ -616,11 +635,13 @@ namespace Avalonia.PropertyStore
{
object? value;
BindingPriority priority;
bool overridden = false;
if (_effectiveValues.TryGetValue(property, out var v))
{
value = v.Value;
priority = v.Priority;
overridden = v.IsOverridenCurrentValue;
}
else if (property.Inherits && TryGetInheritedValue(property, out v))
{
@ -637,7 +658,8 @@ namespace Avalonia.PropertyStore
property,
value,
priority,
null);
null,
overridden);
}
private int InsertFrame(ValueFrame frame)
@ -787,7 +809,7 @@ namespace Avalonia.PropertyStore
// - The value is a non-animation value and its priority is higher than the current
// effective value's base priority
var isRelevantPriority = current is null ||
priority < current.Priority ||
(priority < current.Priority && priority < current.BasePriority) ||
(priority > BindingPriority.Animation && priority < current.BasePriority);
if (foundEntry && isRelevantPriority && entry!.HasValue)

4
src/Avalonia.Base/StyledElement.cs

@ -41,7 +41,11 @@ namespace Avalonia
public static readonly StyledProperty<object?> DataContextProperty =
AvaloniaProperty.Register<StyledElement, object?>(
nameof(DataContext),
defaultValue: null,
inherits: true,
defaultBindingMode: BindingMode.OneWay,
validate: null,
coerce: null,
notifying: DataContextNotifying);
/// <summary>

46
src/Avalonia.Base/StyledProperty.cs

@ -171,7 +171,7 @@ namespace Avalonia
internal override EffectiveValue CreateEffectiveValue(AvaloniaObject o)
{
return new EffectiveValue<TValue>(o, this);
return o.GetValueStore().CreateEffectiveValue(this);
}
/// <inheritdoc/>
@ -194,24 +194,48 @@ namespace Avalonia
}
/// <inheritdoc/>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal override IDisposable? RouteSetValue(
AvaloniaObject target,
object? value,
BindingPriority priority)
{
if (ShouldSetValue(target, value, out var converted))
return target.SetValue<TValue>(this, converted, priority);
return null;
}
internal override void RouteSetCurrentValue(AvaloniaObject target, object? value)
{
if (ShouldSetValue(target, value, out var converted))
target.SetCurrentValue<TValue>(this, converted);
}
internal override IDisposable RouteBind(
AvaloniaObject target,
IObservable<object?> source,
BindingPriority priority)
{
return target.Bind<TValue>(this, source, priority);
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
private bool ShouldSetValue(AvaloniaObject target, object? value, [NotNullWhen(true)] out TValue? converted)
{
if (value == BindingOperations.DoNothing)
{
return null;
converted = default;
return false;
}
else if (value == UnsetValue)
if (value == UnsetValue)
{
target.ClearValue(this);
return null;
converted = default;
return false;
}
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var converted))
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var v))
{
return target.SetValue<TValue>(this, (TValue)converted!, priority);
converted = (TValue)v!;
return true;
}
else
{
@ -220,14 +244,6 @@ namespace Avalonia
}
}
internal override IDisposable RouteBind(
AvaloniaObject target,
IObservable<object?> source,
BindingPriority priority)
{
return target.Bind<TValue>(this, source, priority);
}
private object? GetDefaultBoxedValue(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));

7
src/Avalonia.Controls/ItemsControl.cs

@ -559,7 +559,12 @@ namespace Avalonia.Controls
return new ItemContainerGenerator(this);
}
internal void AddLogicalChild(Control c) => LogicalChildren.Add(c);
internal void AddLogicalChild(Control c)
{
if (!LogicalChildren.Contains(c))
LogicalChildren.Add(c);
}
internal void RemoveLogicalChild(Control c) => LogicalChildren.Remove(c);
/// <summary>

33
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -63,6 +63,15 @@ namespace Avalonia.Controls.Presenters
o => o.PreeditText,
(o, v) => o.PreeditText = v);
/// <summary>
/// Defines the <see cref="CompositionRegion"/> property.
/// </summary>
public static readonly DirectProperty<TextPresenter, TextRange?> CompositionRegionProperty =
AvaloniaProperty.RegisterDirect<TextPresenter, TextRange?>(
nameof(CompositionRegion),
o => o.CompositionRegion,
(o, v) => o.CompositionRegion = v);
/// <summary>
/// Defines the <see cref="TextAlignment"/> property.
/// </summary>
@ -106,6 +115,7 @@ namespace Avalonia.Controls.Presenters
private Rect _caretBounds;
private Point _navigationPosition;
private string? _preeditText;
private TextRange? _compositionRegion;
static TextPresenter()
{
@ -146,6 +156,12 @@ namespace Avalonia.Controls.Presenters
set => SetAndRaise(PreeditTextProperty, ref _preeditText, value);
}
public TextRange? CompositionRegion
{
get => _compositionRegion;
set => SetAndRaise(CompositionRegionProperty, ref _compositionRegion, value);
}
/// <summary>
/// Gets or sets the font family.
/// </summary>
@ -548,7 +564,20 @@ namespace Avalonia.Controls.Presenters
var foreground = Foreground;
if (!string.IsNullOrEmpty(_preeditText))
if(_compositionRegion != null)
{
var preeditHighlight = new ValueSpan<TextRunProperties>(_compositionRegion?.Start ?? 0, _compositionRegion?.Length ?? 0,
new GenericTextRunProperties(typeface, FontSize,
foregroundBrush: foreground,
textDecorations: TextDecorations.Underline));
textStyleOverrides = new[]
{
preeditHighlight
};
}
else if (!string.IsNullOrEmpty(_preeditText))
{
var preeditHighlight = new ValueSpan<TextRunProperties>(_caretIndex, _preeditText.Length,
new GenericTextRunProperties(typeface, FontSize,
@ -911,6 +940,7 @@ namespace Avalonia.Controls.Presenters
break;
}
case nameof(CompositionRegion):
case nameof(Foreground):
case nameof(FontSize):
case nameof(FontStyle):
@ -931,7 +961,6 @@ namespace Avalonia.Controls.Presenters
case nameof(PasswordChar):
case nameof(RevealPassword):
case nameof(FlowDirection):
{
InvalidateTextLayout();

117
src/Avalonia.Controls/TextBoxTextInputMethodClient.cs

@ -5,6 +5,7 @@ using Avalonia.Media.TextFormatting;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.VisualTree;
using static System.Net.Mime.MediaTypeNames;
namespace Avalonia.Controls
{
@ -12,6 +13,7 @@ namespace Avalonia.Controls
{
private TextBox? _parent;
private TextPresenter? _presenter;
private ITextEditable? _textEditable;
public Visual TextViewVisual => _presenter!;
@ -45,7 +47,7 @@ namespace Avalonia.Controls
{
get
{
if(_presenter is null || _parent is null)
if (_presenter is null || _parent is null)
{
return default;
}
@ -71,13 +73,70 @@ namespace Avalonia.Controls
}
}
public ITextEditable? TextEditable
{
get => _textEditable; set
{
if(_textEditable != null)
{
_textEditable.TextChanged -= TextEditable_TextChanged;
_textEditable.SelectionChanged -= TextEditable_SelectionChanged;
_textEditable.CompositionChanged -= TextEditable_CompositionChanged;
}
_textEditable = value;
if(_textEditable != null)
{
_textEditable.TextChanged += TextEditable_TextChanged;
_textEditable.SelectionChanged += TextEditable_SelectionChanged;
_textEditable.CompositionChanged += TextEditable_CompositionChanged;
if (_presenter != null)
{
_textEditable.Text = _presenter.Text;
_textEditable.SelectionStart = _presenter.SelectionStart;
_textEditable.SelectionEnd = _presenter.SelectionEnd;
}
}
}
}
private void TextEditable_CompositionChanged(object? sender, EventArgs e)
{
if (_presenter != null && _textEditable != null)
{
_presenter.CompositionRegion = new TextRange(_textEditable.CompositionStart, _textEditable.CompositionEnd);
}
}
private void TextEditable_SelectionChanged(object? sender, EventArgs e)
{
if(_parent != null && _textEditable != null)
{
_parent.SelectionStart = _textEditable.SelectionStart;
_parent.SelectionEnd = _textEditable.SelectionEnd;
}
}
private void TextEditable_TextChanged(object? sender, EventArgs e)
{
if (_parent != null)
{
if (_parent.Text != _textEditable?.Text)
{
_parent.Text = _textEditable?.Text;
}
}
}
private static string GetTextLineText(TextLine textLine)
{
var builder = StringBuilderCache.Acquire(textLine.Length);
foreach (var run in textLine.TextRuns)
{
if(run.Length > 0)
if (run.Length > 0)
{
#if NET6_0_OR_GREATER
builder.Append(run.Text.Span);
@ -110,9 +169,18 @@ namespace Avalonia.Controls
_presenter.PreeditText = text;
}
public void SetComposingRegion(TextRange? region)
{
if (_presenter == null)
{
return;
}
_presenter.CompositionRegion = region;
}
public void SelectInSurroundingText(int start, int end)
{
if(_parent is null ||_presenter is null)
if (_parent is null || _presenter is null)
{
return;
}
@ -125,21 +193,21 @@ namespace Avalonia.Controls
var selectionStart = lineStart + start;
var selectionEnd = lineStart + end;
_parent.SelectionStart = selectionStart;
_parent.SelectionEnd = selectionEnd;
}
}
public void SetPresenter(TextPresenter? presenter, TextBox? parent)
{
if(_parent != null)
if (_parent != null)
{
_parent.PropertyChanged -= OnParentPropertyChanged;
}
_parent = parent;
if(_parent != null)
if (_parent != null)
{
_parent.PropertyChanged += OnParentPropertyChanged;
}
@ -148,16 +216,18 @@ namespace Avalonia.Controls
{
_presenter.PreeditText = null;
_presenter.CaretBoundsChanged -= OnCaretBoundsChanged;
_presenter.CompositionRegion = null;
_presenter.CaretBoundsChanged -= OnCaretBoundsChanged;
}
_presenter = presenter;
if (_presenter != null)
{
_presenter.CaretBoundsChanged += OnCaretBoundsChanged;
}
TextViewVisualChanged?.Invoke(this, EventArgs.Empty);
OnCaretBoundsChanged(this, EventArgs.Empty);
@ -165,12 +235,33 @@ namespace Avalonia.Controls
private void OnParentPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if(e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
if (e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
{
if (SupportsSurroundingText)
{
SurroundingTextChanged?.Invoke(this, e);
}
if (_textEditable != null)
{
var value = (int)(e.NewValue ?? 0);
if (e.Property == TextBox.SelectionStartProperty)
{
_textEditable.SelectionStart = value;
}
if (e.Property == TextBox.SelectionEndProperty)
{
_textEditable.SelectionEnd = value;
}
}
}
if(e.Property == TextBox.TextProperty)
{
if(_textEditable != null)
{
_textEditable.Text = (string?)e.NewValue;
}
}
}

2
src/Avalonia.FreeDesktop/DBusHelper.cs

@ -6,7 +6,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop
{
public static class DBusHelper
internal static class DBusHelper
{
/// <summary>
/// This class uses synchronous execution at DBus connection establishment stage

2
src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs

@ -6,7 +6,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop.DBusIme
{
public class X11DBusImeHelper
internal class X11DBusImeHelper
{
private static readonly Dictionary<string, Func<Connection, IX11InputMethodFactory>> KnownMethods =
new Dictionary<string, Func<Connection, IX11InputMethodFactory>>

2
src/Avalonia.FreeDesktop/DBusMenuExporter.cs

@ -15,7 +15,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop
{
public class DBusMenuExporter
internal class DBusMenuExporter
{
public static ITopLevelNativeMenuExporter? TryCreateTopLevelNativeMenu(IntPtr xid)
{

6
src/Avalonia.FreeDesktop/IX11InputMethod.cs

@ -6,13 +6,13 @@ using Avalonia.Input.TextInput;
namespace Avalonia.FreeDesktop
{
public interface IX11InputMethodFactory
internal interface IX11InputMethodFactory
{
(ITextInputMethodImpl method, IX11InputMethodControl control) CreateClient(IntPtr xid);
}
#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct X11InputMethodForwardedKey
internal struct X11InputMethodForwardedKey
#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public int KeyVal { get; set; }
@ -20,7 +20,7 @@ namespace Avalonia.FreeDesktop
public RawKeyEventType Type { get; set; }
}
public interface IX11InputMethodControl : IDisposable
internal interface IX11InputMethodControl : IDisposable
{
void SetWindowActive(bool active);
bool IsEnabled { get; }

2
src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs

@ -5,7 +5,7 @@ using Avalonia.Controls.Platform;
namespace Avalonia.FreeDesktop
{
public class LinuxMountedVolumeInfoProvider : IMountedVolumeInfoProvider
internal class LinuxMountedVolumeInfoProvider : IMountedVolumeInfoProvider
{
public IDisposable Listen(ObservableCollection<MountedVolumeInfo> mountedDrives)
{

2
src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs

@ -68,8 +68,6 @@ namespace Avalonia.Headless
.Bind<IKeyboardDevice>().ToConstant(new KeyboardDevice())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(new RenderTimer(60))
.Bind<IFontManagerImpl>().ToSingleton<HeadlessFontManagerStub>()
.Bind<ITextShaperImpl>().ToSingleton<HeadlessTextShaperStub>()
.Bind<IWindowingPlatform>().ToConstant(new HeadlessWindowingPlatform())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
Compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(), null);

2
src/Avalonia.Native/CallbackBase.cs

@ -6,7 +6,7 @@ using MicroCom.Runtime;
namespace Avalonia.Native
{
public abstract class NativeCallbackBase : CallbackBase, IMicroComExceptionCallback
internal abstract class NativeCallbackBase : CallbackBase, IMicroComExceptionCallback
{
public void RaiseException(Exception e)
{

2
src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs

@ -64,7 +64,7 @@ namespace Avalonia.Native
}
}
public class MacOSMountedVolumeInfoProvider : IMountedVolumeInfoProvider
internal class MacOSMountedVolumeInfoProvider : IMountedVolumeInfoProvider
{
public IDisposable Listen(ObservableCollection<MountedVolumeInfo> mountedDrives)
{

2
src/Avalonia.Native/MenuActionCallback.cs

@ -3,7 +3,7 @@ using Avalonia.Native.Interop;
namespace Avalonia.Native
{
public class MenuActionCallback : NativeCallbackBase, IAvnActionCallback
internal class MenuActionCallback : NativeCallbackBase, IAvnActionCallback
{
private Action _action;

2
src/Avalonia.Native/PredicateCallback.cs

@ -3,7 +3,7 @@ using Avalonia.Native.Interop;
namespace Avalonia.Native
{
public class PredicateCallback : NativeCallbackBase, IAvnPredicateCallback
internal class PredicateCallback : NativeCallbackBase, IAvnPredicateCallback
{
private Func<bool> _predicate;

2
src/Avalonia.Native/ScreenImpl.cs

@ -5,7 +5,7 @@ using Avalonia.Platform;
namespace Avalonia.Native
{
class ScreenImpl : IScreenImpl, IDisposable
internal class ScreenImpl : IScreenImpl, IDisposable
{
private IAvnScreens _native;

2
src/Avalonia.X11/Glx/Glx.cs

@ -10,7 +10,7 @@ using Avalonia.SourceGenerator;
namespace Avalonia.X11.Glx
{
unsafe partial class GlxInterface
internal unsafe partial class GlxInterface
{
private const string libGL = "libGL.so.1";
[GetProcAddress("glXMakeContextCurrent")]

2
src/Avalonia.X11/Glx/GlxConsts.cs

@ -4,7 +4,7 @@
#pragma warning disable 414
namespace Avalonia.X11.Glx
{
class GlxConsts
internal class GlxConsts
{
public const int GLX_USE_GL = 1;
public const int GLX_BUFFER_SIZE = 2;

6
src/Avalonia.X11/Glx/GlxContext.cs

@ -7,7 +7,7 @@ using Avalonia.Reactive;
namespace Avalonia.X11.Glx
{
class GlxContext : IGlContext
internal class GlxContext : IGlContext
{
public IntPtr Handle { get; }
public GlxInterface Glx { get; }
@ -46,8 +46,8 @@ namespace Avalonia.X11.Glx
public GlInterface GlInterface { get; }
public int SampleCount { get; }
public int StencilSize { get; }
class RestoreContext : IDisposable
private class RestoreContext : IDisposable
{
private GlxInterface _glx;
private IntPtr _defaultDisplay;

8
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -6,7 +6,7 @@ using static Avalonia.X11.Glx.GlxConsts;
namespace Avalonia.X11.Glx
{
unsafe class GlxDisplay
internal unsafe class GlxDisplay
{
private readonly X11Info _x11;
private readonly GlVersion[] _probeProfiles;
@ -106,7 +106,7 @@ namespace Avalonia.X11.Glx
}
}
IntPtr CreatePBuffer()
private IntPtr CreatePBuffer()
{
return Glx.CreatePbuffer(_x11.Display, _fbconfig, new[] { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 });
}
@ -116,8 +116,8 @@ namespace Avalonia.X11.Glx
public GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share,
share.SampleCount, share.StencilSize, true);
GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
private GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
int sampleCount, int stencilSize, bool ownsPBuffer)
{
var sharelist = ((GlxContext)share)?.Handle ?? IntPtr.Zero;

8
src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs

@ -6,7 +6,7 @@ using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.X11.Glx
{
class GlxGlPlatformSurface: IGlPlatformSurface
internal class GlxGlPlatformSurface: IGlPlatformSurface
{
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
@ -21,7 +21,7 @@ namespace Avalonia.X11.Glx
return new RenderTarget((GlxContext)context, _info);
}
class RenderTarget : IGlPlatformSurfaceRenderTarget
private class RenderTarget : IGlPlatformSurfaceRenderTarget
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
@ -46,8 +46,8 @@ namespace Avalonia.X11.Glx
return new Session(_context, _info, oldContext);
}
class Session : IGlPlatformSurfaceRenderingSession
private class Session : IGlPlatformSurfaceRenderingSession
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;

2
src/Avalonia.X11/Glx/GlxPlatformFeature.cs

@ -6,7 +6,7 @@ using Avalonia.Platform;
namespace Avalonia.X11.Glx
{
class GlxPlatformGraphics : IPlatformGraphics
internal class GlxPlatformGraphics : IPlatformGraphics
{
public GlxDisplay Display { get; private set; }
public bool CanCreateContexts => true;

2
src/Avalonia.X11/Keysyms.cs

@ -3,7 +3,7 @@
// ReSharper disable CommentTypo
namespace Avalonia.X11
{
enum X11Key
internal enum X11Key
{
VoidSymbol = 0xffffff /* Void symbol */,
BackSpace = 0xff08 /* Back space, back char */,

29
src/Avalonia.X11/NativeDialogs/Gtk.cs

@ -7,8 +7,7 @@ using Avalonia.Platform.Interop;
// ReSharper disable IdentifierTypo
namespace Avalonia.X11.NativeDialogs
{
static unsafe class Glib
internal static unsafe class Glib
{
private const string GlibName = "libglib-2.0.so.0";
private const string GObjectName = "libgobject-2.0.so.0";
@ -36,7 +35,7 @@ namespace Avalonia.X11.NativeDialogs
IntPtr destroy);
class ConnectedSignal : IDisposable
private class ConnectedSignal : IDisposable
{
private readonly IntPtr _instance;
private GCHandle _handle;
@ -75,7 +74,7 @@ namespace Avalonia.X11.NativeDialogs
}
static bool TimeoutHandler(IntPtr data)
private static bool TimeoutHandler(IntPtr data)
{
var handle = GCHandle.FromIntPtr(data);
var cb = (Func<bool>)handle.Target;
@ -95,7 +94,7 @@ namespace Avalonia.X11.NativeDialogs
s_pinnedHandler = TimeoutHandler;
}
static void AddTimeout(int priority, uint interval, Func<bool> callback)
private static void AddTimeout(int priority, uint interval, Func<bool> callback)
{
var handle = GCHandle.Alloc(callback);
g_timeout_add_full(priority, interval, s_pinnedHandler, GCHandle.ToIntPtr(handle), IntPtr.Zero);
@ -123,13 +122,13 @@ namespace Avalonia.X11.NativeDialogs
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct GSList
internal unsafe struct GSList
{
public readonly IntPtr Data;
public readonly GSList* Next;
}
enum GtkFileChooserAction
internal enum GtkFileChooserAction
{
Open,
Save,
@ -137,7 +136,7 @@ namespace Avalonia.X11.NativeDialogs
}
// ReSharper disable UnusedMember.Global
enum GtkResponseType
internal enum GtkResponseType
{
Help = -11,
Apply = -10,
@ -153,14 +152,14 @@ namespace Avalonia.X11.NativeDialogs
}
// ReSharper restore UnusedMember.Global
static unsafe class Gtk
internal static unsafe class Gtk
{
private static IntPtr s_display;
private const string GdkName = "libgdk-3.so.0";
private const string GtkName = "libgtk-3.so.0";
[DllImport(GtkName)]
static extern void gtk_main_iteration();
private static extern void gtk_main_iteration();
[DllImport(GtkName)]
@ -231,10 +230,10 @@ namespace Avalonia.X11.NativeDialogs
public static extern void gtk_widget_hide(IntPtr gtkWidget);
[DllImport(GtkName)]
static extern bool gtk_init_check(int argc, IntPtr argv);
private static extern bool gtk_init_check(int argc, IntPtr argv);
[DllImport(GdkName)]
static extern IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
private static extern IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
[DllImport(GdkName)]
public static extern IntPtr gdk_x11_window_get_xid(IntPtr window);
@ -244,13 +243,13 @@ namespace Avalonia.X11.NativeDialogs
public static extern IntPtr gtk_container_add(IntPtr container, IntPtr widget);
[DllImport(GdkName)]
static extern IntPtr gdk_set_allowed_backends(Utf8Buffer backends);
private static extern IntPtr gdk_set_allowed_backends(Utf8Buffer backends);
[DllImport(GdkName)]
static extern IntPtr gdk_display_get_default();
private static extern IntPtr gdk_display_get_default();
[DllImport(GtkName)]
static extern IntPtr gtk_application_new(Utf8Buffer appId, int flags);
private static extern IntPtr gtk_application_new(Utf8Buffer appId, int flags);
[DllImport(GdkName)]
public static extern void gdk_window_set_transient_for(IntPtr window, IntPtr parent);

2
src/Avalonia.X11/TransparencyHelper.cs

@ -3,7 +3,7 @@ using Avalonia.Controls;
namespace Avalonia.X11
{
class TransparencyHelper : IDisposable, X11Globals.IGlobalsSubscriber
internal class TransparencyHelper : IDisposable, X11Globals.IGlobalsSubscriber
{
private readonly X11Info _x11;
private readonly IntPtr _window;

16
src/Avalonia.X11/X11Clipboard.cs

@ -9,7 +9,7 @@ using Avalonia.Input.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
class X11Clipboard : IClipboard
internal class X11Clipboard : IClipboard
{
private readonly X11Info _x11;
private IDataObject _storedDataObject;
@ -33,12 +33,12 @@ namespace Avalonia.X11
}.Where(a => a != IntPtr.Zero).ToArray();
}
bool IsStringAtom(IntPtr atom)
private bool IsStringAtom(IntPtr atom)
{
return _textAtoms.Contains(atom);
}
Encoding GetStringEncoding(IntPtr atom)
private Encoding GetStringEncoding(IntPtr atom)
{
return (atom == _x11.Atoms.XA_STRING
|| atom == _x11.Atoms.OEMTEXT)
@ -213,7 +213,7 @@ namespace Avalonia.X11
}
}
Task<IntPtr[]> SendFormatRequest()
private Task<IntPtr[]> SendFormatRequest()
{
if (_requestedFormatsTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedFormatsTcs = new TaskCompletionSource<IntPtr[]>();
@ -222,7 +222,7 @@ namespace Avalonia.X11
return _requestedFormatsTcs.Task;
}
Task<object> SendDataRequest(IntPtr format)
private Task<object> SendDataRequest(IntPtr format)
{
if (_requestedDataTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedDataTcs = new TaskCompletionSource<object>();
@ -230,7 +230,7 @@ namespace Avalonia.X11
return _requestedDataTcs.Task;
}
bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero;
private bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero;
public async Task<string> GetTextAsync()
{
@ -252,7 +252,7 @@ namespace Avalonia.X11
return (string)await SendDataRequest(target);
}
void StoreAtomsInClipboardManager(IntPtr[] atoms)
private void StoreAtomsInClipboardManager(IntPtr[] atoms)
{
if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
{

4
src/Avalonia.X11/X11CursorFactory.cs

@ -12,7 +12,7 @@ using Avalonia.Utilities;
namespace Avalonia.X11
{
partial class X11CursorFactory : ICursorFactory
internal partial class X11CursorFactory : ICursorFactory
{
private static readonly byte[] NullCursorData = new byte[] { 0 };
@ -142,7 +142,7 @@ namespace Avalonia.X11
}
}
class CursorImpl : ICursorImpl
internal class CursorImpl : ICursorImpl
{
public CursorImpl() { }
public CursorImpl(IntPtr handle) => Handle = handle;

8
src/Avalonia.X11/X11Enums.cs

@ -3,7 +3,7 @@ using System;
namespace Avalonia.X11
{
public enum Status
internal enum Status
{
Success = 0, /* everything's okay */
BadRequest = 1, /* bad request code */
@ -38,7 +38,7 @@ namespace Avalonia.X11
}
[Flags]
public enum XEventMask : int
internal enum XEventMask : int
{
NoEventMask = 0,
KeyPressMask = (1 << 0),
@ -69,7 +69,7 @@ namespace Avalonia.X11
}
[Flags]
public enum XModifierMask
internal enum XModifierMask
{
ShiftMask = (1 << 0),
LockMask = (1 << 1),
@ -89,7 +89,7 @@ namespace Avalonia.X11
}
[Flags]
public enum XCreateWindowFlags
internal enum XCreateWindowFlags
{
CWBackPixmap = (1 << 0),
CWBackPixel = (1 << 1),

2
src/Avalonia.X11/X11Exception.cs

@ -2,7 +2,7 @@ using System;
namespace Avalonia.X11
{
public class X11Exception : Exception
internal class X11Exception : Exception
{
public X11Exception(string message) : base(message)
{

2
src/Avalonia.X11/X11Framebuffer.cs

@ -5,7 +5,7 @@ using SkiaSharp;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
class X11Framebuffer : ILockedFramebuffer
internal class X11Framebuffer : ILockedFramebuffer
{
private readonly IntPtr _display;
private readonly IntPtr _xid;

2
src/Avalonia.X11/X11FramebufferSurface.cs

@ -4,7 +4,7 @@ using Avalonia.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
public class X11FramebufferSurface : IFramebufferPlatformSurface
internal class X11FramebufferSurface : IFramebufferPlatformSurface
{
private readonly IntPtr _display;
private readonly IntPtr _xid;

12
src/Avalonia.X11/X11Globals.cs

@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
unsafe class X11Globals
internal unsafe class X11Globals
{
private readonly AvaloniaX11Platform _plat;
private readonly int _screenNumber;
@ -75,7 +75,7 @@ namespace Avalonia.X11
}
}
IntPtr GetSupportingWmCheck(IntPtr window)
private IntPtr GetSupportingWmCheck(IntPtr window)
{
XGetWindowProperty(_x11.Display, _rootWindow, _x11.Atoms._NET_SUPPORTING_WM_CHECK,
IntPtr.Zero, new IntPtr(IntPtr.Size), false,
@ -95,7 +95,7 @@ namespace Avalonia.X11
}
}
void UpdateCompositingAtomOwner()
private void UpdateCompositingAtomOwner()
{
// This procedure is described in https://tronche.com/gui/x/icccm/sec-2.html#s-2.8
@ -128,10 +128,10 @@ namespace Avalonia.X11
if(ev.type == XEventName.DestroyNotify)
UpdateCompositingAtomOwner();
}
void UpdateWmName() => WmName = GetWmName();
string GetWmName()
private void UpdateWmName() => WmName = GetWmName();
private string GetWmName()
{
var wm = GetSupportingWmCheck(_rootWindow);
if (wm == IntPtr.Zero || wm != GetSupportingWmCheck(wm))

8
src/Avalonia.X11/X11IconLoader.cs

@ -7,9 +7,9 @@ using Avalonia.Platform;
namespace Avalonia.X11
{
class X11IconLoader : IPlatformIconLoader
internal class X11IconLoader : IPlatformIconLoader
{
static IWindowIconImpl LoadIcon(Bitmap bitmap)
private static IWindowIconImpl LoadIcon(Bitmap bitmap)
{
var rv = new X11IconData(bitmap);
bitmap.Dispose();
@ -28,8 +28,8 @@ namespace Avalonia.X11
return LoadIcon(ms);
}
}
unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
internal unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
{
private int _width;
private int _height;

2
src/Avalonia.X11/X11Info.cs

@ -6,7 +6,7 @@ using static Avalonia.X11.XLib;
// ReSharper disable UnusedAutoPropertyAccessor.Local
namespace Avalonia.X11
{
unsafe class X11Info
internal unsafe class X11Info
{
public IntPtr Display { get; }
public IntPtr DeferredDisplay { get; }

2
src/Avalonia.X11/X11KeyTransform.cs

@ -4,7 +4,7 @@ using Avalonia.Input;
namespace Avalonia.X11
{
static class X11KeyTransform
internal static class X11KeyTransform
{
private static readonly Dictionary<X11Key, Key> KeyDic = new Dictionary<X11Key, Key>
{

10
src/Avalonia.X11/X11NativeControlHost.cs

@ -6,7 +6,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
// TODO: Actually implement XEmbed instead of simply using XReparentWindow
class X11NativeControlHost : INativeControlHostImpl
internal class X11NativeControlHost : INativeControlHostImpl
{
private readonly AvaloniaX11Platform _platform;
public X11Window Window { get; }
@ -57,7 +57,7 @@ namespace Avalonia.X11
public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == "XID";
class DumbWindow : INativeControlHostDestroyableControlHandle
private class DumbWindow : INativeControlHostDestroyableControlHandle
{
private readonly IntPtr _display;
@ -96,8 +96,8 @@ namespace Avalonia.X11
}
}
}
class Attachment : INativeControlHostControlTopLevelAttachment
private class Attachment : INativeControlHostControlTopLevelAttachment
{
private readonly IntPtr _display;
private readonly IntPtr _orphanedWindow;
@ -129,7 +129,7 @@ namespace Avalonia.X11
_attachedTo = null;
}
void CheckDisposed()
private void CheckDisposed()
{
if (_child == null)
throw new ObjectDisposedException("X11 INativeControlHostControlTopLevelAttachment");

8
src/Avalonia.X11/X11Platform.cs

@ -20,7 +20,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
class AvaloniaX11Platform : IWindowingPlatform
internal class AvaloniaX11Platform : IWindowingPlatform
{
private Lazy<KeyboardDevice> _keyboardDevice = new Lazy<KeyboardDevice>(() => new KeyboardDevice());
public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
@ -35,7 +35,7 @@ namespace Avalonia.X11
public IntPtr OrphanedWindow { get; private set; }
public X11Globals Globals { get; private set; }
[DllImport("libc")]
static extern void setlocale(int type, string s);
private static extern void setlocale(int type, string s);
public void Initialize(X11PlatformOptions options)
{
Options = options;
@ -138,7 +138,7 @@ namespace Avalonia.X11
throw new NotSupportedException();
}
static bool EnableIme(X11PlatformOptions options)
private static bool EnableIme(X11PlatformOptions options)
{
// Disable if explicitly asked by user
var avaloniaImModule = Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE");
@ -160,7 +160,7 @@ namespace Avalonia.X11
return isCjkLocale;
}
static bool ShouldUseXim()
private static bool ShouldUseXim()
{
// Check if we are forbidden from using IME
if (Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE") == "none"

32
src/Avalonia.X11/X11PlatformThreading.cs

@ -9,7 +9,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
unsafe class X11PlatformThreading : IPlatformThreadingInterface
internal unsafe class X11PlatformThreading : IPlatformThreadingInterface
{
private readonly AvaloniaX11Platform _platform;
private readonly IntPtr _display;
@ -19,7 +19,7 @@ namespace Avalonia.X11
private Thread _mainThread;
[StructLayout(LayoutKind.Explicit)]
struct epoll_data
private struct epoll_data
{
[FieldOffset(0)]
public IntPtr ptr;
@ -36,30 +36,30 @@ namespace Avalonia.X11
private const int O_NONBLOCK = 2048;
[StructLayout(LayoutKind.Sequential)]
struct epoll_event
private struct epoll_event
{
public uint events;
public epoll_data data;
}
[DllImport("libc")]
extern static int epoll_create1(int size);
private extern static int epoll_create1(int size);
[DllImport("libc")]
extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
private extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
[DllImport("libc")]
extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
private extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
[DllImport("libc")]
extern static int pipe2(int* fds, int flags);
private extern static int pipe2(int* fds, int flags);
[DllImport("libc")]
extern static IntPtr write(int fd, void* buf, IntPtr count);
private extern static IntPtr write(int fd, void* buf, IntPtr count);
[DllImport("libc")]
extern static IntPtr read(int fd, void* buf, IntPtr count);
enum EventCodes
private extern static IntPtr read(int fd, void* buf, IntPtr count);
private enum EventCodes
{
X11 = 1,
Signal =2
@ -72,7 +72,7 @@ namespace Avalonia.X11
private int _epoll;
private Stopwatch _clock = Stopwatch.StartNew();
class X11Timer : IDisposable
private class X11Timer : IDisposable
{
private readonly X11PlatformThreading _parent;
@ -104,7 +104,7 @@ namespace Avalonia.X11
}
}
List<X11Timer> _timers = new List<X11Timer>();
private List<X11Timer> _timers = new List<X11Timer>();
public X11PlatformThreading(AvaloniaX11Platform platform)
{
@ -139,12 +139,12 @@ namespace Avalonia.X11
throw new X11Exception("Unable to attach signal pipe to epoll");
}
int TimerComparer(X11Timer t1, X11Timer t2)
private int TimerComparer(X11Timer t1, X11Timer t2)
{
return t2.Priority - t1.Priority;
}
void CheckSignaled()
private void CheckSignaled()
{
int buf = 0;
while (read(_sigread, &buf, new IntPtr(4)).ToInt64() > 0)
@ -164,7 +164,7 @@ namespace Avalonia.X11
Signaled?.Invoke(prio);
}
unsafe void HandleX11(CancellationToken cancellationToken)
private unsafe void HandleX11(CancellationToken cancellationToken)
{
while (XPending(_display) != 0)
{

20
src/Avalonia.X11/X11Screens.cs

@ -8,7 +8,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
class X11Screens : IScreenImpl
internal class X11Screens : IScreenImpl
{
private IX11Screens _impl;
@ -17,7 +17,7 @@ namespace Avalonia.X11
_impl = impl;
}
static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens)
private static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens)
{
var rect = default(PixelRect);
foreach (var s in screens)
@ -58,14 +58,14 @@ namespace Avalonia.X11
XFree(prop);
return screens;
}
class Randr15ScreensImpl : IX11Screens
private class Randr15ScreensImpl : IX11Screens
{
private readonly X11ScreensUserSettings _settings;
private X11Screen[] _cache;
private X11Info _x11;
private IntPtr _window;
const int EDIDStructureLength = 32; // Length of a EDID-Block-Length(128 bytes), XRRGetOutputProperty multiplies offset and length by 4
private const int EDIDStructureLength = 32; // Length of a EDID-Block-Length(128 bytes), XRRGetOutputProperty multiplies offset and length by 4
public Randr15ScreensImpl(AvaloniaX11Platform platform, X11ScreensUserSettings settings)
{
@ -160,7 +160,7 @@ namespace Avalonia.X11
}
}
class FallbackScreensImpl : IX11Screens
private class FallbackScreensImpl : IX11Screens
{
public FallbackScreensImpl(X11Info info, X11ScreensUserSettings settings)
{
@ -220,17 +220,17 @@ namespace Avalonia.X11
_impl.Screens.Select(s => new Screen(s.Scaling, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray();
}
interface IX11Screens
internal interface IX11Screens
{
X11Screen[] Screens { get; }
}
class X11ScreensUserSettings
internal class X11ScreensUserSettings
{
public double GlobalScaleFactor { get; set; } = 1;
public Dictionary<string, double> NamedScaleFactors { get; set; }
static double? TryParse(string s)
private static double? TryParse(string s)
{
if (s == null)
return null;
@ -276,7 +276,7 @@ namespace Avalonia.X11
}
}
class X11Screen
internal class X11Screen
{
private const int FullHDWidth = 1920;
private const int FullHDHeight = 1080;

9
src/Avalonia.X11/X11Structs.cs

@ -1751,8 +1751,7 @@ namespace Avalonia.X11 {
{
public IntPtr client_data;
public XIMProc callback;
[NonSerialized]
GCHandle gch;
[NonSerialized] private GCHandle gch;
public XIMCallback (IntPtr clientData, XIMProc proc)
{
@ -1769,7 +1768,7 @@ namespace Avalonia.X11 {
[StructLayout(LayoutKind.Sequential)]
#pragma warning disable CA1815 // Override equals and operator equals on value types
public unsafe struct XImage
internal unsafe struct XImage
#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public int width, height; /* size of image */
@ -1896,8 +1895,8 @@ namespace Avalonia.X11 {
public const string XNSpotLocation = "spotLocation";
public const string XNFontSet = "fontSet";
}
unsafe struct XRRMonitorInfo {
internal unsafe struct XRRMonitorInfo {
public IntPtr Name;
public int Primary;
public int Automatic;

32
src/Avalonia.X11/X11Window.Ime.cs

@ -11,7 +11,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
partial class X11Window
internal partial class X11Window
{
private ITextInputMethodImpl _ime;
private IX11InputMethodControl _imeControl;
@ -20,7 +20,7 @@ namespace Avalonia.X11
private Queue<(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)> _imeQueue =
new Queue<(RawKeyEventArgs args, XEvent xev, int keyVal, int keyCode)>();
unsafe void CreateIC()
private unsafe void CreateIC()
{
if (_x11.HasXim)
{
@ -65,8 +65,8 @@ namespace Avalonia.X11
new IntPtr((int)(XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing)),
XNames.XNClientWindow, _handle, XNames.XNFocusWindow, _handle, IntPtr.Zero);
}
void InitializeIme()
private void InitializeIme()
{
var ime = AvaloniaLocator.Current.GetService<IX11InputMethodFactory>()?.CreateClient(_handle);
if (ime == null && _x11.HasXim)
@ -89,9 +89,9 @@ namespace Avalonia.X11
}
}
void UpdateImePosition() => _imeControl?.UpdateWindowInfo(Position, RenderScaling);
private void UpdateImePosition() => _imeControl?.UpdateWindowInfo(Position, RenderScaling);
void HandleKeyEvent(ref XEvent ev)
private void HandleKeyEvent(ref XEvent ev)
{
var index = ev.KeyEvent.state.HasAllFlags(XModifierMask.ShiftMask);
@ -117,7 +117,7 @@ namespace Avalonia.X11
ScheduleKeyInput(args, ref ev, (int)key, ev.KeyEvent.keycode);
}
void TriggerClassicTextInputEvent(ref XEvent ev)
private void TriggerClassicTextInputEvent(ref XEvent ev)
{
var text = TranslateEventToString(ref ev);
if (text != null)
@ -128,8 +128,8 @@ namespace Avalonia.X11
private const int ImeBufferSize = 64 * 1024;
[ThreadStatic] private static IntPtr ImeBuffer;
unsafe string TranslateEventToString(ref XEvent ev)
private unsafe string TranslateEventToString(ref XEvent ev)
{
if (ImeBuffer == IntPtr.Zero)
ImeBuffer = Marshal.AllocHGlobal(ImeBufferSize);
@ -158,9 +158,9 @@ namespace Avalonia.X11
return text;
}
void ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode)
private void ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode)
{
_x11.LastActivityTimestamp = xev.ButtonEvent.time;
@ -170,8 +170,8 @@ namespace Avalonia.X11
ScheduleInput(args);
}
bool FilterIme(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)
private bool FilterIme(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)
{
if (_ime == null)
return false;
@ -182,7 +182,7 @@ namespace Avalonia.X11
return true;
}
async void ProcessNextImeEvent()
private async void ProcessNextImeEvent()
{
if(_processingIme)
return;
@ -203,7 +203,7 @@ namespace Avalonia.X11
}
// This class is used to attach the text value of the key to an asynchronously dispatched KeyDown event
class RawKeyEventArgsWithText : RawKeyEventArgs
private class RawKeyEventArgsWithText : RawKeyEventArgs
{
public RawKeyEventArgsWithText(IKeyboardDevice device, ulong timestamp, IInputRoot root,
RawKeyEventType type, Key key, RawInputModifiers modifiers, string text) :

4
src/Avalonia.X11/X11Window.Xim.cs

@ -8,9 +8,9 @@ using Avalonia.Threading;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
partial class X11Window
internal partial class X11Window
{
class XimInputMethod : ITextInputMethodImpl, IX11InputMethodControl
private class XimInputMethod : ITextInputMethodImpl, IX11InputMethodControl
{
private readonly X11Window _parent;
private bool _windowActive, _imeActive;

46
src/Avalonia.X11/X11Window.cs

@ -27,7 +27,7 @@ using static Avalonia.X11.XLib;
// ReSharper disable StringLiteralTypo
namespace Avalonia.X11
{
unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
{
private readonly AvaloniaX11Platform _platform;
private readonly bool _popup;
@ -59,7 +59,7 @@ namespace Avalonia.X11
private bool _useRenderWindow = false;
private bool _usePositioningFlags = false;
enum XSyncState
private enum XSyncState
{
None,
WaitConfigure,
@ -219,7 +219,7 @@ namespace Avalonia.X11
});
}
class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
private class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
{
private readonly X11Window _window;
private readonly IntPtr _display;
@ -249,7 +249,7 @@ namespace Avalonia.X11
public double Scaling => _window.RenderScaling;
}
void UpdateMotifHints()
private void UpdateMotifHints()
{
var functions = MotifFunctions.Move | MotifFunctions.Close | MotifFunctions.Resize |
MotifFunctions.Minimize | MotifFunctions.Maximize;
@ -278,7 +278,7 @@ namespace Avalonia.X11
PropertyMode.Replace, ref hints, 5);
}
void UpdateSizeHints(PixelSize? preResize)
private void UpdateSizeHints(PixelSize? preResize)
{
var min = _minMaxSize.minSize;
var max = _minMaxSize.maxSize;
@ -386,7 +386,7 @@ namespace Avalonia.X11
public IRenderer CreateRenderer(IRenderRoot root) =>
new CompositingRenderer(root, _platform.Compositor, () => Surfaces);
void OnEvent(ref XEvent ev)
private void OnEvent(ref XEvent ev)
{
if (ev.type == XEventName.MapNotify)
{
@ -668,7 +668,7 @@ namespace Avalonia.X11
}
static RawInputModifiers TranslateModifiers(XModifierMask state)
private static RawInputModifiers TranslateModifiers(XModifierMask state)
{
var rv = default(RawInputModifiers);
if (state.HasAllFlags(XModifierMask.Button1Mask))
@ -704,13 +704,13 @@ namespace Avalonia.X11
private double _scaling = 1;
void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
private void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
{
_x11.LastActivityTimestamp = xev.ButtonEvent.time;
ScheduleInput(args);
}
void DispatchInput(RawInputEventArgs args)
private void DispatchInput(RawInputEventArgs args)
{
Input?.Invoke(args);
if (!args.Handled && args is RawKeyEventArgsWithText text && !string.IsNullOrEmpty(text.Text))
@ -746,8 +746,8 @@ namespace Avalonia.X11
_rawEventGrouper.HandleEvent(args);
}
void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
private void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
{
var mev = new RawPointerEventArgs(
_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot,
@ -755,7 +755,7 @@ namespace Avalonia.X11
ScheduleInput(mev, ref ev);
}
void EnqueuePaint()
private void EnqueuePaint()
{
if (!_triggeredExpose)
{
@ -767,8 +767,8 @@ namespace Avalonia.X11
}, DispatcherPriority.Render);
}
}
void DoPaint()
private void DoPaint()
{
Paint?.Invoke(new Rect());
if (_xSyncCounter != IntPtr.Zero && _xSyncState == XSyncState.WaitPaint)
@ -819,8 +819,8 @@ namespace Avalonia.X11
return null;
}
void Cleanup()
private void Cleanup()
{
if (_rawEventGrouper != null)
{
@ -871,7 +871,7 @@ namespace Avalonia.X11
}
}
bool ActivateTransientChildIfNeeded()
private bool ActivateTransientChildIfNeeded()
{
if (_disabled)
{
@ -923,9 +923,9 @@ namespace Avalonia.X11
Resize(size, true, PlatformResizeReason.Layout);
}
PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * RenderScaling), (int)(size.Height * RenderScaling));
void Resize(Size clientSize, bool force, PlatformResizeReason reason)
private PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * RenderScaling), (int)(size.Height * RenderScaling));
private void Resize(Size clientSize, bool force, PlatformResizeReason reason)
{
if (!force && clientSize == ClientSize)
return;
@ -1020,7 +1020,7 @@ namespace Avalonia.X11
.OrderByDescending(x => x.Width + x.Height).FirstOrDefault();
void SendNetWMMessage(IntPtr message_type, IntPtr l0,
private void SendNetWMMessage(IntPtr message_type, IntPtr l0,
IntPtr? l1 = null, IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null)
{
var xev = new XEvent
@ -1044,7 +1044,7 @@ namespace Avalonia.X11
}
void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e)
private void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e)
{
var pos = GetCursorPos(_x11);
XUngrabPointer(_x11.Display, new IntPtr(0));
@ -1184,7 +1184,7 @@ namespace Avalonia.X11
ChangeWMAtoms(!value, _x11.Atoms._NET_WM_STATE_SKIP_TASKBAR);
}
void ChangeWMAtoms(bool enable, params IntPtr[] atoms)
private void ChangeWMAtoms(bool enable, params IntPtr[] atoms)
{
if (atoms.Length != 1 && atoms.Length != 2)
throw new ArgumentException();

5
src/Avalonia.X11/XError.cs

@ -2,11 +2,12 @@ using System;
namespace Avalonia.X11
{
static class XError
internal static class XError
{
private static readonly XErrorHandler s_errorHandlerDelegate = Handler;
public static XErrorEvent LastError;
static int Handler(IntPtr display, ref XErrorEvent error)
private static int Handler(IntPtr display, ref XErrorEvent error)
{
LastError = error;
return 0;

16
src/Avalonia.X11/XI2Manager.cs

@ -7,7 +7,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
unsafe class XI2Manager
internal unsafe class XI2Manager
{
private static readonly XiEventType[] DefaultEventTypes = new XiEventType[]
{
@ -30,7 +30,7 @@ namespace Avalonia.X11
private bool _multitouch;
private Dictionary<IntPtr, IXI2Client> _clients = new Dictionary<IntPtr, IXI2Client>();
class DeviceInfo
private class DeviceInfo
{
public int Id { get; }
public XIValuatorClassInfo[] Valuators { get; private set; }
@ -67,7 +67,7 @@ namespace Avalonia.X11
}
}
class PointerDeviceInfo : DeviceInfo
private class PointerDeviceInfo : DeviceInfo
{
public PointerDeviceInfo(XIDeviceInfo info) : base(info)
{
@ -197,7 +197,7 @@ namespace Avalonia.X11
}
}
void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
private void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
{
if (ev.evtype == XiEventType.XI_Leave)
{
@ -215,7 +215,7 @@ namespace Avalonia.X11
}
}
void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
private void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
{
if (ev.Type == XiEventType.XI_TouchBegin
|| ev.Type == XiEventType.XI_TouchUpdate
@ -304,7 +304,7 @@ namespace Avalonia.X11
}
}
unsafe class ParsedDeviceEvent
internal unsafe class ParsedDeviceEvent
{
public XiEventType Type { get; }
public RawInputModifiers Modifiers { get; }
@ -367,8 +367,8 @@ namespace Avalonia.X11
Emulated = ev->flags.HasAllFlags(XiDeviceEventFlags.XIPointerEmulated);
}
}
interface IXI2Client
internal interface IXI2Client
{
IInputRoot InputRoot { get; }
void ScheduleXI2Input(RawInputEventArgs args);

54
src/Avalonia.X11/XIStructs.cs

@ -10,7 +10,7 @@ using Atom = System.IntPtr;
namespace Avalonia.X11
{
[StructLayout(LayoutKind.Sequential)]
struct XIAddMasterInfo
internal struct XIAddMasterInfo
{
public int Type;
public IntPtr Name;
@ -19,7 +19,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
struct XIRemoveMasterInfo
internal struct XIRemoveMasterInfo
{
public int Type;
public int Deviceid;
@ -29,7 +29,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
struct XIAttachSlaveInfo
internal struct XIAttachSlaveInfo
{
public int Type;
public int Deviceid;
@ -37,14 +37,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
struct XIDetachSlaveInfo
internal struct XIDetachSlaveInfo
{
public int Type;
public int Deviceid;
};
[StructLayout(LayoutKind.Explicit)]
struct XIAnyHierarchyChangeInfo
internal struct XIAnyHierarchyChangeInfo
{
[FieldOffset(0)]
public int type; /* must be first element */
@ -59,7 +59,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
struct XIModifierState
internal struct XIModifierState
{
public int Base;
public int Latched;
@ -68,14 +68,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIButtonState
internal unsafe struct XIButtonState
{
public int MaskLen;
public byte* Mask;
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIValuatorState
internal unsafe struct XIValuatorState
{
public int MaskLen;
public byte* Mask;
@ -83,7 +83,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEventMask
internal unsafe struct XIEventMask
{
public int Deviceid;
public int MaskLen;
@ -91,14 +91,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
struct XIAnyClassInfo
internal struct XIAnyClassInfo
{
public XiDeviceClass Type;
public int Sourceid;
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIButtonClassInfo
internal unsafe struct XIButtonClassInfo
{
public int Type;
public int Sourceid;
@ -108,7 +108,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIKeyClassInfo
internal unsafe struct XIKeyClassInfo
{
public int Type;
public int Sourceid;
@ -117,7 +117,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
struct XIValuatorClassInfo
internal struct XIValuatorClassInfo
{
public int Type;
public int Sourceid;
@ -132,7 +132,7 @@ namespace Avalonia.X11
/* new in XI 2.1 */
[StructLayout(LayoutKind.Sequential)]
struct XIScrollClassInfo
internal struct XIScrollClassInfo
{
public int Type;
public int Sourceid;
@ -142,14 +142,14 @@ namespace Avalonia.X11
public int Flags;
};
enum XiScrollType
internal enum XiScrollType
{
Vertical = 1,
Horizontal = 2
}
[StructLayout(LayoutKind.Sequential)]
struct XITouchClassInfo
internal struct XITouchClassInfo
{
public int Type;
public int Sourceid;
@ -158,7 +158,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIDeviceInfo
internal unsafe struct XIDeviceInfo
{
public int Deviceid;
public IntPtr Name;
@ -169,7 +169,7 @@ namespace Avalonia.X11
public XIAnyClassInfo** Classes;
}
enum XiDeviceType
internal enum XiDeviceType
{
XIMasterPointer = 1,
XIMasterKeyboard = 2,
@ -178,13 +178,13 @@ namespace Avalonia.X11
XIFloatingSlave = 5
}
enum XiPredefinedDeviceId : int
internal enum XiPredefinedDeviceId : int
{
XIAllDevices = 0,
XIAllMasterDevices = 1
}
enum XiDeviceClass
internal enum XiDeviceClass
{
XIKeyClass = 0,
XIButtonClass = 1,
@ -194,7 +194,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIDeviceChangedEvent
internal unsafe struct XIDeviceChangedEvent
{
public int Type; /* GenericEvent */
public UIntPtr Serial; /* # of last request processed by server */
@ -211,7 +211,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
struct XIDeviceEvent
internal struct XIDeviceEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@ -238,7 +238,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEnterLeaveEvent
internal unsafe struct XIEnterLeaveEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@ -266,14 +266,14 @@ namespace Avalonia.X11
}
[Flags]
public enum XiDeviceEventFlags : int
internal enum XiDeviceEventFlags : int
{
None = 0,
XIPointerEmulated = (1 << 16)
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEvent
internal unsafe struct XIEvent
{
public int type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@ -284,7 +284,7 @@ namespace Avalonia.X11
public IntPtr time;
}
enum XiEventType
internal enum XiEventType
{
XI_DeviceChanged = 1,
XI_KeyPress = 2,
@ -315,7 +315,7 @@ namespace Avalonia.X11
XI_LASTEVENT = XI_BarrierLeave,
}
enum XiEnterLeaveDetail
internal enum XiEnterLeaveDetail
{
XINotifyAncestor = 0,
XINotifyVirtual = 1,

10
src/Avalonia.X11/XLib.cs

@ -16,11 +16,11 @@ namespace Avalonia.X11
{
internal unsafe static class XLib
{
const string libX11 = "libX11.so.6";
const string libX11Randr = "libXrandr.so.2";
const string libX11Ext = "libXext.so.6";
const string libXInput = "libXi.so.6";
const string libXCursor = "libXcursor.so.1";
private const string libX11 = "libX11.so.6";
private const string libX11Randr = "libXrandr.so.2";
private const string libX11Ext = "libXext.so.6";
private const string libXInput = "libXi.so.6";
private const string libXCursor = "libXcursor.so.1";
[DllImport(libX11)]
public static extern IntPtr XOpenDisplay(IntPtr display);

27
src/Browser/Avalonia.Browser/AvaloniaView.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices.JavaScript;
using Avalonia.Browser.Interop;
@ -15,6 +16,7 @@ using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using SkiaSharp;
using static System.Runtime.CompilerServices.RuntimeHelpers;
namespace Avalonia.Browser
{
@ -94,6 +96,7 @@ namespace Avalonia.Browser
InputHelper.SubscribeTextEvents(
_inputElement,
OnBeforeInput,
OnTextInput,
OnCompositionStart,
OnCompositionUpdate,
@ -316,6 +319,30 @@ namespace Avalonia.Browser
return _topLevelImpl.RawTextEvent(data);
}
private bool OnBeforeInput(JSObject arg, int start, int end)
{
var type = arg.GetPropertyAsString("inputType");
if (type != "deleteByComposition")
{
if (type == "deleteContentBackward")
{
start = _inputElement.GetPropertyAsInt32("selectionStart");
end = _inputElement.GetPropertyAsInt32("selectionEnd");
}
else
{
start = -1;
end = -1;
}
}
if(start != -1 && end != -1 && _client != null)
{
_client.SelectInSurroundingText(start, end);
}
return false;
}
private bool OnCompositionStart (JSObject args)
{
if (_client == null)

2
src/Browser/Avalonia.Browser/Interop/InputHelper.cs

@ -18,6 +18,8 @@ internal static partial class InputHelper
[JSImport("InputHelper.subscribeTextEvents", AvaloniaModule.MainModuleName)]
public static partial void SubscribeTextEvents(
JSObject htmlElement,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Number, JSType.Number, JSType.Boolean>>]
Func<JSObject, int, int, bool> onBeforeInput,
[JSMarshalAs<JSType.Function<JSType.String, JSType.String, JSType.Boolean>>]
Func<string, string?, bool> onInput,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Boolean>>]

2
src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs

@ -6,7 +6,7 @@ using Avalonia.Reactive;
namespace Avalonia.Browser.Skia
{
public class BrowserSkiaGpu : ISkiaGpu
internal class BrowserSkiaGpu : ISkiaGpu
{
public ISkiaGpuRenderTarget? TryCreateRenderTarget(IEnumerable<object> surfaces)
{

20
src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts

@ -47,6 +47,7 @@ export class InputHelper {
public static subscribeTextEvents(
element: HTMLInputElement,
beforeInputCallback: (args: InputEvent, start: number, end: number) => boolean,
inputCallback: (type: string, data: string | null) => boolean,
compositionStartCallback: (args: CompositionEvent) => boolean,
compositionUpdateCallback: (args: CompositionEvent) => boolean,
@ -68,6 +69,25 @@ export class InputHelper {
};
element.addEventListener("compositionstart", compositionStartHandler);
const beforeInputHandler = (args: InputEvent) => {
const ranges = args.getTargetRanges();
let start = -1;
let end = -1;
if (ranges.length > 0) {
start = ranges[0].startOffset;
end = ranges[0].endOffset;
}
if (args.inputType === "insertCompositionText") {
start = 2;
end = start + 2;
}
if (beforeInputCallback(args, start, end)) {
args.preventDefault();
}
};
element.addEventListener("beforeinput", beforeInputHandler);
const compositionUpdateHandler = (args: CompositionEvent) => {
if (compositionUpdateCallback(args)) {
args.preventDefault();

4
src/Shared/RawEventGrouping.cs

@ -17,8 +17,8 @@ internal class RawEventGrouper : IDisposable
private readonly Action<RawInputEventArgs> _eventCallback;
private readonly Queue<RawInputEventArgs> _inputQueue = new();
private readonly Action _dispatchFromQueue;
readonly Dictionary<long, RawPointerEventArgs> _lastTouchPoints = new();
RawInputEventArgs? _lastEvent;
private readonly Dictionary<long, RawPointerEventArgs> _lastTouchPoints = new();
private RawInputEventArgs? _lastEvent;
public RawEventGrouper(Action<RawInputEventArgs> eventCallback)
{

5
src/Skia/Avalonia.Skia/GlyphRunImpl.cs

@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using Avalonia.Metadata;
using Avalonia.Platform;
using SkiaSharp;
#nullable enable
namespace Avalonia.Skia
{
/// <inheritdoc />
[Unstable]
public class GlyphRunImpl : IGlyphRunImpl
internal class GlyphRunImpl : IGlyphRunImpl
{
public GlyphRunImpl(SKTextBlob textBlob, Size size, Point baselineOrigin)
{

4
src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

@ -1,14 +1,12 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Media;
using Avalonia.Metadata;
using HarfBuzzSharp;
using SkiaSharp;
namespace Avalonia.Skia
{
[Unstable]
public class GlyphTypefaceImpl : IGlyphTypeface
internal class GlyphTypefaceImpl : IGlyphTypeface
{
private bool _isDisposed;

2
src/Skia/Avalonia.Skia/SKTypefaceCollection.cs

@ -4,7 +4,7 @@ using SkiaSharp;
namespace Avalonia.Skia
{
public class SKTypefaceCollection
internal class SKTypefaceCollection
{
private readonly ConcurrentDictionary<Typeface, SKTypeface> _typefaces =
new ConcurrentDictionary<Typeface, SKTypeface>();

2
src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs

@ -7,7 +7,7 @@ using SkiaSharp;
namespace Avalonia.Skia
{
public static class SKTypefaceCollectionCache
internal static class SKTypefaceCollectionCache
{
private static readonly ConcurrentDictionary<FontFamily, SKTypefaceCollection> s_cachedCollections;

22
src/Skia/Avalonia.Skia/readme.md

@ -1,22 +0,0 @@
DrawingContextImpl
- Alpha support missing as SkiaSharp does not expose this
- Gradient Shader caching?
- Pen Dash styles
Formatted Text Rendering
- Minor polish
Linux
- Need gpu platform implementation
macOS
- Need gpu platform implementation
Android
- Not tested at all yet
iOS
- Not tested at all yet
General
- Get Skia Unit Tests passing (most of the issues are related to antialiasing)

6
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -5,11 +5,6 @@
<PackageId>Avalonia.Direct2D1</PackageId>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Win32\Interop\UnmanagedMethods.cs">
<Link>UnmanagedMethods.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Avalonia.Win32\Avalonia.Win32.csproj" />
@ -22,6 +17,7 @@
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Direct2D1.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32.Interop, PublicKey=$(AvaloniaPublicKey)"/>
</ItemGroup>
<ItemGroup>

2
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -27,7 +27,7 @@ namespace Avalonia
namespace Avalonia.Direct2D1
{
public class Direct2D1Platform : IPlatformRenderInterface
internal class Direct2D1Platform : IPlatformRenderInterface
{
private static readonly Direct2D1Platform s_instance = new Direct2D1Platform();

33
src/Windows/Avalonia.Direct2D1/Disposable.cs

@ -1,33 +0,0 @@
using System;
namespace Avalonia.Direct2D1
{
public class Disposable<T> : IDisposable where T : IDisposable
{
private readonly IDisposable _extra;
public Disposable(T inner)
{
Inner = inner;
}
public Disposable(T inner, IDisposable extra)
{
Inner = inner;
_extra = extra;
}
public T Inner { get; }
public static implicit operator T(Disposable<T> i)
{
return i.Inner;
}
public void Dispose()
{
Inner.Dispose();
_extra?.Dispose();
}
}
}

2
src/Windows/Avalonia.Direct2D1/ILayerFactory.cs

@ -2,7 +2,7 @@
namespace Avalonia.Direct2D1
{
public interface ILayerFactory
internal interface ILayerFactory
{
IDrawingContextLayerImpl CreateLayer(Size size);
}

4
src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs

@ -1,10 +1,8 @@
using System;
using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
[Unstable]
public abstract class BrushImpl : IDisposable
internal abstract class BrushImpl : IDisposable
{
public SharpDX.Direct2D1.Brush PlatformBrush { get; set; }

4
src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs

@ -6,7 +6,7 @@ namespace Avalonia.Direct2D1.Media
/// <summary>
/// Resource FontFileEnumerator.
/// </summary>
public class DWriteResourceFontFileEnumerator : CallbackBase, FontFileEnumerator
internal class DWriteResourceFontFileEnumerator : CallbackBase, FontFileEnumerator
{
private readonly Factory _factory;
private readonly FontFileLoader _loader;
@ -64,4 +64,4 @@ namespace Avalonia.Direct2D1.Media
}
}
}
}
}

2
src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs

@ -7,7 +7,7 @@ namespace Avalonia.Direct2D1.Media
/// <summary>
/// This FontFileStream implementation is reading data from a <see cref="DataStream"/>.
/// </summary>
public class DWriteResourceFontFileStream : CallbackBase, FontFileStream
internal class DWriteResourceFontFileStream : CallbackBase, FontFileStream
{
private readonly DataStream _stream;

4
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -11,15 +11,13 @@ using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using BitmapInterpolationMode = Avalonia.Media.Imaging.BitmapInterpolationMode;
using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
/// <summary>
/// Draws using Direct2D1.
/// </summary>
[Unstable]
public class DrawingContextImpl : IDrawingContextImpl
internal class DrawingContextImpl : IDrawingContextImpl
{
private readonly IVisualBrushRenderer _visualBrushRenderer;
private readonly ILayerFactory _layerFactory;

4
src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs

@ -1,5 +1,4 @@
using Avalonia.Logging;
using Avalonia.Metadata;
using Avalonia.Platform;
using SharpDX.Direct2D1;
@ -8,8 +7,7 @@ namespace Avalonia.Direct2D1.Media
/// <summary>
/// The platform-specific interface for <see cref="Avalonia.Media.Geometry"/>.
/// </summary>
[Unstable]
public abstract class GeometryImpl : IGeometryImpl
internal abstract class GeometryImpl : IGeometryImpl
{
private const float ContourApproximation = 0.0001f;

4
src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs

@ -1,6 +1,5 @@
using System;
using Avalonia.Media;
using Avalonia.Metadata;
using HarfBuzzSharp;
using SharpDX.DirectWrite;
using FontMetrics = Avalonia.Media.FontMetrics;
@ -9,8 +8,7 @@ using GlyphMetrics = Avalonia.Media.GlyphMetrics;
namespace Avalonia.Direct2D1.Media
{
[Unstable]
public class GlyphTypefaceImpl : IGlyphTypeface
internal class GlyphTypefaceImpl : IGlyphTypeface
{
private bool _isDisposed;

4
src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@ -1,13 +1,11 @@
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Rendering.Utilities;
using Avalonia.Utilities;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
[Unstable]
public sealed class ImageBrushImpl : BrushImpl
internal sealed class ImageBrushImpl : BrushImpl
{
private readonly OptionalDispose<Bitmap> _bitmap;

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs

@ -1,13 +1,11 @@
using System;
using System.IO;
using Avalonia.Metadata;
using Avalonia.Platform;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
namespace Avalonia.Direct2D1.Media
{
[Unstable]
public abstract class BitmapImpl : IBitmapImpl, IDisposable
internal abstract class BitmapImpl : IBitmapImpl, IDisposable
{
public abstract Vector Dpi { get; }
public abstract PixelSize PixelSize { get; }

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs

@ -1,6 +1,5 @@
using System;
using System.IO;
using Avalonia.Metadata;
using SharpDX.WIC;
using Bitmap = SharpDX.Direct2D1.Bitmap;
@ -9,8 +8,7 @@ namespace Avalonia.Direct2D1.Media
/// <summary>
/// A Direct2D Bitmap implementation that uses a GPU memory bitmap as its image.
/// </summary>
[Unstable]
public class D2DBitmapImpl : BitmapImpl
internal class D2DBitmapImpl : BitmapImpl
{
private readonly Bitmap _direct2DBitmap;

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs

@ -1,6 +1,5 @@
using System;
using System.IO;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Utilities;
@ -10,8 +9,7 @@ using D2DBitmap = SharpDX.Direct2D1.Bitmap;
namespace Avalonia.Direct2D1.Media.Imaging
{
[Unstable]
public class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory
internal class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory
{
private readonly BitmapRenderTarget _renderTarget;

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs

@ -6,7 +6,6 @@ using SharpDX.WIC;
using APixelFormat = Avalonia.Platform.PixelFormat;
using AlphaFormat = Avalonia.Platform.AlphaFormat;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
using Avalonia.Metadata;
using Avalonia.Platform;
using PixelFormat = SharpDX.WIC.PixelFormat;
@ -15,8 +14,7 @@ namespace Avalonia.Direct2D1.Media
/// <summary>
/// A WIC implementation of a <see cref="Avalonia.Media.Imaging.Bitmap"/>.
/// </summary>
[Unstable]
public class WicBitmapImpl : BitmapImpl, IReadableBitmapImpl
internal class WicBitmapImpl : BitmapImpl, IReadableBitmapImpl
{
private readonly BitmapDecoder _decoder;

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs

@ -1,13 +1,11 @@
using System;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
[Unstable]
public class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl
internal class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl
{
private readonly WicRenderTarget _renderTarget;

2
src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs

@ -6,7 +6,7 @@ using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Direct2D1.Media.Imaging
{
class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
internal class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
{
public WriteableWicBitmapImpl(Stream stream, int decodeSize, bool horizontal,
Avalonia.Media.Imaging.BitmapInterpolationMode interpolationMode)

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save