Skip to content

Commit

Permalink
Merge branch 'AvaloniaUI:stable/0.10.x' into stable/0.10.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Whiletru3 authored Jun 7, 2022
2 parents 55101cd + 4aedf52 commit b446f21
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 46 deletions.
8 changes: 8 additions & 0 deletions native/Avalonia.Native/src/OSX/AvnWindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ -(void)becomeKeyWindow
- (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification
{
_parent->BringToFront();

dispatch_async(dispatch_get_main_queue(), ^{
@try {
[self invalidateShadow];
}
@finally{
}
});
}

- (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification
Expand Down
1 change: 0 additions & 1 deletion native/Avalonia.Native/src/OSX/WindowBaseImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ BEGIN_INTERFACE_MAP()
private:
void CreateNSWindow (bool isDialog);
void CleanNSWindow ();
void InitialiseNSWindow ();

NSCursor *cursor;
ComPtr<IAvnGlContext> _glContext;
Expand Down
43 changes: 15 additions & 28 deletions native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@
lastMenu = nullptr;

CreateNSWindow(usePanel);
InitialiseNSWindow();

[Window setContentView:StandardContainer];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];

[Window setContentMinSize:lastMinSize];
[Window setContentMaxSize:lastMaxSize];

[Window setOpaque:false];
[Window setHasShadow:true];
}

HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) {
Expand Down Expand Up @@ -89,6 +98,8 @@
START_COM_CALL;

@autoreleasepool {
[Window setContentSize:lastSize];

if(hasPosition)
{
SetPosition(lastPositionSet);
Expand All @@ -98,6 +109,8 @@
}

UpdateStyle();

[Window invalidateShadow];

if (ShouldTakeFocusOnShow() && activate) {
[Window orderFront:Window];
Expand Down Expand Up @@ -289,8 +302,7 @@
if (!_shown) {
BaseEvents->Resized(AvnSize{x, y}, reason);
}

if(Window != nullptr) {
else if(Window != nullptr) {
[Window setContentSize:lastSize];
[Window invalidateShadow];
}
Expand Down Expand Up @@ -566,31 +578,6 @@
}
}

void WindowBaseImpl::InitialiseNSWindow() {
if(Window != nullptr) {
[Window setContentView:StandardContainer];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];

[Window setContentSize:lastSize];
[Window setContentMinSize:lastMinSize];
[Window setContentMaxSize:lastMaxSize];

[Window setOpaque:false];

[Window setHasShadow:true];
[Window invalidateShadow];

if (lastMenu != nullptr) {
[GetWindowProtocol() applyMenu:lastMenu];

if ([Window isKeyWindow]) {
[GetWindowProtocol() showWindowMenuWithAppMenu];
}
}
}
}

id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() {
if(Window == nullptr)
{
Expand Down
5 changes: 0 additions & 5 deletions native/Avalonia.Native/src/OSX/WindowImpl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@
[GetWindowProtocol() setIsExtended:true];
SetExtendClientArea(true);
}

if(_parent != nullptr)
{
SetParent(_parent);
}
}

HRESULT WindowImpl::Show(bool activate, bool isDialog) {
Expand Down
11 changes: 11 additions & 0 deletions native/Avalonia.Native/src/OSX/app.mm
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ - (void)sendEvent:(NSEvent *)event
_isHandlingSendEvent = oldHandling;
}
}

// This is needed for certain embedded controls DO NOT REMOVE..
- (BOOL) isHandlingSendEvent
{
return _isHandlingSendEvent;
}

- (void)setHandlingSendEvent:(BOOL)handlingSendEvent
{
_isHandlingSendEvent = handlingSendEvent;
}
@end

