Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 53 additions & 67 deletions FlyleafLib/Controls/WPF/FlyleafHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ IsStandAlone [ReadOnly]

static bool isDesignMode;
static int idGenerator = 1;
static nint NONE_STYLE = (nint) (WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_VISIBLE); // WS_MINIMIZEBOX required for swapchain
static Point zeroPoint;
static POINT zeroPOINT;
static Rect zeroRect;
static CornerRadius zeroCornerRadius;
static WindowStyles NONE_STYLE = WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_VISIBLE; // WS_MINIMIZEBOX required for swapchain
static Point zeroPoint = new();
static POINT zeroPOINT = new();
static Rect zeroRect = new();
static CornerRadius zeroCornerRadius= new();

double curResizeRatio;
bool surfaceClosed, surfaceClosing, overlayClosed;
Expand Down Expand Up @@ -523,6 +523,14 @@ public CornerRadius CornerRadius
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), _flType, new(new CornerRadius(0), new(OnCornerRadiusChanged)));

public Brush VideoBackground
{
get => (Brush)GetValue(VideoBackgroundProperty);
set => SetValue(VideoBackgroundProperty, value);
}
public static readonly DependencyProperty VideoBackgroundProperty =
DependencyProperty.Register(nameof(VideoBackground), typeof(Brush), _flType, new(Brushes.Black, new(OnVideoBackgroundChanged)));
#endregion

#region Events
Expand Down Expand Up @@ -580,9 +588,9 @@ private static void OnShowInTaskBarChanged(DependencyObject d, DependencyPropert
return;

if (host.DetachedShowInTaskbar)
SetWindowLong(host.SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE, GetWindowLong(host.SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE) | (nint)WindowStylesEx.WS_EX_APPWINDOW);
SetWindowLong(host.SurfaceHandle, GetWindowLongEx(host.SurfaceHandle) | WindowStylesEx.WS_EX_APPWINDOW);
else
SetWindowLong(host.SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE, GetWindowLong(host.SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE) & ~(nint)WindowStylesEx.WS_EX_APPWINDOW);
SetWindowLong(host.SurfaceHandle, GetWindowLongEx(host.SurfaceHandle) & ~WindowStylesEx.WS_EX_APPWINDOW);
}
private static void OnNoOwnerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Expand Down Expand Up @@ -725,31 +733,20 @@ private static void OnCornerRadiusChanged(DependencyObject d, DependencyProperty
if (host.Surface == null)
return;

if (host.CornerRadius == zeroCornerRadius)
host.Surface.Background = Brushes.Black;
else
{
host.Surface.Background = Brushes.Transparent;
host.SetCornerRadiusBorder();
}

if (host?.Player == null)
return;

host.Player.renderer.CornerRadius = (CornerRadius)e.NewValue;

}
private void SetCornerRadiusBorder()
private static void OnVideoBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Required to handle mouse events as the window's background will be transparent
// This does not set the background color we do that with the renderer (which causes some issues eg. when returning from fullscreen to normalscreen)
Surface.Content = new Border()
{
Background = Brushes.Black, // TBR: for alpha channel -> Background == Brushes.Transparent || Background ==null ? new SolidColorBrush(Color.FromArgb(1,0,0,0)) : Background
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
CornerRadius = CornerRadius,
};
FlyleafHost host = d as FlyleafHost;
if (host.Disposed)
return;

