From 7b3a25e45a4c20fe4ffda4a6c340a6e69a63a102 Mon Sep 17 00:00:00 2001 From: Mbucari <37587114+Mbucari@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:42:33 -0600 Subject: [PATCH 1/6] Create bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..6eec1d52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve Libation +title: '' +labels: bug +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Platform** + +[e.g. Windows 10, Windows 11, Mac, Linux (State distribution)] + +**Log Files** +Attach your Libation log file here. From 16b0feeb823b21b174d3d32dbb211fc97f2299dd Mon Sep 17 00:00:00 2001 From: Mbucari <37587114+Mbucari@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:43:11 -0600 Subject: [PATCH 2/6] Create feature request template --- .github/ISSUE_TEMPLATE/feature_request.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..5f0a04ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From a99b644917dc53c58c42e236b196a9f2862eae01 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 28 Jul 2022 10:12:43 -0600 Subject: [PATCH 3/6] Fix thread hang issue#329 --- Source/LibationAvalonia/MessageBox.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index f92eedde..39d4ac66 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using System.Threading; namespace LibationAvalonia { @@ -147,13 +148,18 @@ Libation. DisplayWindow(form, owner); } - private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) - => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => ShowCoreAsync2(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)).GetAwaiter().GetResult(); - - private static DialogResult ShowCoreAsync2(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { + using var source = new CancellationTokenSource(); + var dialogTask = Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); + dialogTask.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + Avalonia.Threading.Dispatcher.UIThread.MainLoop(source.Token); + return DisplayWindow(dialogTask.Result, owner); + } + + private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) + { owner ??= (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow; var dialog = new MessageBoxWindow(saveAndRestorePosition); @@ -186,8 +192,7 @@ Libation. dialog.MaxWidth = dialog.MinWidth; dialog.Height = dialog.MinHeight; dialog.Width = dialog.MinWidth; - - return DisplayWindow(dialog, owner); + return dialog; } private static DialogResult DisplayWindow(Window toDisplay, Window owner) { From 92327dcc0d348c2edee38acfb35143d18153e9e1 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 28 Jul 2022 10:40:39 -0600 Subject: [PATCH 4/6] Add synchronous thread extensions --- .../LibationAvalonia/AvaloniaThreadUtils.cs | 46 +++++++++++++++++++ Source/LibationAvalonia/AvaloniaUtils.cs | 7 +-- Source/LibationAvalonia/MessageBox.cs | 8 ++-- 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 Source/LibationAvalonia/AvaloniaThreadUtils.cs diff --git a/Source/LibationAvalonia/AvaloniaThreadUtils.cs b/Source/LibationAvalonia/AvaloniaThreadUtils.cs new file mode 100644 index 00000000..b14f6ec0 --- /dev/null +++ b/Source/LibationAvalonia/AvaloniaThreadUtils.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Avalonia.Threading +{ + internal static class AvaloniaThreadUtils + { + public static TResult Invoke(this Dispatcher dispatcher, Func function, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal) + { + using var source = new CancellationTokenSource(); + var task = dispatcher.InvokeAsync(function, dispatcherPriority); + task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + dispatcher.MainLoop(source.Token); + return task.Result; + } + + public static void Invoke(this Dispatcher dispatcher, Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal) + { + using var source = new CancellationTokenSource(); + var task = dispatcher.InvokeAsync(action, dispatcherPriority); + task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + Dispatcher.UIThread.MainLoop(source.Token); + } + + public static T WaitOnUIAndGetResult(this Task task) + => WaitOnDispatcherAndGetResult(task, Dispatcher.UIThread); + + public static T WaitOnDispatcherAndGetResult(this Task task, Dispatcher dispatcher) + { + using var source = new CancellationTokenSource(); + task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + dispatcher.MainLoop(source.Token); + return task.Result; + } + + public static void WaitOnUI(this Task task) + => WaitOnDispatcher(task, Dispatcher.UIThread); + public static void WaitOnDispatcher(this Task task, Dispatcher dispatcher) + { + using var source = new CancellationTokenSource(); + task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + dispatcher.MainLoop(source.Token); + } + } +} diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 7ade8b9a..6efc93a5 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using Avalonia.Threading; using System; using System.Threading; using System.Threading.Tasks; @@ -18,11 +19,7 @@ namespace LibationAvalonia public static T ShowDialogSynchronously(this Avalonia.Controls.Window window, Avalonia.Controls.Window owner) { - using var source = new CancellationTokenSource(); - var dialogTask = window.ShowDialog(owner); - dialogTask.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - Avalonia.Threading.Dispatcher.UIThread.MainLoop(source.Token); - return dialogTask.Result; + return window.ShowDialog(owner).WaitOnUIAndGetResult(); } } } diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index 39d4ac66..3ad00a8f 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Threading; +using Avalonia.Threading; namespace LibationAvalonia { @@ -150,12 +151,9 @@ Libation. private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { - using var source = new CancellationTokenSource(); - var dialogTask = Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); - dialogTask.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - Avalonia.Threading.Dispatcher.UIThread.MainLoop(source.Token); + var dialogTask = Dispatcher.UIThread.Invoke(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); - return DisplayWindow(dialogTask.Result, owner); + return DisplayWindow(dialogTask, owner); } private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) From 7525d318c0c38a42c7772e0d9cc6e33488ab5cb1 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 28 Jul 2022 11:03:22 -0600 Subject: [PATCH 5/6] Crean up helper methods --- .../LibationAvalonia/AvaloniaThreadUtils.cs | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/Source/LibationAvalonia/AvaloniaThreadUtils.cs b/Source/LibationAvalonia/AvaloniaThreadUtils.cs index b14f6ec0..93213183 100644 --- a/Source/LibationAvalonia/AvaloniaThreadUtils.cs +++ b/Source/LibationAvalonia/AvaloniaThreadUtils.cs @@ -7,35 +7,25 @@ namespace Avalonia.Threading internal static class AvaloniaThreadUtils { public static TResult Invoke(this Dispatcher dispatcher, Func function, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal) - { - using var source = new CancellationTokenSource(); - var task = dispatcher.InvokeAsync(function, dispatcherPriority); - task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - dispatcher.MainLoop(source.Token); - return task.Result; - } + => WaitOnDispatcherAndGetResult(dispatcher.InvokeAsync(function, dispatcherPriority), dispatcher); public static void Invoke(this Dispatcher dispatcher, Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal) - { - using var source = new CancellationTokenSource(); - var task = dispatcher.InvokeAsync(action, dispatcherPriority); - task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - Dispatcher.UIThread.MainLoop(source.Token); - } + => WaitOnDispatcher(dispatcher.InvokeAsync(action, dispatcherPriority), dispatcher); - public static T WaitOnUIAndGetResult(this Task task) + public static TResult WaitOnUIAndGetResult(this Task task) => WaitOnDispatcherAndGetResult(task, Dispatcher.UIThread); - public static T WaitOnDispatcherAndGetResult(this Task task, Dispatcher dispatcher) - { - using var source = new CancellationTokenSource(); - task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - dispatcher.MainLoop(source.Token); - return task.Result; - } - public static void WaitOnUI(this Task task) => WaitOnDispatcher(task, Dispatcher.UIThread); + + public static TResult WaitOnDispatcherAndGetResult(this Task task, Dispatcher dispatcher) + { + using var source = new CancellationTokenSource(); + task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + dispatcher.MainLoop(source.Token); + return task.Result; + } + public static void WaitOnDispatcher(this Task task, Dispatcher dispatcher) { using var source = new CancellationTokenSource(); From 433974323c92df2dadca0c4a89d0b7d151136cc2 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 28 Jul 2022 11:17:29 -0600 Subject: [PATCH 6/6] Remove unnecessary extensions --- Source/LibationAvalonia/AvaloniaThreadUtils.cs | 6 ------ Source/LibationAvalonia/AvaloniaUtils.cs | 2 +- Source/LibationAvalonia/MessageBox.cs | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Source/LibationAvalonia/AvaloniaThreadUtils.cs b/Source/LibationAvalonia/AvaloniaThreadUtils.cs index 93213183..b5683223 100644 --- a/Source/LibationAvalonia/AvaloniaThreadUtils.cs +++ b/Source/LibationAvalonia/AvaloniaThreadUtils.cs @@ -12,12 +12,6 @@ namespace Avalonia.Threading public static void Invoke(this Dispatcher dispatcher, Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal) => WaitOnDispatcher(dispatcher.InvokeAsync(action, dispatcherPriority), dispatcher); - public static TResult WaitOnUIAndGetResult(this Task task) - => WaitOnDispatcherAndGetResult(task, Dispatcher.UIThread); - - public static void WaitOnUI(this Task task) - => WaitOnDispatcher(task, Dispatcher.UIThread); - public static TResult WaitOnDispatcherAndGetResult(this Task task, Dispatcher dispatcher) { using var source = new CancellationTokenSource(); diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 6efc93a5..906bfe61 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -19,7 +19,7 @@ namespace LibationAvalonia public static T ShowDialogSynchronously(this Avalonia.Controls.Window window, Avalonia.Controls.Window owner) { - return window.ShowDialog(owner).WaitOnUIAndGetResult(); + return window.ShowDialog(owner).WaitOnDispatcherAndGetResult(Dispatcher.UIThread); } } } diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index 3ad00a8f..26de6e0f 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -151,9 +151,9 @@ Libation. private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { - var dialogTask = Dispatcher.UIThread.Invoke(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); + var dialog = Dispatcher.UIThread.Invoke(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); - return DisplayWindow(dialogTask, owner); + return DisplayWindow(dialog, owner); } private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true)