extern void InitializeAvnApp(IAvnApplicationEvents* events)
Expand Down
6 changes: 4 additions & 2 deletions src/Avalonia.Base/Reactive/TypedBindingAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public void OnNext(BindingValue<object?> value)
}
catch (InvalidCastException e)
{
var unwrappedValue = value.HasValue ? value.Value : null;

Logger.TryGet(LogEventLevel.Error, LogArea.Binding)?.Log(
_target,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
_property.Name,
_property.PropertyType,
value.Value,
value.Value?.GetType());
unwrappedValue,
unwrappedValue?.GetType());
PublishNext(BindingValue<T>.BindingError(e));
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/Avalonia.Controls/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e
StopListeningForDefault(inputElement);
}
}
if (IsCancel)
{
if (e.Root is IInputElement inputElement)
{
StopListeningForCancel(inputElement);
}
}
}

protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.X11/X11Atoms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ internal class X11Atoms
public readonly IntPtr _NET_FRAME_EXTENTS;
public readonly IntPtr _NET_WM_PING;
public readonly IntPtr _NET_WM_SYNC_REQUEST;
public readonly IntPtr _NET_WM_SYNC_REQUEST_COUNTER;
public readonly IntPtr _NET_SYSTEM_TRAY_S;
public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;
Expand Down
10 changes: 10 additions & 0 deletions src/Avalonia.X11/X11Info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ unsafe class X11Info
public IntPtr LastActivityTimestamp { get; set; }
public XVisualInfo? TransparentVisualInfo { get; set; }
public bool HasXim { get; set; }
public bool HasXSync { get; set; }
public IntPtr DefaultFontSet { get; set; }

public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
Expand Down Expand Up @@ -101,6 +102,15 @@ public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
{
//Ignore, XI is not supported
}

try
{
HasXSync = XSyncInitialize(display, out _, out _) != Status.Success;
}
catch
{
//Ignore, XSync is not supported
}
}
}
}
44 changes: 34 additions & 10 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client,
private IntPtr _handle;
private IntPtr _xic;
private IntPtr _renderHandle;
private IntPtr _xSyncCounter;
private XSyncValue _xSyncValue;
private bool _mapped;
private bool _wasMappedAtLeastOnce = false;
private double? _scalingOverride;
Expand Down Expand Up @@ -188,6 +190,16 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent)
NativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
NativeControlHost = new X11NativeControlHost(_platform, this);
InitializeIme();

XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32,
PropertyMode.Replace, new[] { _x11.Atoms.WM_DELETE_WINDOW, _x11.Atoms._NET_WM_SYNC_REQUEST }, 2);

if (_x11.HasXSync)
{
_xSyncCounter = XSyncCreateCounter(_x11.Display, _xSyncValue);
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_SYNC_REQUEST_COUNTER,
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
}
}

class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
Expand Down Expand Up @@ -381,15 +393,7 @@ void OnEvent(ref XEvent ev)
(ev.type == XEventName.VisibilityNotify &&
ev.VisibilityEvent.state < 2))
{
if (!_triggeredExpose)
{
_triggeredExpose = true;
Dispatcher.UIThread.Post(() =>
{
_triggeredExpose = false;
DoPaint();
}, DispatcherPriority.Render);
}
EnqueuePaint();
}
else if (ev.type == XEventName.FocusIn)
{
Expand Down Expand Up @@ -501,6 +505,7 @@ void OnEvent(ref XEvent ev)
if (_useRenderWindow)
XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
ev.ConfigureEvent.height);
EnqueuePaint();
}
else if (ev.type == XEventName.DestroyNotify
&& ev.DestroyWindowEvent.window == _handle)
Expand All @@ -516,7 +521,11 @@ void OnEvent(ref XEvent ev)
if (Closing?.Invoke() != true)
Dispose();
}

else if (ev.ClientMessageEvent.ptr1 == _x11.Atoms._NET_WM_SYNC_REQUEST)
{
_xSyncValue.Lo = new UIntPtr(ev.ClientMessageEvent.ptr3.ToPointer()).ToUInt32();
_xSyncValue.Hi = ev.ClientMessageEvent.ptr4.ToInt32();
}
}
}
else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease)
Expand Down Expand Up @@ -728,9 +737,24 @@ void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
ScheduleInput(mev, ref ev);
}