if (host.Surface != null)
host.Surface.Background = (Brush)e.NewValue;
}
private static object OnContentChanging(DependencyObject d, object baseValue)
{
Expand Down Expand Up @@ -885,14 +882,14 @@ private void Host_IsVisibleChanged(object sender, DependencyPropertyChangedEvent
{
// Detach Overlay
SetParent(OverlayHandle, IntPtr.Zero);
SetWindowLong(OverlayHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE);
SetWindowLong(OverlayHandle, NONE_STYLE);
Overlay.Owner = null;

SetWindowPos(OverlayHandle, IntPtr.Zero, 0, 0, (int)Surface.ActualWidth, (int)Surface.ActualHeight,
(uint)(SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE));

// Attache Overlay
SetWindowLong(OverlayHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE | (nint)(WindowStyles.WS_CHILD | WindowStyles.WS_MAXIMIZE));
SetWindowLong(OverlayHandle, NONE_STYLE | WindowStyles.WS_CHILD | WindowStyles.WS_MAXIMIZE);
Overlay.Owner = Surface;
SetParent(OverlayHandle, SurfaceHandle);

Expand Down Expand Up @@ -1536,59 +1533,54 @@ public virtual void SetPlayer(Player oldPlayer)
}

if (Surface != null)
{
if (CornerRadius == zeroCornerRadius)
Surface.Background = new SolidColorBrush(Player.Config.Video.BackgroundColor);
//else // TBR: this border probably not required? only when we don't have a renderer?
//((Border)Surface.Content).Background = new SolidColorBrush(Player.Config.Video.BackgroundColor);

Player.VideoDecoder.CreateSwapChain(SurfaceHandle);
}
}
public virtual void SetSurface(bool fromSetOverlay = false)
{
if (Surface != null)
return;

// Required for some reason (WindowStyle.None will not be updated with our style)
Surface = new();
Surface.Name = $"Surface_{UniqueId}";
Surface.Width = Surface.Height = 1; // Will be set on loaded
Surface.WindowStyle = WindowStyle.None;
Surface.ResizeMode = ResizeMode.NoResize;
Surface.ShowInTaskbar = false;

// CornerRadius must be set initially to AllowsTransparency!
if (_CornerRadius == zeroCornerRadius)
Surface.Background = Player != null ? new SolidColorBrush(Player.Config.Video.BackgroundColor) : Brushes.Black;
else
{
Surface.AllowsTransparency = true;
Surface.Background = Brushes.Transparent;
SetCornerRadiusBorder();
}
Surface = new()
{
Name = $"Surface_{UniqueId}",
Width = 1,
Height = 1,
WindowStyle = WindowStyle.None,
ResizeMode = ResizeMode.NoResize,
ShowInTaskbar = false,
Background = VideoBackground
};

// NOTE: AllowsTransparency will cause performance issues (enable only if really required)
if (Surface.Background is SolidColorBrush scb)
Surface.AllowsTransparency = scb.Color.A < 255;
else
Surface.AllowsTransparency = true; // Non-solid consider true?

// When using ItemsControl with ObservableCollection<Player> to fill DataTemplates with FlyleafHost EnsureHandle will call Host_loaded
if (_IsAttached) Loaded -= Host_Loaded;
SurfaceHandle = new WindowInteropHelper(Surface).EnsureHandle();
if (_IsAttached) Loaded += Host_Loaded;

if (_IsAttached)
{
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE | (nint)WindowStyles.WS_CHILD);
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE, (nint)WindowStylesEx.WS_EX_LAYERED);
SetWindowLong(SurfaceHandle, NONE_STYLE | WindowStyles.WS_CHILD);
SetWindowLong(SurfaceHandle, WindowStylesEx.WS_EX_LAYERED);
}
else // Detached || StandAlone
{
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE);
SetWindowLong(SurfaceHandle, NONE_STYLE);
if (DetachedShowInTaskbar || IsStandAlone)
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE, (nint)(WindowStylesEx.WS_EX_APPWINDOW | WindowStylesEx.WS_EX_LAYERED));
SetWindowLong(SurfaceHandle, WindowStylesEx.WS_EX_APPWINDOW | WindowStylesEx.WS_EX_LAYERED);
else
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_EXSTYLE, (nint)WindowStylesEx.WS_EX_LAYERED);
SetWindowLong(SurfaceHandle, WindowStylesEx.WS_EX_LAYERED);
}

if (Player != null)
Player.VideoDecoder.CreateSwapChain(SurfaceHandle);
// AllowsTransparency = true will ignore it (if we have it with other flags it might cause issues)
SetWindowLong(SurfaceHandle, GetWindowLongEx(SurfaceHandle) | WindowStylesEx.WS_EX_NOREDIRECTIONBITMAP);

