Skip to content

Commit d086ac9

Browse files
committed
Fix background switch queue race condition
1 parent 595dd65 commit d086ac9

File tree

3 files changed

+40
-91
lines changed

3 files changed

+40
-91
lines changed

CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
using System.Diagnostics.CodeAnalysis;
1313
using System.IO;
1414
using System.Linq;
15+
using System.Threading;
1516
using System.Threading.Tasks;
16-
using System.Threading.Tasks.Dataflow;
1717
using ImageUI = Microsoft.UI.Xaml.Controls.Image;
1818
// ReSharper disable PartialTypeWithSinglePart
1919
// ReSharper disable AsyncVoidMethod
@@ -49,9 +49,9 @@ internal enum MediaType
4949
[".mp4", ".mov", ".mkv", ".webm", ".avi", ".gif"];
5050

5151
private static FrameworkElement? _parentUI;
52-
private ImageUI? _bgImageBackground;
53-
private ImageUI? _bgImageBackgroundLast;
54-
private MediaPlayerElement? _bgMediaPlayerBackground;
52+
private ImageUI? _bgImageBackground;
53+
private ImageUI? _bgImageBackgroundLast;
54+
private MediaPlayerElement? _bgMediaPlayerBackground;
5555

5656
private Grid? _bgAcrylicMask;
5757
private Grid? _bgOverlayTitleBar;
@@ -70,28 +70,23 @@ internal enum MediaType
7070

7171
private static FileStream? _alternativeFileStream;
7272

73-
private delegate ValueTask AssignDefaultAction<in T>(T element) where T : class;
74-
internal delegate void ThrowExceptionAction(Exception element);
75-
internal static ActionBlock<Task>? SharedActionBlockQueue = new(async action =>
76-
{
77-
try
78-
{
79-
await action;
80-
}
81-
catch (Exception ex)
82-
{
83-
_parentUI?.DispatcherQueue.TryEnqueue(() =>
84-
ErrorSender.SendException(ex));
85-
}
86-
},
87-
new ExecutionDataflowBlockOptions
88-
{
89-
EnsureOrdered = true,
90-
MaxMessagesPerTask = 1,
91-
MaxDegreeOfParallelism = 1,
92-
BoundedCapacity = 1,
93-
TaskScheduler = TaskScheduler.Current
94-
});
73+
private delegate ValueTask AssignDefaultAction<in T>(T element) where T : class;
74+
internal delegate void ThrowExceptionAction(Exception element);
75+
76+
private static bool _isOnQueue;
77+
internal static async void RunQueuedTask(Task task)
78+
{
79+
while (_isOnQueue)
80+
{
81+
await Task.Delay(100);
82+
}
83+
84+
Interlocked.Exchange(ref _isOnQueue, true);
85+
await task;
86+
Interlocked.Exchange(ref _isOnQueue, false);
87+
}
88+
89+
internal static void RunQueuedTask(Action action) => RunQueuedTask(Task.Factory.StartNew(action));
9590

9691
/// <summary>
9792
/// Attach and register the <see cref="Grid" /> of the page to be assigned with background utility.
@@ -319,19 +314,12 @@ private void EnsureCurrentMediaPlayerRegistered()
319314
/// <param name="actionAfterLoaded">Action to do after background is loaded</param>
320315
/// <exception cref="FormatException">Throws if the background file is not supported</exception>
321316
/// <exception cref="NullReferenceException">Throws if some instances aren't yet initialized</exception>
322-
internal async void LoadBackground(string mediaPath,
323-
bool isRequestInit = false,
324-
bool isForceRecreateCache = false,
325-
ThrowExceptionAction? throwAction = null,
326-
Action? actionAfterLoaded = null)
327-
{
328-
while (!await SharedActionBlockQueue?.SendAsync(LoadBackgroundInner(mediaPath, isRequestInit, isForceRecreateCache, throwAction, actionAfterLoaded))!)
329-
{
330-
// Delay the invoke 1/4 second and wait until the action can
331-
// be sent again.
332-
await Task.Delay(250);
333-
}
334-
}
317+
internal void LoadBackground(string mediaPath,
318+
bool isRequestInit = false,
319+
bool isForceRecreateCache = false,
320+
ThrowExceptionAction? throwAction = null,
321+
Action? actionAfterLoaded = null)
322+
=> RunQueuedTask(LoadBackgroundInner(mediaPath, isRequestInit, isForceRecreateCache, throwAction, actionAfterLoaded));
335323

336324
private async Task LoadBackgroundInner(string mediaPath, bool isRequestInit = false,
337325
bool isForceRecreateCache = false, ThrowExceptionAction? throwAction = null,
@@ -340,11 +328,13 @@ private async Task LoadBackgroundInner(string mediaPath, bool
340328
if (mediaPath.Equals(CurrentAppliedMediaPath, StringComparison.OrdinalIgnoreCase))
341329
return;
342330

331+
Interlocked.Exchange(ref CurrentAppliedMediaPath, mediaPath);
332+
343333
try
344334
{
345335
while (!_isCurrentRegistered)
346336
{
347-
await Task.Delay(250, _cancellationToken?.Token ?? default);
337+
await Task.Delay(250, _cancellationToken?.Token ?? CancellationToken.None);
348338
}
349339

350340
EnsureCurrentImageRegistered();
@@ -401,8 +391,6 @@ private async Task LoadBackgroundInner(string mediaPath, bool
401391

402392
CurrentAppliedMediaType = mediaType;
403393
actionAfterLoaded?.Invoke();
404-
405-
CurrentAppliedMediaPath = mediaPath;
406394
}
407395
catch (Exception ex)
408396
{

CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System.IO;
2222
using System.Threading;
2323
using System.Threading.Tasks;
24-
using System.Threading.Tasks.Dataflow;
2524
using Windows.Foundation;
2625
using Windows.Media.Playback;
2726
using Windows.Storage;
@@ -424,15 +423,9 @@ private async void FrameGrabberEvent(MediaPlayer mediaPlayer, object args)
424423
}
425424
}
426425

427-
public void Dimm()
428-
{
429-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(true));
430-
}
426+
public void Dimm() => BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(true));
431427

432-
public void Undimm()
433-
{
434-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false));
435-
}
428+
public void Undimm() => BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(false));
436429

437430
private async Task ToggleImageVisibility(bool hideImage)
438431
{
@@ -458,10 +451,7 @@ await Task.WhenAll(
458451
);
459452
}
460453

461-
public void Show(bool isForceShow = false)
462-
{
463-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ShowInner());
464-
}
454+
public void Show(bool isForceShow = false) => BackgroundMediaUtility.RunQueuedTask(ShowInner());
465455

466456
private async Task ShowInner()
467457
{
@@ -480,10 +470,7 @@ await _currentMediaPlayerFrameParentGrid
480470
);
481471
}
482472

483-
public void Hide()
484-
{
485-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(HideInner());
486-
}
473+
public void Hide() => BackgroundMediaUtility.RunQueuedTask(HideInner());
487474

488475
private async Task HideInner()
489476
{
@@ -508,17 +495,7 @@ await _currentMediaPlayerFrameParentGrid
508495
DisposeMediaModules();
509496
}
510497

511-
public async void WindowUnfocused()
512-
{
513-
try
514-
{
515-
await (BackgroundMediaUtility.SharedActionBlockQueue?.SendAsync(WindowUnfocusedInner()) ?? Task.CompletedTask);
516-
}
517-
catch (Exception)
518-
{
519-
// ignored
520-
}
521-
}
498+
public void WindowUnfocused() => BackgroundMediaUtility.RunQueuedTask(WindowUnfocusedInner());
522499

523500
private async Task WindowUnfocusedInner()
524501
{
@@ -527,17 +504,7 @@ private async Task WindowUnfocusedInner()
527504
Pause();
528505
}
529506

530-
public async void WindowFocused()
531-
{
532-
try
533-
{
534-
await (BackgroundMediaUtility.SharedActionBlockQueue?.SendAsync(WindowFocusedInner()) ?? Task.CompletedTask);
535-
}
536-
catch (Exception)
537-
{
538-
// ignored
539-
}
540-
}
507+
public void WindowFocused() => BackgroundMediaUtility.RunQueuedTask(WindowFocusedInner());
541508

542509
private async Task WindowFocusedInner()
543510
{

CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,9 @@ await Task.WhenAll(
121121
);
122122
}
123123

124-
public void Dimm()
125-
{
126-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(true));
127-
}
124+
public void Dimm() => BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(true));
128125

129-
public void Undimm()
130-
{
131-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false));
132-
}
126+
public void Undimm() => BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(false));
133127

134128
private async Task ToggleImageVisibility(bool hideImage, bool completeInvisible = false, bool isForceShow = false)
135129
{
@@ -207,13 +201,13 @@ await Task.WhenAll(
207201
public void Show(bool isForceShow = false)
208202
{
209203
if (ImageBackParentGrid?.Opacity > 0f) return;
210-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(false, true, isForceShow));
204+
BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(false, true, isForceShow));
211205
}
212206

213207
public void Hide()
214208
{
215209
if (ImageBackParentGrid?.Opacity < 1f) return;
216-
BackgroundMediaUtility.SharedActionBlockQueue?.Post(ToggleImageVisibility(true, true));
210+
BackgroundMediaUtility.RunQueuedTask(ToggleImageVisibility(true, true));
217211
}
218212

219213
public void Mute()

0 commit comments

Comments
 (0)