void EnqueuePaint()
{
if (!_triggeredExpose)
{
_triggeredExpose = true;
Dispatcher.UIThread.Post(() =>
{
_triggeredExpose = false;
DoPaint();
}, DispatcherPriority.Render);
}
}

void DoPaint()
{
Paint?.Invoke(new Rect());
if (_xSyncCounter != IntPtr.Zero)
XSyncSetCounter(_x11.Display, _xSyncCounter, _xSyncValue);
}

public void Invalidate(Rect rect)
Expand Down
17 changes: 17 additions & 0 deletions src/Avalonia.X11/XLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,18 @@ public static extern bool XQueryExtension(IntPtr display, [MarshalAs(UnmanagedTy
public static extern int XRRQueryExtension (IntPtr dpy,
out int event_base_return,
out int error_base_return);

[DllImport(libX11Ext)]
public static extern Status XSyncInitialize(IntPtr dpy, out int event_base_return, out int error_base_return);

[DllImport(libX11Ext)]
public static extern IntPtr XSyncCreateCounter(IntPtr dpy, XSyncValue initialValue);

[DllImport(libX11Ext)]
public static extern int XSyncDestroyCounter(IntPtr dpy, IntPtr counter);

[DllImport(libX11Ext)]
public static extern int XSyncSetCounter(IntPtr dpy, IntPtr counter, XSyncValue value);

[DllImport(libX11Randr)]
public static extern int XRRQueryVersion(IntPtr dpy,
Expand Down Expand Up @@ -627,6 +639,11 @@ public struct XGeometry
public int bw;
public int d;
}

public struct XSyncValue {
public int Hi;
public uint Lo;
}

public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo)
{
Expand Down
74 changes: 74 additions & 0 deletions tests/Avalonia.Controls.UnitTests/ButtonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,80 @@ public void Button_Invokes_Doesnt_Execute_When_Button_Disabled()

Assert.Equal(0, raised);
}

[Fact]
public void Button_IsDefault_Works()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var raised = 0;
var target = new Button();
var window = new Window { Content = target };
window.Show();

target.Click += (s, e) => ++raised;

target.IsDefault = false;
window.RaiseEvent(CreateKeyDownEvent(Key.Enter));
Assert.Equal(0, raised);

target.IsDefault = true;
window.RaiseEvent(CreateKeyDownEvent(Key.Enter));
Assert.Equal(1, raised);

target.IsDefault = false;
window.RaiseEvent(CreateKeyDownEvent(Key.Enter));
Assert.Equal(1, raised);

target.IsDefault = true;
window.RaiseEvent(CreateKeyDownEvent(Key.Enter));
Assert.Equal(2, raised);

window.Content = null;
// To check if handler was raised on the button, when it's detached, we need to pass it as a source manually.
window.RaiseEvent(CreateKeyDownEvent(Key.Enter, target));
Assert.Equal(2, raised);
}
}

[Fact]
public void Button_IsCancel_Works()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var raised = 0;
var target = new Button();
var window = new Window { Content = target };
window.Show();

target.Click += (s, e) => ++raised;

target.IsCancel = false;
window.RaiseEvent(CreateKeyDownEvent(Key.Escape));
Assert.Equal(0, raised);

target.IsCancel = true;
window.RaiseEvent(CreateKeyDownEvent(Key.Escape));
Assert.Equal(1, raised);

target.IsCancel = false;
window.RaiseEvent(CreateKeyDownEvent(Key.Escape));
Assert.Equal(1, raised);

target.IsCancel = true;
window.RaiseEvent(CreateKeyDownEvent(Key.Escape));
Assert.Equal(2, raised);

window.Content = null;
window.RaiseEvent(CreateKeyDownEvent(Key.Escape, target));
Assert.Equal(2, raised);
}
}

private KeyEventArgs CreateKeyDownEvent(Key key, IInteractive source = null)
{
return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source };
}

private class TestButton : Button, IRenderRoot
{
Expand Down

0 comments on commit b446f21

Please sign in to comment.