Player?.VideoDecoder.CreateSwapChain(SurfaceHandle);

Surface.IsVisibleChanged
+= Surface_IsVisibleChanged;
Expand Down Expand Up @@ -1667,7 +1659,7 @@ public virtual void SetOverlay()
Overlay.ShowInTaskbar = false;
Overlay.Owner = Surface;
SetParent(OverlayHandle, SurfaceHandle);
SetWindowLong(OverlayHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE | (nint)(WindowStyles.WS_CHILD | WindowStyles.WS_MAXIMIZE)); // TBR: WS_MAXIMIZE required? (possible better for DWM on fullscreen?)
SetWindowLong(OverlayHandle, NONE_STYLE | WindowStyles.WS_CHILD | WindowStyles.WS_MAXIMIZE); // TBR: WS_MAXIMIZE required? (possible better for DWM on fullscreen?)

Overlay.KeyUp += Overlay_KeyUp;
Overlay.KeyDown += Overlay_KeyDown;
Expand Down Expand Up @@ -1836,7 +1828,7 @@ public virtual void Attach(bool ignoreRestoreRect = false)
Surface.MaxWidth = MaxWidth;
Surface.MaxHeight = MaxHeight;

SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE | (nint)WindowStyles.WS_CHILD);
SetWindowLong(SurfaceHandle, NONE_STYLE | WindowStyles.WS_CHILD);
Surface.Owner = Owner;
SetParent(SurfaceHandle, OwnerHandle);

Expand Down Expand Up @@ -1913,7 +1905,7 @@ public virtual void Detach()

// Detach (Parent=Null, Owner=Null ?, ShowInTaskBar?, TopMost?)
SetParent(SurfaceHandle, IntPtr.Zero);
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE); // TBR (also in Attach/FullScren): Needs to be after SetParent. when detached and trying to close the owner will take two clicks (like mouse capture without release) //SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, GetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE) & ~(nint)WindowStyles.WS_CHILD);
SetWindowLong(SurfaceHandle, NONE_STYLE); // TBR (also in Attach/FullScren): Needs to be after SetParent. when detached and trying to close the owner will take two clicks (like mouse capture without release) //SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, GetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE) & ~(nint)WindowStyles.WS_CHILD);
Surface.Owner = DetachedNoOwner ? null : Owner;
Surface.Topmost = DetachedTopMost;

Expand All @@ -1938,7 +1930,7 @@ public void RefreshNormalFullScreen()

ResetVisibleRect();
SetParent(SurfaceHandle, IntPtr.Zero);
SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, NONE_STYLE); // TBR (also in Attach/FullScren): Needs to be after SetParent. when detached and trying to close the owner will take two clicks (like mouse capture without release) //SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, GetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE) & ~(nint)WindowStyles.WS_CHILD);
SetWindowLong(SurfaceHandle, NONE_STYLE); // TBR (also in Attach/FullScren): Needs to be after SetParent. when detached and trying to close the owner will take two clicks (like mouse capture without release) //SetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE, GetWindowLong(SurfaceHandle, (int)WindowLongFlags.GWL_STYLE) & ~(nint)WindowStyles.WS_CHILD);
Surface.Owner = DetachedNoOwner ? null : Owner;
Surface.Topmost = DetachedTopMost;

Expand All @@ -1948,9 +1940,6 @@ public void RefreshNormalFullScreen()
if (Player != null)
Player.renderer.CornerRadius = zeroCornerRadius;

if (CornerRadius != zeroCornerRadius)
((Border)Surface.Content).CornerRadius = zeroCornerRadius;

if (Overlay != null)
{
Overlay.Hide();
Expand Down Expand Up @@ -1987,9 +1976,6 @@ public void RefreshNormalFullScreen()
if (Player != null)
Player.renderer.CornerRadius = CornerRadius;

if (CornerRadius != zeroCornerRadius)
((Border)Surface.Content).CornerRadius = CornerRadius;

if (!IsStandAlone) //when play with alpha video and not standalone, we need to set window state to normal last, otherwise it will be lost the background
Surface.WindowState = WindowState.Normal;

Expand Down
Loading