Browse Source

Merge branch 'master' into feature/TabControlRework

pull/1842/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
c42a477fe6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      native/Avalonia.Native/inc/avalonia-native.h
  2. 9
      native/Avalonia.Native/src/OSX/common.h
  3. 24
      native/Avalonia.Native/src/OSX/main.mm
  4. 2
      native/Avalonia.Native/src/OSX/window.h
  5. 125
      native/Avalonia.Native/src/OSX/window.mm
  6. 5
      samples/ControlCatalog/Pages/DialogsPage.xaml
  7. 14
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  8. 2
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  9. 16
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  10. 1
      scripts/ReplaceNugetCache.sh
  11. 5
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  12. 6
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  13. 31
      src/Avalonia.Controls/SystemDialog.cs
  14. 1
      src/Avalonia.Controls/TextBox.cs
  15. 38
      src/Avalonia.Controls/Window.cs
  16. 5
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  17. 6
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  18. 6
      src/Avalonia.Layout/Properties/AssemblyInfo.cs
  19. 23
      src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs
  20. 108
      src/Avalonia.Native/DeferredRendererProxy.cs
  21. 4
      src/Avalonia.Native/GlPlatformFeature.cs
  22. 4
      src/Avalonia.Native/WindowImpl.cs
  23. 8
      src/Avalonia.Native/WindowImplBase.cs
  24. 44
      src/Avalonia.OpenGL/EglContext.cs
  25. 53
      src/Avalonia.OpenGL/EglDisplay.cs
  26. 4
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  27. 32
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  28. 28
      src/Avalonia.OpenGL/EglSurface.cs
  29. 4
      src/Avalonia.OpenGL/IGlContext.cs
  30. 10
      src/Avalonia.OpenGL/IGlSurface.cs
  31. 28
      src/Avalonia.Themes.Default/ButtonSpinner.xaml
  32. 29
      src/Avalonia.Themes.Default/NumericUpDown.xaml
  33. 5
      src/Avalonia.Themes.Default/TextBox.xaml
  34. 35
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  35. 9
      src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs
  36. 17
      src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs
  37. 4
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  38. 4
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  39. 13
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  40. 2
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  41. 18
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  42. 9
      src/Windows/Avalonia.Win32/Win32Platform.cs
  43. 31
      src/Windows/Avalonia.Win32/WindowImpl.cs
  44. 14
      tests/Avalonia.Controls.UnitTests/CursorFactoryMock.cs
  45. 7
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  46. 2
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

2
native/Avalonia.Native/inc/avalonia-native.h

