diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs index d065b231ce..eb5218cd6f 100644 --- a/src/Avalonia.Styling/Styling/Setter.cs +++ b/src/Avalonia.Styling/Styling/Setter.cs @@ -141,20 +141,20 @@ namespace Avalonia.Styling { var description = style?.ToString(); - if (sourceInstance.Subject != null) + if (sourceInstance.Mode == BindingMode.TwoWay || sourceInstance.Mode == BindingMode.OneWayToSource) { var activated = new ActivatedSubject(activator, sourceInstance.Subject, description); cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger); } - else if (sourceInstance.Observable != null) + else if (sourceInstance.Mode == BindingMode.OneTime) { - var activated = new ActivatedObservable(activator, sourceInstance.Observable, description); - cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger); + var activated = new ActivatedValue(activator, sourceInstance.Value, description); + cloned = new InstancedBinding(activated, BindingMode.OneWay, BindingPriority.StyleTrigger); } else { - var activated = new ActivatedValue(activator, sourceInstance.Value, description); - cloned = new InstancedBinding(activated, BindingMode.OneWay, BindingPriority.StyleTrigger); + var activated = new ActivatedObservable(activator, sourceInstance.Observable ?? sourceInstance.Subject, description); + cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger); } } else diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 15b3a11fbb..3b9007786d 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -102,6 +102,9 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate void gdk_window_resize(IntPtr gtkWindow, int width, int height); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] + public delegate void gdk_window_set_override_redirect(IntPtr gdkWindow, bool value); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_widget_realize(GtkWidget gtkWidget); @@ -402,6 +405,7 @@ namespace Avalonia.Gtk3.Interop public static D.gtk_window_get_size GtkWindowGetSize; public static D.gtk_window_resize GtkWindowResize; public static D.gdk_window_resize GdkWindowResize; + public static D.gdk_window_set_override_redirect GdkWindowSetOverrideRedirect; public static D.gtk_widget_set_size_request GtkWindowSetSizeRequest; public static D.gtk_window_set_default_size GtkWindowSetDefaultSize; public static D.gtk_window_get_position GtkWindowGetPosition; diff --git a/src/Gtk/Avalonia.Gtk3/PopupImpl.cs b/src/Gtk/Avalonia.Gtk3/PopupImpl.cs index 8fd1c28ea4..13beff580e 100644 --- a/src/Gtk/Avalonia.Gtk3/PopupImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/PopupImpl.cs @@ -19,6 +19,7 @@ namespace Avalonia.Gtk3 public PopupImpl() : base(CreateWindow()) { + OverrideRedirect = true; } } } diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index e14ed77877..136023c31d 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -32,6 +32,7 @@ namespace Avalonia.Gtk3 private IDeferredRenderOperation _nextRenderOperation; private readonly AutoResetEvent _canSetNextOperation = new AutoResetEvent(true); internal IntPtr? GdkWindowHandle; + private bool _overrideRedirect; public WindowBaseImpl(GtkWindow gtkWidget) { @@ -69,12 +70,15 @@ namespace Avalonia.Gtk3 private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata) { int w, h; - Native.GtkWindowGetSize(GtkWidget, out w, out h); - var size = ClientSize = new Size(w, h); - if (_lastSize != size) + if (!OverrideRedirect) { - Resized?.Invoke(size); - _lastSize = size; + Native.GtkWindowGetSize(GtkWidget, out w, out h); + var size = ClientSize = new Size(w, h); + if (_lastSize != size) + { + Resized?.Invoke(size); + _lastSize = size; + } } var pos = Position; if (_lastPosition != pos) @@ -406,6 +410,28 @@ namespace Avalonia.Gtk3 if (GtkWidget.IsClosed) return; Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height); + if (OverrideRedirect) + { + var size = ClientSize = value; + if (_lastSize != size) + { + Resized?.Invoke(size); + _lastSize = size; + } + } + } + + public bool OverrideRedirect + { + get => _overrideRedirect; + set + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Native.GdkWindowSetOverrideRedirect(Native.GtkWidgetGetWindow(GtkWidget), value); + _overrideRedirect = value; + } + } } public IScreenImpl Screen diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs index 71c8902cbd..a38029964f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs @@ -135,6 +135,8 @@ namespace Avalonia.Markup.Xaml.PortableXaml }; } + protected override bool LookupIsUnknown() => false; + protected override XamlType LookupType() { var propType = GetPropertyType(); diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github index eebf9dbb92..f226a516fe 160000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github @@ -1 +1 @@ -Subproject commit eebf9dbb9275ecc48c18ec24f6fbad8cb494857f +Subproject commit f226a516fe2bc191145c1fbf732f5a087f121a33 diff --git a/tests/Avalonia.Styling.UnitTests/SetterTests.cs b/tests/Avalonia.Styling.UnitTests/SetterTests.cs index 84536fa47b..9c43097a21 100644 --- a/tests/Avalonia.Styling.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Styling.UnitTests/SetterTests.cs @@ -8,6 +8,9 @@ using Avalonia.Data; using Xunit; using System; using Avalonia.Controls.Templates; +using Avalonia.Markup.Xaml.Data; +using Avalonia.Markup; +using System.Globalization; namespace Avalonia.Styling.UnitTests { @@ -61,5 +64,39 @@ namespace Avalonia.Styling.UnitTests Assert.NotNull(NameScope.GetNameScope((Control)control.Child)); } + + [Fact] + public void Does_Not_Call_Converter_ConvertBack_On_OneWay_Binding() + { + var control = new Decorator { Name = "foo" }; + var style = Mock.Of(); + var binding = new Binding("Name", BindingMode.OneWay) + { + Converter = new TestConverter(), + RelativeSource = new RelativeSource(RelativeSourceMode.Self), + }; + var setter = new Setter(Decorator.TagProperty, binding); + var activator = new BehaviorSubject(true); + + setter.Apply(style, control, activator); + Assert.Equal("foobar", control.Tag); + + // Issue #1218 caused TestConverter.ConvertBack to throw here. + activator.OnNext(false); + Assert.Null(control.Tag); + } + + private class TestConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value.ToString() + "bar"; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } } }