Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test to check GUI thread safety #3914

Merged
merged 1 commit into from
Sep 28, 2023
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
6 changes: 3 additions & 3 deletions Cmdline/Action/GameInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ internal class CloneOptions : CommonOptions

internal class RenameOptions : CommonOptions
{
[GameInstancesAttribute]
[GameInstances]
[ValueOption(0)] public string old_name { get; set; }
[ValueOption(1)] public string new_name { get; set; }
}

internal class ForgetOptions : CommonOptions
{
[GameInstancesAttribute]
[GameInstances]
[ValueOption(0)] public string name { get; set; }
}

internal class DefaultOptions : CommonOptions
{
[GameInstancesAttribute]
[GameInstances]
[ValueOption(0)] public string name { get; set; }
}

Expand Down
5 changes: 5 additions & 0 deletions Core/Extensions/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ public static ICollection<T> AsCollection<T>(this IEnumerable<T> source)
}

#if NET45

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));

return new HashSet<T>(source);
}

public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T next)
=> source.Concat(Enumerable.Repeat<T>(next, 1));

#endif

public static Dictionary<K, V> ToDictionary<K, V>(this IEnumerable<KeyValuePair<K, V>> pairs)
Expand Down
13 changes: 13 additions & 0 deletions GUI/Attributes/ForbidGUICallsAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace CKAN.GUI.Attributes
{
/// <summary>
/// Tag background functions with this, and a test will check
/// that they're not calling GUI code without Util.Invoke.
/// </summary>
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Property
| AttributeTargets.Method | AttributeTargets.Delegate,
Inherited = true, AllowMultiple = false)]
public class ForbidGUICallsAttribute : Attribute { }
}
1 change: 1 addition & 0 deletions GUI/CKAN-GUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\ForbidGUICallsAttribute.cs" />
<Compile Include="Dialogs\AboutDialog.cs">
<SubType>Form</SubType>
</Compile>
Expand Down
4 changes: 4 additions & 0 deletions GUI/Controls/ChooseProvidedMods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Collections.Generic;
using System.Windows.Forms;

using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
public partial class ChooseProvidedMods : UserControl
Expand All @@ -13,6 +15,7 @@ public ChooseProvidedMods()
InitializeComponent();
}

[ForbidGUICalls]
public void LoadProviders(string message, List<CkanModule> modules, NetModuleCache cache)
{
Util.Invoke(this, () =>
Expand All @@ -36,6 +39,7 @@ public void LoadProviders(string message, List<CkanModule> modules, NetModuleCac
});
}

[ForbidGUICalls]
public CkanModule Wait()
{
task = new TaskCompletionSource<CkanModule>();
Expand Down
4 changes: 4 additions & 0 deletions GUI/Controls/ChooseRecommendedMods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

using CKAN.Extensions;
using CKAN.Versioning;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand All @@ -16,6 +18,7 @@ public ChooseRecommendedMods()
InitializeComponent();
}

[ForbidGUICalls]
public void LoadRecommendations(
IRegistryQuerier registry,
List<CkanModule> toInstall, HashSet<CkanModule> toUninstall,
Expand All @@ -38,6 +41,7 @@ Dictionary<CkanModule, HashSet<string>> supporters
});
}