@ -213,7 +213,7 @@ AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{ {
virtual HRESULT ShowDialog (IUnknown**ppv) = 0; virtual HRESULT ShowDialog (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetHasDecorations(bool value) = 0; virtual HRESULT SetHasDecorations(bool value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitle (void* utf8Title) = 0;

9
native/Avalonia.Native/src/OSX/common.h

@ -31,4 +31,13 @@ extern NSSize ToNSSize (AvnSize s);
#define NSDebugLog(...) (void)0 #define NSDebugLog(...) (void)0
#endif #endif
template<typename T> inline T* objc_cast(id from) {
if(from == nil)
return nil;
if ([from isKindOfClass:[T class]]) {
return static_cast<T*>(from);
}
return nil;
}
#endif #endif

24
native/Avalonia.Native/src/OSX/main.mm

@ -32,27 +32,23 @@ public:
- (void) do; - (void) do;
@end @end
@implementation ThreadingInitializer @implementation ThreadingInitializer
{
pthread_mutex_t mutex; int _fds[2];
pthread_cond_t cond; }
- (void) runOnce - (void) runOnce
{ {
pthread_mutex_lock(&mutex); char buf[]={0};
pthread_cond_signal(&cond); write(_fds[1], buf, 1);
pthread_mutex_unlock(&mutex);
} }
- (void) do - (void) do
{ {
pthread_mutex_init(&mutex, NULL); pipe(_fds);
pthread_cond_init(&cond, NULL);
[[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start]; [[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start];
pthread_mutex_lock(&mutex); char buf[1];
pthread_cond_wait(&cond, &mutex); read(_fds[0], buf, 1);
pthread_mutex_unlock(&mutex); close(_fds[0]);
pthread_cond_destroy(&cond); close(_fds[1]);
pthread_mutex_destroy(&mutex);
} }

2
native/Avalonia.Native/src/OSX/window.h

@ -18,6 +18,8 @@ class WindowBaseImpl;
-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent; -(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
-(void) setCanBecomeKeyAndMain; -(void) setCanBecomeKeyAndMain;
-(void) pollModalSession: (NSModalSession _Nonnull) session; -(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents;
@end @end
struct INSWindowHolder struct INSWindowHolder

125
native/Avalonia.Native/src/OSX/window.mm

@ -109,6 +109,7 @@ public:
if(Window != nullptr) if(Window != nullptr)
{ {
[Window orderOut:Window]; [Window orderOut:Window];
[Window restoreParentWindow];
} }
return S_OK; return S_OK;
@ -392,30 +393,6 @@ protected:
} }
}; };
class ModalDisposable : public ComUnknownObject
{
NSModalSession _session;
AvnWindow* _window;
void Dispose ()
{
[_window orderOut:_window];
[NSApp endModalSession:_session];
}
public:
ModalDisposable(AvnWindow* window, NSModalSession session)
{
_session = session;
_window = window;
}
virtual ~ModalDisposable()
{
Dispose();
}
};
class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
{ {
private: private:
@ -444,32 +421,27 @@ private:
{ {
@autoreleasepool @autoreleasepool
{ {
if([Window parentWindow] != nil)
[[Window parentWindow] removeChildWindow:Window];
WindowBaseImpl::Show(); WindowBaseImpl::Show();
return SetWindowState(_lastWindowState); return SetWindowState(_lastWindowState);
} }
} }
virtual HRESULT ShowDialog (IUnknown**ppv) override virtual HRESULT ShowDialog (IAvnWindow* parent) override
{ {
@autoreleasepool @autoreleasepool
{ {
if(ppv == nullptr) if(parent == nullptr)
{
return E_POINTER; return E_POINTER;
}
auto cparent = dynamic_cast<WindowImpl*>(parent);
auto session = [NSApp beginModalSessionForWindow:Window]; if(cparent == nullptr)
auto disposable = new ModalDisposable(Window, session); return E_INVALIDARG;
*ppv = disposable;
SetPosition(lastPositionSet);
UpdateStyle();
[Window setTitle:_lastTitle];
[Window setTitleVisibility:NSWindowTitleVisible];
[Window pollModalSession:session]; [cparent->Window addChildWindow:Window ordered:NSWindowAbove];
WindowBaseImpl::Show();
return S_OK; return S_OK;
} }
@ -843,8 +815,19 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[super viewDidChangeBackingProperties]; [super viewDidChangeBackingProperties];
} }
- (bool) ignoreUserInput
{
auto parentWindow = objc_cast<AvnWindow>([self window]);
if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
return TRUE;
return FALSE;
}
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
{ {
if([self ignoreUserInput])
return;
[self becomeFirstResponder]; [self becomeFirstResponder];
auto localPoint = [self convertPoint:[event locationInWindow] toView:self]; auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
auto avnPoint = [self toAvnPoint:localPoint]; auto avnPoint = [self toAvnPoint:localPoint];
@ -952,7 +935,9 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type - (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{ {
if([self ignoreUserInput])
return;
auto key = s_KeyMap[[event keyCode]]; auto key = s_KeyMap[[event keyCode]];
auto timestamp = [event timestamp] * 1000; auto timestamp = [event timestamp] * 1000;
@ -1125,13 +1110,15 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{ {
ComPtr<WindowBaseImpl> parent = _parent; ComPtr<WindowBaseImpl> parent = _parent;
_parent = NULL; _parent = NULL;
[self restoreParentWindow];
parent->BaseEvents->Closed(); parent->BaseEvents->Closed();
[parent->View onClosed]; [parent->View onClosed];
[self setContentView: nil]; dispatch_async(dispatch_get_main_queue(), ^{
[self setContentView: nil];
});
} }
} }
-(BOOL)canBecomeKeyWindow -(BOOL)canBecomeKeyWindow
{ {
return _canBecomeKeyAndMain; return _canBecomeKeyAndMain;
@ -1142,12 +1129,62 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return _canBecomeKeyAndMain; return _canBecomeKeyAndMain;
} }
-(bool) activateAppropriateChild: (bool)activating
{
for(NSWindow* uch in [self childWindows])
{
auto ch = objc_cast<AvnWindow>(uch);
if(ch == nil)
continue;
[ch activateAppropriateChild:false];
return FALSE;
}
if(!activating)
[self makeKeyAndOrderFront:self];
return TRUE;
}
-(bool)shouldTryToHandleEvents
{
for(NSWindow* uch in [self childWindows])
{
auto ch = objc_cast<AvnWindow>(uch);
if(ch == nil)
continue;
return FALSE;
}
return TRUE;
}
-(void)makeKeyWindow
{
if([self activateAppropriateChild: true])
{
[super makeKeyWindow];
}
}
-(void)becomeKeyWindow -(void)becomeKeyWindow
{ {
_parent->BaseEvents->Activated(); if([self activateAppropriateChild: true])
[super becomeKeyWindow]; {
_parent->BaseEvents->Activated();
[super becomeKeyWindow];
}
}
-(void) restoreParentWindow;
{
auto parent = objc_cast<AvnWindow>([self parentWindow]);
if(parent != nil)
{
[parent removeChildWindow:self];
[parent activateAppropriateChild: false];
}
} }
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
{ {
return true; return true;

5
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -3,10 +3,7 @@
<Button Name="OpenFile">Open File</Button> <Button Name="OpenFile">Open File</Button>
<Button Name="SaveFile">Save File</Button> <Button Name="SaveFile">Save File</Button>
<Button Name="SelectFolder">Select Folder</Button> <Button Name="SelectFolder">Select Folder</Button>
<StackPanel Orientation="Horizontal">
<CheckBox Name="IsModal" IsChecked="True"/>
<TextBlock>Modal to window</TextBlock>
</StackPanel>
<Button Name="DecoratedWindow">Decorated window</Button> <Button Name="DecoratedWindow">Decorated window</Button>
<Button Name="Dialog">Dialog</Button>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

14
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -31,12 +31,18 @@ namespace ControlCatalog.Pages
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
}; };
this.FindControl<Button>("DecoratedWindow").Click += delegate this.FindControl<Button>("DecoratedWindow").Click += delegate
{ {
new DecoratedWindow().Show(); new DecoratedWindow().ShowDialog(GetWindow());
}; };
this.FindControl<Button>("Dialog").Click += delegate
{
new MainWindow().ShowDialog(GetWindow());
};
} }
Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked.Value ? (Window)this.VisualRoot : null; Window GetWindow() => (Window)this.VisualRoot;
private void InitializeComponent() private void InitializeComponent()
{ {

2
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@ -83,7 +83,7 @@ namespace ControlCatalog.Pages
public async Task Open() public async Task Open()
{ {
var dialog = new OpenFileDialog(); var dialog = new OpenFileDialog();
var result = await dialog.ShowAsync(); var result = await dialog.ShowAsync(App.Current.MainWindow);
if (result != null) if (result != null)
{ {

16
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -6,7 +6,7 @@
<TextBlock Margin="2,5,2,2" FontSize="14" FontWeight="Bold">Features:</TextBlock> <TextBlock Margin="2,5,2,2" FontSize="14" FontWeight="Bold">Features:</TextBlock>
<Grid Margin="2" ColumnDefinitions="Auto,Auto,Auto,Auto" RowDefinitions="Auto,Auto"> <Grid Margin="2" ColumnDefinitions="Auto,Auto,Auto,Auto" RowDefinitions="Auto,Auto">
<Grid Grid.Row="0" Grid.Column="0" ColumnDefinitions="Auto, Auto" RowDefinitions="35,35,35,35,35"> <Grid Grid.Row="0" Grid.Column="0" ColumnDefinitions="Auto, Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">ShowButtonSpinner:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">ShowButtonSpinner:</TextBlock>
<CheckBox Grid.Row="0" Grid.Column="1" IsChecked="{Binding #upDown.ShowButtonSpinner}" VerticalAlignment="Center" Margin="2"/> <CheckBox Grid.Row="0" Grid.Column="1" IsChecked="{Binding #upDown.ShowButtonSpinner}" VerticalAlignment="Center" Margin="2"/>
@ -20,7 +20,7 @@
<CheckBox Grid.Row="3" Grid.Column="1" IsChecked="{Binding #upDown.ClipValueToMinMax}" VerticalAlignment="Center" Margin="2"/> <CheckBox Grid.Row="3" Grid.Column="1" IsChecked="{Binding #upDown.ClipValueToMinMax}" VerticalAlignment="Center" Margin="2"/>
</Grid> </Grid>
<Grid Grid.Row="0" Grid.Column="1" Margin="10,2,2,2" ColumnDefinitions="Auto, 120" RowDefinitions="35,35,35,35,35"> <Grid Grid.Row="0" Grid.Column="1" Margin="10,2,2,2" ColumnDefinitions="Auto, 120" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">FormatString:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="2">FormatString:</TextBlock>
<DropDown Grid.Row="0" Grid.Column="1" Items="{Binding Formats}" SelectedItem="{Binding SelectedFormat}" <DropDown Grid.Row="0" Grid.Column="1" Items="{Binding Formats}" SelectedItem="{Binding SelectedFormat}"
VerticalAlignment="Center" Margin="2"> VerticalAlignment="Center" Margin="2">
@ -49,22 +49,22 @@
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Margin="2">Text:</TextBlock> <TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Margin="2">Text:</TextBlock>
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding #upDown.Text}" VerticalAlignment="Center" Margin="2" /> <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding #upDown.Text}" VerticalAlignment="Center" Margin="2" />
</Grid> </Grid>
<Grid Grid.Row="0" Grid.Column="2" Margin="10,2,2,2" RowDefinitions="35,35,35,35,35" ColumnDefinitions="Auto, 120"> <Grid Grid.Row="0" Grid.Column="2" Margin="10,2,2,2" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, 120">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Minimum:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Minimum:</TextBlock>
<NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding #upDown.Minimum}" <NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding #upDown.Minimum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Height="25" Margin="2" Width="70" HorizontalAlignment="Center"/> CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" Width="70" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Maximum:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Maximum:</TextBlock>
<NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding #upDown.Maximum}" <NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding #upDown.Maximum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Height="25" Margin="2" Width="70" HorizontalAlignment="Center"/> CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" Width="70" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Increment:</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Increment:</TextBlock>
<NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center" <NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center"
Height="25" Margin="2" Width="70" HorizontalAlignment="Center"/> Margin="2" Width="70" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock> <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock>
<NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center" <NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center"
Height="25" Margin="2" Width="70" HorizontalAlignment="Center"/> Margin="2" Width="70" HorizontalAlignment="Center"/>
</Grid> </Grid>
</Grid> </Grid>
@ -72,7 +72,7 @@
<StackPanel Margin="2,10,2,2" Orientation="Horizontal" Spacing="10"> <StackPanel Margin="2,10,2,2" Orientation="Horizontal" Spacing="10">
<TextBlock FontSize="14" FontWeight="Bold" VerticalAlignment="Center">Usage of NumericUpDown:</TextBlock> <TextBlock FontSize="14" FontWeight="Bold" VerticalAlignment="Center">Usage of NumericUpDown:</TextBlock>
<NumericUpDown Name="upDown" Minimum="0" Maximum="10" Increment="0.5" <NumericUpDown Name="upDown" Minimum="0" Maximum="10" Increment="0.5"
CultureInfo="en-US" VerticalAlignment="Center" Height="25" Width="100" CultureInfo="en-US" VerticalAlignment="Center" Width="100"
Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}"/> Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}"/>
</StackPanel> </StackPanel>

1
scripts/ReplaceNugetCache.sh

@ -4,5 +4,6 @@
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.native/$1/lib/netstandard2.0/

5
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -30,10 +30,7 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Shows the window as a dialog. /// Shows the window as a dialog.
/// </summary> /// </summary>
/// <returns> void ShowDialog(IWindowImpl parent);
/// An <see cref="IDisposable"/> that should be used to close the window.
/// </returns>
IDisposable ShowDialog();
/// <summary> /// <summary>
/// Enables or disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)

6
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -84,8 +84,10 @@ namespace Avalonia.Controls.Primitives
if (screen != null) if (screen != null)
{ {
var screenX = Position.X + Bounds.Width - screen.Bounds.X; var scaling = VisualRoot.RenderScaling;
var screenY = Position.Y + Bounds.Height - screen.Bounds.Y;
var screenX = Position.X + (Bounds.Width * scaling) - screen.Bounds.X;
var screenY = Position.Y + (Bounds.Height * scaling) - screen.Bounds.Y;
if (screenX > screen.Bounds.Width) if (screenX > screen.Bounds.Width)
{ {

31
src/Avalonia.Controls/SystemDialog.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -18,28 +19,40 @@ namespace Avalonia.Controls
public class SaveFileDialog : FileDialog public class SaveFileDialog : FileDialog
{ {
public string DefaultExtension { get; set; } public string DefaultExtension { get; set; }
public async Task<string> ShowAsync(Window window) public async Task<string> ShowAsync(Window parent)
=> {
((await AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFileDialogAsync(this, window?.PlatformImpl)) ?? if(parent == null)
new string[0]).FirstOrDefault(); throw new ArgumentNullException(nameof(parent));
return ((await AvaloniaLocator.Current.GetService<ISystemDialogImpl>()
.ShowFileDialogAsync(this, parent?.PlatformImpl)) ??
new string[0]).FirstOrDefault();
}
} }
public class OpenFileDialog : FileDialog public class OpenFileDialog : FileDialog
{ {
public bool AllowMultiple { get; set; } public bool AllowMultiple { get; set; }
public Task<string[]> ShowAsync(Window window = null) public Task<string[]> ShowAsync(Window parent)
=> AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFileDialogAsync(this, window?.PlatformImpl); {
if(parent == null)
throw new ArgumentNullException(nameof(parent));
return AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFileDialogAsync(this, parent?.PlatformImpl);
}
} }
public class OpenFolderDialog : FileSystemDialog public class OpenFolderDialog : FileSystemDialog
{ {
public string DefaultDirectory { get; set; } public string DefaultDirectory { get; set; }
public Task<string> ShowAsync(Window window = null) public Task<string> ShowAsync(Window parent)
=> AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFolderDialogAsync(this, window?.PlatformImpl); {
if(parent == null)
throw new ArgumentNullException(nameof(parent));
return AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFolderDialogAsync(this, parent?.PlatformImpl);
}
} }
public abstract class SystemDialog public abstract class SystemDialog

1
src/Avalonia.Controls/TextBox.cs

@ -262,7 +262,6 @@ namespace Avalonia.Controls
protected override void OnTemplateApplied(TemplateAppliedEventArgs e) protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{ {
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter"); _presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
_presenter.Cursor = new Cursor(StandardCursorType.Ibeam);
if (IsFocused) if (IsFocused)
{ {

38
src/Avalonia.Controls/Window.cs

@ -397,11 +397,23 @@ namespace Avalonia.Controls
/// <returns> /// <returns>
/// A task that can be used to track the lifetime of the dialog. /// A task that can be used to track the lifetime of the dialog.
/// </returns> /// </returns>
public Task ShowDialog() public Task ShowDialog(Window parent)
{ {
return ShowDialog<object>(); return ShowDialog<object>(parent);
} }
/// <summary>
/// Shows the window as a dialog.
/// </summary>
/// <typeparam name="TResult">
/// The type of the result produced by the dialog.
/// </typeparam>
/// <returns>.
/// A task that can be used to retrieve the result of the dialog when it closes.
/// </returns>
public Task<TResult> ShowDialog<TResult>(Window parent) => ShowDialog<TResult>(parent.PlatformImpl);
/// <summary> /// <summary>
/// Shows the window as a dialog. /// Shows the window as a dialog.
/// </summary> /// </summary>
@ -411,8 +423,10 @@ namespace Avalonia.Controls
/// <returns>. /// <returns>.
/// A task that can be used to retrieve the result of the dialog when it closes. /// A task that can be used to retrieve the result of the dialog when it closes.
/// </returns> /// </returns>
public Task<TResult> ShowDialog<TResult>() public Task<TResult> ShowDialog<TResult>(IWindowImpl parent)
{ {
if(parent == null)
throw new ArgumentNullException(nameof(parent));
if (IsVisible) if (IsVisible)
{ {
throw new InvalidOperationException("The window is already being shown."); throw new InvalidOperationException("The window is already being shown.");
@ -427,24 +441,18 @@ namespace Avalonia.Controls
using (BeginAutoSizing()) using (BeginAutoSizing())
{ {
var affectedWindows = Application.Current.Windows.Where(w => w.IsEnabled && w != this).ToList();
var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault();
SetIsEnabled(affectedWindows, false);
var modal = PlatformImpl?.ShowDialog(); PlatformImpl?.ShowDialog(parent);
var result = new TaskCompletionSource<TResult>(); var result = new TaskCompletionSource<TResult>();
Renderer?.Start(); Renderer?.Start();
Observable.FromEventPattern<EventHandler, EventArgs>( Observable.FromEventPattern<EventHandler, EventArgs>(
x => this.Closed += x, x => this.Closed += x,
x => this.Closed -= x) x => this.Closed -= x)
.Take(1) .Take(1)
.Subscribe(_ => .Subscribe(_ =>
{ {
modal?.Dispose(); parent.Activate();
SetIsEnabled(affectedWindows, true);
activated?.Activate();
result.SetResult((TResult)(_dialogResult ?? default(TResult))); result.SetResult((TResult)(_dialogResult ?? default(TResult)));
}); });
@ -452,14 +460,6 @@ namespace Avalonia.Controls
} }
} }
void SetIsEnabled(IEnumerable<Window> windows, bool isEnabled)
{
foreach (var window in windows)
{
window.IsEnabled = isEnabled;
}
}
void SetWindowStartupLocation() void SetWindowStartupLocation()
{ {
if (WindowStartupLocation == WindowStartupLocation.CenterScreen) if (WindowStartupLocation == WindowStartupLocation.CenterScreen)

5
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -86,9 +86,8 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public IDisposable ShowDialog() public void ShowDialog(IWindowImpl parent)
{ {
return Disposable.Empty;
} }
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(bool enabled)
@ -111,4 +110,4 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
} }
} }

6
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -87,7 +87,9 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public IDisposable ShowDialog() => Disposable.Empty; public void ShowDialog(IWindowImpl parent)
{
}
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(bool enabled)
{ {
@ -157,4 +159,4 @@ namespace Avalonia.DesignerSupport.Remote
public Screen[] AllScreens { get; } = public Screen[] AllScreens { get; } =
{new Screen(new Rect(0, 0, 4000, 4000), new Rect(0, 0, 4000, 4000), true)}; {new Screen(new Rect(0, 0, 4000, 4000), new Rect(0, 0, 4000, 4000), true)};
} }
} }

6
src/Avalonia.Layout/Properties/AssemblyInfo.cs

@ -0,0 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Layout")]

23
src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs

@ -0,0 +1,23 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Native.Interop;
using Avalonia.Rendering;
namespace Avalonia.Native
{
public class AvaloniaNativeDeferredRendererLock : IDeferredRendererLock
{
private readonly IAvnWindowBase _window;
public AvaloniaNativeDeferredRendererLock(IAvnWindowBase window)
{
_window = window;
}
public IDisposable TryLock()
{
if (_window.TryLock())
return Disposable.Create(() => _window.Unlock());
return null;
}
}
}

108
src/Avalonia.Native/DeferredRendererProxy.cs

@ -1,108 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Native.Interop;
using Avalonia.Rendering;
using Avalonia.VisualTree;
namespace Avalonia.Native
{
public class DeferredRendererProxy : IRenderer, IRenderLoopTask, IRenderLoop
{
public DeferredRendererProxy(IRenderRoot root, IAvnWindowBase window)
{
if (window != null)
{
_useLock = true;
window.AddRef();
_window = new IAvnWindowBase(window.NativePointer);
}
_renderer = new DeferredRenderer(root, this);
_rendererTask = (IRenderLoopTask)_renderer;
}
void IRenderLoop.Add(IRenderLoopTask i)
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Add(this);
}
void IRenderLoop.Remove(IRenderLoopTask i)
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Remove(this);
}
private DeferredRenderer _renderer;
private IRenderLoopTask _rendererTask;
private IAvnWindowBase _window;
private bool _useLock;
public bool DrawFps{
get => _renderer.DrawFps;
set => _renderer.DrawFps = value;
}
public bool DrawDirtyRects
{
get => _renderer.DrawDirtyRects;
set => _renderer.DrawDirtyRects = value;
}
public bool NeedsUpdate => _rendererTask.NeedsUpdate;
public void AddDirty(IVisual visual) => _renderer.AddDirty(visual);
public void Dispose()
{
_renderer.Dispose();
_window?.Dispose();
_window = null;
}
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
{
return _renderer.HitTest(p, root, filter);
}
public void Paint(Rect rect)
{
if (NeedsUpdate)
{
Update(TimeSpan.FromMilliseconds(Environment.TickCount));
}
Render();
}
public void Resized(Size size) => _renderer.Resized(size);
public void Start() => _renderer.Start();
public void Stop() => _renderer.Stop();
public void Update(TimeSpan time)
{
_rendererTask.Update(time);
}
public void Render()
{
if(_useLock)
{
_rendererTask.Render();
return;
}
if (_window == null)
return;
if (!_window.TryLock())
return;
try
{
_rendererTask.Render();
}
finally
{
_window.Unlock();
}
}
}
}

4
src/Avalonia.Native/GlPlatformFeature.cs

@ -58,10 +58,8 @@ namespace Avalonia.Native
public IGlDisplay Display { get; } public IGlDisplay Display { get; }
public void MakeCurrent(IGlSurface surface) public void MakeCurrent()
{ {
if (surface != null)
throw new ArgumentException(nameof(surface));
Context.MakeCurrent(); Context.MakeCurrent();
} }
} }

4
src/Avalonia.Native/WindowImpl.cs

@ -47,9 +47,9 @@ namespace Avalonia.Native
public IAvnWindow Native => _native; public IAvnWindow Native => _native;
public IDisposable ShowDialog() public void ShowDialog(IWindowImpl window)
{ {
return _native.ShowDialog(); _native.ShowDialog(((WindowImpl)window).Native);
} }
public void CanResize(bool value) public void CanResize(bool value)

8
src/Avalonia.Native/WindowImplBase.cs

@ -186,10 +186,6 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.RunRenderPriorityJobs() void IAvnWindowBaseEvents.RunRenderPriorityJobs()
{ {
if (_parent._deferredRendering
&& _parent._lastRenderedLogicalSize != _parent.ClientSize)
// Hack to trigger Paint event on the renderer
_parent.Paint?.Invoke(new Rect());
Dispatcher.UIThread.RunJobs(DispatcherPriority.Render); Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
} }
} }
@ -245,7 +241,9 @@ namespace Avalonia.Native
public IRenderer CreateRenderer(IRenderRoot root) public IRenderer CreateRenderer(IRenderRoot root)
{ {
if (_deferredRendering) if (_deferredRendering)
return new DeferredRendererProxy(root, _gpu ? _native : null); return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>(),
rendererLock:
_gpu ? new AvaloniaNativeDeferredRendererLock(_native) : null);
return new ImmediateRenderer(root); return new ImmediateRenderer(root);
} }

44
src/Avalonia.OpenGL/EglContext.cs

@ -0,0 +1,44 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
namespace Avalonia.OpenGL
{
public class EglContext : IGlContext
{
private readonly EglDisplay _disp;
private readonly EglInterface _egl;
private readonly object _lock = new object();
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, IntPtr offscreenSurface)
{
_disp = display;
_egl = egl;
Context = ctx;
OffscreenSurface = offscreenSurface;
}
public IntPtr Context { get; }
public IntPtr OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
public void MakeCurrent()
{
if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
public void MakeCurrent(EglSurface surface)
{
var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
if (!_egl.MakeCurrent(_disp.Handle, surf, surf, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
}
}

53
src/Avalonia.OpenGL/EglDisplay.cs

@ -12,7 +12,8 @@ namespace Avalonia.OpenGL
private readonly IntPtr _display; private readonly IntPtr _display;
private readonly IntPtr _config; private readonly IntPtr _config;
private readonly int[] _contextAttributes; private readonly int[] _contextAttributes;
public IntPtr Handle => _display;
public EglDisplay(EglInterface egl) public EglDisplay(EglInterface egl)
{ {
_egl = egl; _egl = egl;
@ -121,7 +122,7 @@ namespace Avalonia.OpenGL
}); });
if (surf == IntPtr.Zero) if (surf == IntPtr.Zero)
throw new OpenGlException("eglCreatePbufferSurface failed"); throw new OpenGlException("eglCreatePbufferSurface failed");
var rv = new EglContext(this, ctx, surf); var rv = new EglContext(this, _egl, ctx, surf);
rv.MakeCurrent(null); rv.MakeCurrent(null);
return rv; return rv;
} }
@ -132,12 +133,12 @@ namespace Avalonia.OpenGL
throw new OpenGlException("eglMakeCurrent failed"); throw new OpenGlException("eglMakeCurrent failed");
} }
public IGlSurface CreateWindowSurface(IntPtr window) public EglSurface CreateWindowSurface(IntPtr window)
{ {
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE}); var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero) if (s == IntPtr.Zero)
throw new OpenGlException("eglCreateWindowSurface failed"); throw new OpenGlException("eglCreateWindowSurface failed");
return new EglSurface(this, s); return new EglSurface(this, _egl, s);
} }
public int SampleCount public int SampleCount
@ -157,49 +158,5 @@ namespace Avalonia.OpenGL
return rv; return rv;
} }
} }
class EglSurface : SafeHandle, IGlSurface
{
private readonly EglDisplay _display;
public EglSurface(EglDisplay display, IntPtr surface) : base(surface, true)
{
_display = display;
}
protected override bool ReleaseHandle()
{
_display._egl.DestroySurface(_display._display, handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _display._egl.SwapBuffers(_display._display, handle);
}
class EglContext : IGlContext
{
private readonly EglDisplay _disp;
public EglContext(EglDisplay display, IntPtr ctx, IntPtr offscreenSurface)
{
_disp = display;
Context = ctx;
OffscreenSurface = offscreenSurface;
}
public IntPtr Context { get; }
public IntPtr OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public void MakeCurrent(IGlSurface surface)
{
var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
if (!_disp._egl.MakeCurrent(_disp._display, surf, surf, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
}
} }
} }

4
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -7,7 +7,7 @@ namespace Avalonia.OpenGL
{ {
public IGlDisplay Display { get; set; } public IGlDisplay Display { get; set; }
public IGlContext ImmediateContext { get; set; } public IGlContext ImmediateContext { get; set; }
public IGlContext DeferredContext { get; set; } public EglContext DeferredContext { get; set; }
public static void TryInitialize() public static void TryInitialize()
{ {
@ -26,7 +26,7 @@ namespace Avalonia.OpenGL
{ {
Display = disp, Display = disp,
ImmediateContext = ctx, ImmediateContext = ctx,
DeferredContext = disp.CreateContext(ctx) DeferredContext = (EglContext)disp.CreateContext(ctx)
}; };
} }
catch(Exception e) catch(Exception e)

32
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
namespace Avalonia.OpenGL namespace Avalonia.OpenGL
{ {
@ -12,10 +13,10 @@ namespace Avalonia.OpenGL
} }
private readonly EglDisplay _display; private readonly EglDisplay _display;
private readonly IGlContext _context; private readonly EglContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info; private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglDisplay display, IGlContext context, IEglWindowGlPlatformSurfaceInfo info) public EglGlPlatformSurface(EglDisplay display, EglContext context, IEglWindowGlPlatformSurfaceInfo info)
{ {
_display = display; _display = display;
_context = context; _context = context;
@ -30,11 +31,11 @@ namespace Avalonia.OpenGL
class RenderTarget : IGlPlatformSurfaceRenderTarget class RenderTarget : IGlPlatformSurfaceRenderTarget
{ {
private readonly IGlContext _context; private readonly EglContext _context;
private readonly IGlSurface _glSurface; private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info; private readonly IEglWindowGlPlatformSurfaceInfo _info;
public RenderTarget(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) public RenderTarget(EglContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
{ {
_context = context; _context = context;
_glSurface = glSurface; _glSurface = glSurface;
@ -45,21 +46,33 @@ namespace Avalonia.OpenGL
public IGlPlatformSurfaceRenderingSession BeginDraw() public IGlPlatformSurfaceRenderingSession BeginDraw()
{ {
_context.MakeCurrent(_glSurface); var l = _context.Lock();
return new Session(_context, _glSurface, _info); try
{
_context.MakeCurrent(_glSurface);
return new Session(_context, _glSurface, _info, l);
}
catch
{
l.Dispose();
throw;
}
} }
class Session : IGlPlatformSurfaceRenderingSession class Session : IGlPlatformSurfaceRenderingSession
{ {
private readonly IGlContext _context; private readonly IGlContext _context;
private readonly IGlSurface _glSurface; private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info; private readonly IEglWindowGlPlatformSurfaceInfo _info;
private IDisposable _lock;
public Session(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) public Session(IGlContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock)
{ {
_context = context; _context = context;
_glSurface = glSurface; _glSurface = glSurface;
_info = info; _info = info;
_lock = @lock;
} }
public void Dispose() public void Dispose()
@ -67,6 +80,7 @@ namespace Avalonia.OpenGL
_context.Display.GlInterface.Flush(); _context.Display.GlInterface.Flush();
_glSurface.SwapBuffers(); _glSurface.SwapBuffers();
_context.Display.ClearContext(); _context.Display.ClearContext();
_lock.Dispose();
} }
public IGlDisplay Display => _context.Display; public IGlDisplay Display => _context.Display;

28
src/Avalonia.OpenGL/EglSurface.cs

@ -0,0 +1,28 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
{
public class EglSurface : SafeHandle
{
private readonly EglDisplay _display;
private readonly EglInterface _egl;
public EglSurface(EglDisplay display, EglInterface egl, IntPtr surface) : base(surface, true)
{
_display = display;
_egl = egl;
}
protected override bool ReleaseHandle()
{
_egl.DestroySurface(_display.Handle, handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _egl.SwapBuffers(_display.Handle, handle);
}
}

4
src/Avalonia.OpenGL/IGlContext.cs

@ -3,6 +3,6 @@ namespace Avalonia.OpenGL
public interface IGlContext public interface IGlContext
{ {
IGlDisplay Display { get; } IGlDisplay Display { get; }
void MakeCurrent(IGlSurface surface); void MakeCurrent();
} }
} }

10
src/Avalonia.OpenGL/IGlSurface.cs

@ -1,10 +0,0 @@
using System;
namespace Avalonia.OpenGL
{
public interface IGlSurface : IDisposable
{
IGlDisplay Display { get; }
void SwapBuffers();
}
}

28
src/Avalonia.Themes.Default/ButtonSpinner.xaml

@ -1,17 +1,17 @@
<Styles xmlns="https://github.com/avaloniaui"> <Styles xmlns="https://github.com/avaloniaui">
<Style Selector="ButtonSpinner"> <Style Selector="ButtonSpinner">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> <Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/>
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton"> <Style Selector="ButtonSpinner /template/ RepeatButton">
<Setter Property="RepeatButton.Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Setter Property="RepeatButton.BorderBrush" Value="Transparent"/> <Setter Property="BorderBrush" Value="Transparent"/>
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton:pointerover"> <Style Selector="ButtonSpinner /template/ RepeatButton:pointerover">
<Setter Property="RepeatButton.Background" Value="{DynamicResource ThemeControlMidBrush}"/> <Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="RepeatButton.BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton#PART_IncreaseButton"> <Style Selector="ButtonSpinner /template/ RepeatButton#PART_IncreaseButton">
<Setter Property="Content"> <Setter Property="Content">
@ -42,7 +42,8 @@
<Style Selector="ButtonSpinner:right"> <Style Selector="ButtonSpinner:right">
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Background="{TemplateBinding Background}" <Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}" Margin="{TemplateBinding Padding}"
@ -67,7 +68,8 @@
<Style Selector="ButtonSpinner:left"> <Style Selector="ButtonSpinner:left">
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Background="{TemplateBinding Background}" <Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}" Margin="{TemplateBinding Padding}"
@ -87,9 +89,15 @@
</Grid> </Grid>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="ButtonSpinner:pointerover"> <Style Selector="ButtonSpinner:pointerover /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
</Style>
<Style Selector="ButtonSpinner:focus /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
</Style>
<Style Selector="ButtonSpinner:error /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/>
</Style> </Style>
</Styles> </Styles>

29
src/Avalonia.Themes.Default/NumericUpDown.xaml

@ -1,10 +1,10 @@
<Styles xmlns="https://github.com/avaloniaui"> <Styles xmlns="https://github.com/avaloniaui">
<Style Selector="NumericUpDown"> <Style Selector="NumericUpDown">
<Setter Property="TemplatedControl.BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/> <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
<Setter Property="TemplatedControl.BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="TemplatedControl.Background" Value="{DynamicResource ThemeBackgroundBrush}" /> <Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="TemplatedControl.Foreground" Value="{DynamicResource ThemeForegroundBrush}" /> <Setter Property="Padding" Value="4"/>
<Setter Property="TemplatedControl.Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<ButtonSpinner Name="PART_Spinner" <ButtonSpinner Name="PART_Spinner"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
@ -17,20 +17,13 @@
ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}"> ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}">
<TextBox Name="PART_TextBox" <TextBox Name="PART_TextBox"
BorderThickness="0" BorderThickness="0"
Background="Transparent" Background="{TemplateBinding Background}"
ContextMenu="{TemplateBinding ContextMenu}" BorderBrush="{TemplateBinding BorderBrush}"
FontFamily="{TemplateBinding FontFamily}" Padding="{TemplateBinding Padding}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Watermark="{TemplateBinding Watermark}" Watermark="{TemplateBinding Watermark}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
IsReadOnly="{TemplateBinding IsReadOnly}" IsReadOnly="{TemplateBinding IsReadOnly}"
Text="{TemplateBinding Text}" Text="{TemplateBinding Text}"
Padding="{TemplateBinding Padding}"
TextAlignment="Left"
Margin="1"
MinWidth="20"
AcceptsReturn="False" AcceptsReturn="False"
TextWrapping="NoWrap"> TextWrapping="NoWrap">
</TextBox> </TextBox>
@ -38,4 +31,8 @@
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="NumericUpDown /template/ TextBox#PART_TextBox">
<Setter Property="Margin" Value="4"/>
<Setter Property="MinWidth" Value="20"/>
</Style>
</Styles> </Styles>

5
src/Avalonia.Themes.Default/TextBox.xaml

@ -62,4 +62,7 @@
<Style Selector="TextBox:error /template/ Border#border"> <Style Selector="TextBox:error /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/>
</Style> </Style>
</Styles> <Style Selector="TextBox">
<Setter Property="Cursor" Value="IBeam" />
</Style>
</Styles>

35
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -36,6 +36,7 @@ namespace Avalonia.Rendering
private int _lastSceneId = -1; private int _lastSceneId = -1;
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects(); private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
private IRef<IDrawOperation> _currentDraw; private IRef<IDrawOperation> _currentDraw;
private readonly IDeferredRendererLock _lock;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DeferredRenderer"/> class. /// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
@ -44,11 +45,13 @@ namespace Avalonia.Rendering
/// <param name="renderLoop">The render loop.</param> /// <param name="renderLoop">The render loop.</param>
/// <param name="sceneBuilder">The scene builder to use. Optional.</param> /// <param name="sceneBuilder">The scene builder to use. Optional.</param>
/// <param name="dispatcher">The dispatcher to use. Optional.</param> /// <param name="dispatcher">The dispatcher to use. Optional.</param>
/// <param name="rendererLock">Lock object used before trying to access render target</param>
public DeferredRenderer( public DeferredRenderer(
IRenderRoot root, IRenderRoot root,
IRenderLoop renderLoop, IRenderLoop renderLoop,
ISceneBuilder sceneBuilder = null, ISceneBuilder sceneBuilder = null,
IDispatcher dispatcher = null) IDispatcher dispatcher = null,
IDeferredRendererLock rendererLock = null)
{ {
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -57,6 +60,7 @@ namespace Avalonia.Rendering
_sceneBuilder = sceneBuilder ?? new SceneBuilder(); _sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers(); Layers = new RenderLayers();
_renderLoop = renderLoop; _renderLoop = renderLoop;
_lock = rendererLock ?? new ManagedDeferredRendererLock();
} }
/// <summary> /// <summary>
@ -137,6 +141,10 @@ namespace Avalonia.Rendering
/// <inheritdoc/> /// <inheritdoc/>
public void Paint(Rect rect) public void Paint(Rect rect)
{ {
var t = (IRenderLoopTask)this;
if(t.NeedsUpdate)
UpdateScene();
Render(true);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -168,13 +176,7 @@ namespace Avalonia.Rendering
void IRenderLoopTask.Update(TimeSpan time) => UpdateScene(); void IRenderLoopTask.Update(TimeSpan time) => UpdateScene();
void IRenderLoopTask.Render() void IRenderLoopTask.Render() => Render(false);
{
using (var scene = _scene?.Clone())
{
Render(scene?.Item);
}
}
/// <inheritdoc/> /// <inheritdoc/>
Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
@ -195,9 +197,19 @@ namespace Avalonia.Rendering
internal void UnitTestUpdateScene() => UpdateScene(); internal void UnitTestUpdateScene() => UpdateScene();
internal void UnitTestRender() => Render(_scene.Item); internal void UnitTestRender() => Render(_scene.Item, false);
private void Render(Scene scene) private void Render(bool forceComposite)
{
using (var l = _lock.TryLock())
if (l != null)
using (var scene = _scene?.Clone())
{
Render(scene?.Item, forceComposite);
}
}
private void Render(Scene scene, bool forceComposite)
{ {
bool renderOverlay = DrawDirtyRects || DrawFps; bool renderOverlay = DrawDirtyRects || DrawFps;
bool composite = false; bool composite = false;
@ -241,7 +253,7 @@ namespace Avalonia.Rendering
RenderOverlay(scene, context); RenderOverlay(scene, context);
RenderComposite(scene, context); RenderComposite(scene, context);
} }
else if (composite) else if (composite || forceComposite)
{ {
context = context ?? RenderTarget.CreateDrawingContext(this); context = context ?? RenderTarget.CreateDrawingContext(this);
RenderComposite(scene, context); RenderComposite(scene, context);
@ -415,7 +427,6 @@ namespace Avalonia.Rendering
oldScene?.Dispose(); oldScene?.Dispose();
_dirty.Clear(); _dirty.Clear();
(_root as IRenderRoot)?.Invalidate(new Rect(scene.Size));
} }
else else
{ {

9
src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Rendering
{
public interface IDeferredRendererLock
{
IDisposable TryLock();
}
}

17
src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs

@ -0,0 +1,17 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
namespace Avalonia.Rendering
{
public class ManagedDeferredRendererLock : IDeferredRendererLock
{
private readonly object _lock = new object();
public IDisposable TryLock()
{
if (Monitor.TryEnter(_lock))
return Disposable.Create(() => Monitor.Exit(_lock));
return null;
}
}
}

4
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -67,6 +67,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_modal(GtkWindow window, bool modal); public delegate void gtk_window_set_modal(GtkWindow window, bool modal);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_transient_for(GtkWindow window, IntPtr parent);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] //No manual import [UnmanagedFunctionPointer(CallingConvention.Cdecl)] //No manual import
public delegate IntPtr gdk_get_native_handle(IntPtr gdkWindow); public delegate IntPtr gdk_get_native_handle(IntPtr gdkWindow);
@ -408,6 +411,7 @@ namespace Avalonia.Gtk3.Interop
public static D.gtk_window_new GtkWindowNew; public static D.gtk_window_new GtkWindowNew;
public static D.gtk_window_set_icon GtkWindowSetIcon; public static D.gtk_window_set_icon GtkWindowSetIcon;
public static D.gtk_window_set_modal GtkWindowSetModal; public static D.gtk_window_set_modal GtkWindowSetModal;
public static D.gtk_window_set_transient_for GtkWindowSetTransientFor;
public static D.gdk_set_allowed_backends GdkSetAllowedBackends; public static D.gdk_set_allowed_backends GdkSetAllowedBackends;
public static D.gtk_init GtkInit; public static D.gtk_init GtkInit;
public static D.gtk_window_present GtkWindowPresent; public static D.gtk_window_present GtkWindowPresent;

4
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@ -265,6 +265,8 @@ namespace Avalonia.Gtk3
Paint?.Invoke(new Rect(ClientSize)); Paint?.Invoke(new Rect(ClientSize));
CurrentCairoContext = IntPtr.Zero; CurrentCairoContext = IntPtr.Zero;
} }
else
Paint?.Invoke(new Rect(ClientSize));
return true; return true;
} }
@ -422,7 +424,7 @@ namespace Avalonia.Gtk3
Native.GdkWindowSetCursor(Native.GtkWidgetGetWindow(GtkWidget), cursor?.Handle ?? IntPtr.Zero); Native.GdkWindowSetCursor(Native.GtkWidgetGetWindow(GtkWidget), cursor?.Handle ?? IntPtr.Zero);
} }
public void Show() => Native.GtkWindowPresent(GtkWidget); public virtual void Show() => Native.GtkWindowPresent(GtkWidget);
public void Hide() => Native.GtkWidgetHide(GtkWidget); public void Hide() => Native.GtkWidgetHide(GtkWidget);

13
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@ -63,11 +63,18 @@ namespace Avalonia.Gtk3
public Action<WindowState> WindowStateChanged { get; set; } public Action<WindowState> WindowStateChanged { get; set; }
public IDisposable ShowDialog() public void ShowDialog(IWindowImpl parent)
{ {
Native.GtkWindowSetModal(GtkWidget, true); Native.GtkWindowSetModal(GtkWidget, true);
Show(); Native.GtkWindowSetTransientFor(GtkWidget, ((WindowImpl)parent).GtkWidget.DangerousGetHandle());
return new EmptyDisposable(); Native.GtkWindowPresent(GtkWidget);
}
public override void Show()
{
Native.GtkWindowSetModal(GtkWidget, false);
Native.GtkWindowSetTransientFor(GtkWidget, IntPtr.Zero);
Native.GtkWindowPresent(GtkWidget);
} }
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled); public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled);

2
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -28,7 +28,7 @@ namespace Avalonia.Skia
var iface = display.Type == GlDisplayType.OpenGL2 var iface = display.Type == GlDisplayType.OpenGL2
? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) ? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc))
: GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)); : GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc));
gl.ImmediateContext.MakeCurrent(null); gl.ImmediateContext.MakeCurrent();
GrContext = GRContext.Create(GRBackend.OpenGL, iface); GrContext = GRContext.Create(GRBackend.OpenGL, iface);
} }
} }

18
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -780,8 +780,8 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")] [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
private static extern uint SetWindowLong32b(IntPtr hWnd, int nIndex, uint value); private static extern uint SetWindowLong32b(IntPtr hWnd, int nIndex, uint value);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
private static extern uint SetWindowLongPtr(IntPtr hWnd, int nIndex, uint value); private static extern IntPtr SetWindowLong64b(IntPtr hWnd, int nIndex, IntPtr value);
public static uint SetWindowLong(IntPtr hWnd, int nIndex, uint value) public static uint SetWindowLong(IntPtr hWnd, int nIndex, uint value)
{ {
@ -791,7 +791,19 @@ namespace Avalonia.Win32.Interop
} }
else else
{ {
return SetWindowLongPtr(hWnd, nIndex, value); return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr((uint)value)).ToInt32();
}
}
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr handle)
{
if (IntPtr.Size == 4)
{
return new IntPtr(SetWindowLong32b(hWnd, nIndex, (uint)handle.ToInt32()));
}
else
{
return SetWindowLong64b(hWnd, nIndex, handle);
} }
} }

9
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -27,11 +27,11 @@ namespace Avalonia
{ {
public static T UseWin32<T>( public static T UseWin32<T>(
this T builder, this T builder,
bool deferredRendering = true) bool deferredRendering = true, bool allowEgl = false)
where T : AppBuilderBase<T>, new() where T : AppBuilderBase<T>, new()
{ {
return builder.UseWindowingSubsystem( return builder.UseWindowingSubsystem(
() => Win32.Win32Platform.Initialize(deferredRendering), () => Win32.Win32Platform.Initialize(deferredRendering, allowEgl),
"Win32"); "Win32");
} }
} }
@ -66,7 +66,7 @@ namespace Avalonia.Win32
Initialize(true); Initialize(true);
} }
public static void Initialize(bool deferredRendering = true) public static void Initialize(bool deferredRendering = true, bool allowEgl = false)
{ {
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardImpl>() .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
@ -80,7 +80,8 @@ namespace Avalonia.Win32
.Bind<IWindowingPlatform>().ToConstant(s_instance) .Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>() .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformIconLoader>().ToConstant(s_instance); .Bind<IPlatformIconLoader>().ToConstant(s_instance);
Win32GlManager.Initialize(); if (allowEgl)
Win32GlManager.Initialize();
UseDeferredRendering = deferredRendering; UseDeferredRendering = deferredRendering;
_uiThread = Thread.CurrentThread; _uiThread = Thread.CurrentThread;

31
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -42,6 +42,8 @@ namespace Avalonia.Win32
private OleDropTarget _dropTarget; private OleDropTarget _dropTarget;
private Size _minSize; private Size _minSize;
private Size _maxSize; private Size _maxSize;
private WindowImpl _parent;
private readonly List<WindowImpl> _disabledBy = new List<WindowImpl>();
#if USE_MANAGED_DRAG #if USE_MANAGED_DRAG
private readonly ManagedWindowResizeDragHelper _managedDrag; private readonly ManagedWindowResizeDragHelper _managedDrag;
@ -165,10 +167,10 @@ namespace Avalonia.Win32
private set; private set;
} }
public bool IsEnabled
void UpdateEnabled()
{ {
get { return UnmanagedMethods.IsWindowEnabled(_hwnd); } EnableWindow(_hwnd, _disabledBy.Count == 0);
set { UnmanagedMethods.EnableWindow(_hwnd, value); }
} }
public Size MaxClientSize public Size MaxClientSize
@ -248,6 +250,12 @@ namespace Avalonia.Win32
public void Hide() public void Hide()
{ {
if (_parent != null)
{
_parent._disabledBy.Remove(this);
_parent.UpdateEnabled();
_parent = null;
}
UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide); UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide);
} }
@ -359,6 +367,7 @@ namespace Avalonia.Win32
public virtual void Show() public virtual void Show()
{ {
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, IntPtr.Zero);
ShowWindow(_showWindowState); ShowWindow(_showWindowState);
} }
@ -412,11 +421,13 @@ namespace Avalonia.Win32
} }
} }
public virtual IDisposable ShowDialog() public void ShowDialog(IWindowImpl parent)
{ {
Show(); _parent = (WindowImpl)parent;
_parent._disabledBy.Add(this);
return Disposable.Empty; _parent.UpdateEnabled();
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, ((WindowImpl)parent)._hwnd);
ShowWindow(_showWindowState);
} }
public void SetCursor(IPlatformHandle cursor) public void SetCursor(IPlatformHandle cursor)
@ -490,6 +501,11 @@ namespace Avalonia.Win32
//Remove root reference to this class, so unmanaged delegate can be collected //Remove root reference to this class, so unmanaged delegate can be collected
s_instances.Remove(this); s_instances.Remove(this);
Closed?.Invoke(); Closed?.Invoke();
if (_parent != null)
{
_parent._disabledBy.Remove(this);
_parent.UpdateEnabled();
}
//Free other resources //Free other resources
Dispose(); Dispose();
return IntPtr.Zero; return IntPtr.Zero;
@ -633,7 +649,6 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_PAINT: case UnmanagedMethods.WindowsMessage.WM_PAINT:
UnmanagedMethods.PAINTSTRUCT ps; UnmanagedMethods.PAINTSTRUCT ps;
if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero) if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero)
{ {
var f = Scaling; var f = Scaling;

14
tests/Avalonia.Controls.UnitTests/CursorFactoryMock.cs

@ -0,0 +1,14 @@
using System;
using Avalonia.Input;
using Avalonia.Platform;
namespace Avalonia.Controls.UnitTests
{
public class CursorFactoryMock : IStandardCursorFactory
{
public IPlatformHandle GetCursor(StandardCursorType cursorType)
{
return new PlatformHandle(IntPtr.Zero, cursorType.ToString());
}
}
}

7
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -62,9 +62,11 @@ namespace Avalonia.Controls.UnitTests
{ {
using (UnitTestApplication.Start(TestServices.StyledWindow)) using (UnitTestApplication.Start(TestServices.StyledWindow))
{ {
var parent = new Window();
parent.Show();
var window = new Window(); var window = new Window();
var task = window.ShowDialog(); var task = window.ShowDialog(parent);
Assert.True(window.IsVisible); Assert.True(window.IsVisible);
} }
@ -258,12 +260,13 @@ namespace Avalonia.Controls.UnitTests
{ {
using (UnitTestApplication.Start(TestServices.StyledWindow)) using (UnitTestApplication.Start(TestServices.StyledWindow))
{ {
var parent = new Mock<IWindowImpl>();
var windowImpl = new Mock<IWindowImpl>(); var windowImpl = new Mock<IWindowImpl>();
windowImpl.SetupProperty(x => x.Closed); windowImpl.SetupProperty(x => x.Closed);
windowImpl.Setup(x => x.Scaling).Returns(1); windowImpl.Setup(x => x.Scaling).Returns(1);
var target = new Window(windowImpl.Object); var target = new Window(windowImpl.Object);
var task = target.ShowDialog<bool>(); var task = target.ShowDialog<bool>(parent.Object);
windowImpl.Object.Closed(); windowImpl.Object.Closed();

2
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@ -21,6 +21,7 @@ using Xunit;
using Avalonia.Media; using Avalonia.Media;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Controls.UnitTests;
using Avalonia.UnitTests; using Avalonia.UnitTests;
namespace Avalonia.Layout.UnitTests namespace Avalonia.Layout.UnitTests
@ -197,6 +198,7 @@ namespace Avalonia.Layout.UnitTests
windowImpl.SetupGet(x => x.Scaling).Returns(1); windowImpl.SetupGet(x => x.Scaling).Returns(1);
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactoryMock())
.Bind<IAssetLoader>().ToConstant(new AssetLoader()) .Bind<IAssetLoader>().ToConstant(new AssetLoader())
.Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object) .Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
.Bind<IGlobalStyles>().ToConstant(globalStyles.Object) .Bind<IGlobalStyles>().ToConstant(globalStyles.Object)

Loading…
Cancel
Save