[ForbidGUICalls]
public HashSet<CkanModule> Wait()
{
if (Platform.IsMono)
Expand Down
4 changes: 4 additions & 0 deletions GUI/Controls/DeleteDirectories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Windows.Forms;

using CKAN.Extensions;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand All @@ -21,6 +23,7 @@ public DeleteDirectories()
/// before the calling code switches to the tab.
/// </summary>
/// <param name="possibleConfigOnlyDirs">Directories that the user may want to delete</param>
[ForbidGUICalls]
public void LoadDirs(GameInstance ksp, HashSet<string> possibleConfigOnlyDirs)
{
instance = ksp;
Expand Down Expand Up @@ -50,6 +53,7 @@ public void LoadDirs(GameInstance ksp, HashSet<string> possibleConfigOnlyDirs)
/// <returns>
/// true if user chose to delete, false otherwise
/// </returns>
[ForbidGUICalls]
public bool Wait(out HashSet<string> toDelete)
{
if (Platform.IsMono)
Expand Down
3 changes: 3 additions & 0 deletions GUI/Controls/EditModpack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using CKAN.Versioning;
using CKAN.Types;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand All @@ -33,6 +34,7 @@ public EditModpack()
this.ToolTip.SetToolTip(ExportModpackButton, Properties.Resources.EditModpackTooltipExport);
}

[ForbidGUICalls]
public void LoadModule(CkanModule module, IRegistryQuerier registry)
{
this.module = module;
Expand Down Expand Up @@ -64,6 +66,7 @@ public void LoadModule(CkanModule module, IRegistryQuerier registry)

public event Action<ListView.SelectedListViewItemCollection> OnSelectedItemsChanged;

[ForbidGUICalls]
public bool Wait(IUser user)
{
if (Platform.IsMono)
Expand Down
14 changes: 13 additions & 1 deletion GUI/Controls/ManageMods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

using CKAN.Extensions;
using CKAN.Versioning;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand Down Expand Up @@ -102,6 +103,7 @@ private List<string> sortColumns
private List<ModChange> ChangeSet
{
get => currentChangeSet;
[ForbidGUICalls]
set
{
var orig = currentChangeSet;
Expand All @@ -111,6 +113,7 @@ private List<ModChange> ChangeSet
}
}

[ForbidGUICalls]
private void ChangeSetUpdated()
{
Util.Invoke(this, () =>
Expand Down Expand Up @@ -149,12 +152,15 @@ private void ChangeSetUpdated()
private Dictionary<GUIMod, string> Conflicts
{
get => conflicts;
[ForbidGUICalls]
set
{
var orig = conflicts;
conflicts = value;
if (orig != value)
ConflictsUpdated(orig);
{
Util.Invoke(this, () => ConflictsUpdated(orig));
}
}
}

Expand Down Expand Up @@ -1033,6 +1039,7 @@ private void reinstallToolStripMenuItem_Click(object sender, EventArgs e)
}
}

[ForbidGUICalls]
public Dictionary<string, GUIMod> AllGUIMods()
=> mainModList.Modules.ToDictionary(guiMod => guiMod.Identifier,
guiMod => guiMod);
Expand Down Expand Up @@ -1087,6 +1094,7 @@ private void EditModSearches_SurrenderFocus()
Util.Invoke(this, () => ModGrid.Focus());
}

[ForbidGUICalls]
public void UpdateFilters()
{
Util.Invoke(this, _UpdateFilters);
Expand Down Expand Up @@ -1135,11 +1143,13 @@ private void _UpdateFilters()
}
}

[ForbidGUICalls]
public void Update(object sender, DoWorkEventArgs e)
{
e.Result = _UpdateModsList(e.Argument as Dictionary<string, bool>);
}

[ForbidGUICalls]
private bool _UpdateModsList(Dictionary<string, bool> old_modules = null)
{
log.Info("Updating the mod list");
Expand Down Expand Up @@ -1275,6 +1285,7 @@ private bool _UpdateModsList(Dictionary<string, bool> old_modules = null)
return true;
}

[ForbidGUICalls]
public void MarkModForInstall(string identifier, bool uncheck = false)
{
Util.Invoke(this, () => _MarkModForInstall(identifier, uncheck));
Expand Down Expand Up @@ -1649,6 +1660,7 @@ public void InstanceUpdated(GameInstance inst)
Conflicts = null;
}

[ForbidGUICalls]
public void UpdateChangeSetAndConflicts(GameInstance inst, IRegistryQuerier registry)
{
if (freezeChangeSet)
Expand Down
2 changes: 2 additions & 0 deletions GUI/Controls/ModInfoTabs/Relationships.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

using CKAN.Versioning;
using CKAN.Extensions;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand Down Expand Up @@ -158,6 +159,7 @@ private void BeforeExpand(object sender, TreeViewCancelEventArgs args)
}
}

[ForbidGUICalls]
private void ExpandOnePage(IRegistryQuerier registry, TreeNode parent, int start, int length)
{
// Should already have children, since the user is expanding it
Expand Down
3 changes: 3 additions & 0 deletions GUI/Controls/ModInfoTabs/Versions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Autofac;

using CKAN.Versioning;
using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
Expand Down Expand Up @@ -88,6 +89,7 @@ private void VersionsListView_ItemCheck(object sender, ItemCheckEventArgs e)
}
}

[ForbidGUICalls]
private bool installable(ModuleInstaller installer, CkanModule module, IRegistryQuerier registry)
{
return module.IsCompatible(Main.Instance.CurrentInstance.VersionCriteria())
Expand Down Expand Up @@ -199,6 +201,7 @@ private ListViewItem[] getItems(GUIMod gmod, List<CkanModule> versions)
return items;
}

[ForbidGUICalls]
private void checkInstallable(ListViewItem[] items)
{
GameInstance currentInstance = Main.Instance.Manager.CurrentInstance;
Expand Down
9 changes: 9 additions & 0 deletions GUI/Controls/Wait.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;

using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
public partial class Wait : UserControl
Expand All @@ -19,6 +21,8 @@ public Wait()
bgWorker.RunWorkerCompleted += RunWorkerCompleted;
}


[ForbidGUICalls]
public void StartWaiting(Action<object, DoWorkEventArgs> mainWork,
Action<object, RunWorkerCompletedEventArgs> postWork,
bool cancelable,
Expand All @@ -38,6 +42,7 @@ public void StartWaiting(Action<object, DoWorkEventArgs> mainWork,

public bool RetryEnabled
{
[ForbidGUICalls]
set
{
Util.Invoke(this, () =>
Expand All @@ -58,6 +63,7 @@ public int ProgressValue

public bool ProgressIndeterminate
{
[ForbidGUICalls]
set
{
Util.Invoke(this, () =>
Expand Down Expand Up @@ -217,6 +223,7 @@ private void ClearProgressBars()
});
}

[ForbidGUICalls]
public void Reset(bool cancelable)
{
Util.Invoke(this, () =>
Expand Down Expand Up @@ -250,12 +257,14 @@ public void SetDescription(string message)
MessageTextBox.Text = "(" + message + ")");
}

[ForbidGUICalls]
private void ClearLog()
{
Util.Invoke(this, () =>
LogTextBox.Text = "");
}

[ForbidGUICalls]
public void AddLogMessage(string message)
{
Util.Invoke(this, () =>
Expand Down
3 changes: 3 additions & 0 deletions GUI/Dialogs/DownloadsFailedDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

using log4net;

using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
/// <summary>
Expand Down Expand Up @@ -66,6 +68,7 @@ public DownloadsFailedDialog(
+ BottomButtonPanel.Height);
}

[ForbidGUICalls]
public object[] Wait() => task.Task.Result;

/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions GUI/Dialogs/ErrorDialog.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Drawing;
using System.Windows.Forms;

using log4net;

using CKAN.GUI.Attributes;

namespace CKAN.GUI
{
public partial class ErrorDialog : Form
Expand All @@ -12,6 +15,7 @@ public ErrorDialog()
InitializeComponent();
}

[ForbidGUICalls]
public void ShowErrorDialog(string text, params object[] args)
{
Util.Invoke(Main.Instance, () =>
Expand Down
Loading
Loading