Skip to content

Commit 2aee531

Browse files
AlexTyrerekcoh
andauthored
Fix resource leaks in Input Actions Editor window. (#1909)
FIX: Fixed Input Actions Editor window resource leak that could result in unexpected exceptions ISXB-865 --------- Co-authored-by: Håkan Sidenvall <[email protected]>
1 parent 1a756df commit 2aee531

File tree

4 files changed

+35
-29
lines changed

4 files changed

+35
-29
lines changed

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ however, it has to be formatted properly to pass verification tests.
1818
- Fixed DualSense Edge's vibration and light bar not working on Windows
1919
- Fixed Project-wide Actions asset failing to reload properly after deleting project's Library folder.
2020
- Fixed an issue where `System.InvalidOperationException` is thrown when entering PlayMode after deleting an ActionMap from Project-wide actions and later resetting it.
21+
- Fixed Input Actions Editor window resource leak that could result in unexpected exceptions [ISXB-865](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-865).
2122

2223
### Changed
2324
- For Unity 6.0 and above, when an `EventSystem` GameObject is created in the Editor it will have the

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorSettingsProvider.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace UnityEngine.InputSystem.Editor
1010
{
1111
internal class InputActionsEditorSettingsProvider : SettingsProvider
1212
{
13+
private static InputActionsEditorSettingsProvider s_Provider;
14+
1315
public static string SettingsPath => InputSettingsPath.kSettingsRootPath;
1416

1517
[SerializeField] InputActionsEditorState m_State;
@@ -106,11 +108,11 @@ private void OnEditFocus(FocusInEvent @event)
106108

107109
void SaveAssetOnFocusLost()
108110
{
109-
#if UNITY_INPUT_SYSTEM_INPUT_ACTIONS_EDITOR_AUTO_SAVE_ON_FOCUS_LOST
111+
#if UNITY_INPUT_SYSTEM_INPUT_ACTIONS_EDITOR_AUTO_SAVE_ON_FOCUS_LOST
110112
var asset = GetAsset();
111113
if (asset != null)
112114
ValidateAndSaveAsset(asset);
113-
#endif
115+
#endif
114116
}
115117

116118
public static void SetIMGUIDropdownVisible(bool visible, bool optionWasSelected)
@@ -162,14 +164,14 @@ private void OnEditFocusLost(FocusOutEvent @event)
162164

163165
private void OnStateChanged(InputActionsEditorState newState)
164166
{
165-
#if UNITY_INPUT_SYSTEM_INPUT_ACTIONS_EDITOR_AUTO_SAVE_ON_FOCUS_LOST
167+
#if UNITY_INPUT_SYSTEM_INPUT_ACTIONS_EDITOR_AUTO_SAVE_ON_FOCUS_LOST
166168
// No action, auto-saved on edit-focus lost
167-
#else
169+
#else
168170
// Project wide input actions always auto save - don't check the asset auto save status
169171
var asset = GetAsset();
170172
if (asset != null)
171173
ValidateAndSaveAsset(asset);
172-
#endif
174+
#endif
173175
}
174176

175177
private void ValidateAndSaveAsset(InputActionAsset asset)
@@ -235,23 +237,18 @@ private void BuildUI()
235237

236238
// Remove input action editor if already present
237239
{
238-
VisualElement element;
239-
do
240-
{
241-
element = m_RootVisualElement.Q("action-editor");
242-
if (element != null)
243-
m_RootVisualElement.Remove(element);
244-
}
245-
while (element != null);
240+
VisualElement element = m_RootVisualElement.Q("action-editor");
241+
if (element != null)
242+
m_RootVisualElement.Remove(element);
246243
}
247244

248245
// If the editor is associated with an asset we show input action editor
249246
if (hasAsset)
250247
{
251-
m_StateContainer = new StateContainer(m_RootVisualElement, m_State);
248+
m_StateContainer = new StateContainer(m_State);
252249
m_StateContainer.StateChanged += OnStateChanged;
253250
m_View = new InputActionsEditorView(m_RootVisualElement, m_StateContainer, true, null);
254-
m_StateContainer.Initialize();
251+
m_StateContainer.Initialize(m_RootVisualElement.Q("action-editor"));
255252
}
256253
}
257254

@@ -289,7 +286,10 @@ private void ModeChanged(PlayModeStateChange change)
289286
[SettingsProvider]
290287
public static SettingsProvider CreateGlobalInputActionsEditorProvider()
291288
{
292-
return new InputActionsEditorSettingsProvider(SettingsPath, SettingsScope.Project);
289+
if (s_Provider == null)
290+
s_Provider = new InputActionsEditorSettingsProvider(SettingsPath, SettingsScope.Project);
291+
292+
return s_Provider;
293293
}
294294

295295
#region Shortcuts

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorWindow.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using UnityEditor.Callbacks;
88
using UnityEditor.PackageManager.UI;
99
using UnityEditor.ShortcutManagement;
10+
using UnityEngine.UIElements;
11+
using UnityEditor.UIElements;
1012

1113
namespace UnityEngine.InputSystem.Editor
1214
{
@@ -212,15 +214,15 @@ private void BuildUI()
212214
{
213215
CleanupStateContainer();
214216

215-
m_StateContainer = new StateContainer(rootVisualElement, m_State);
217+
m_StateContainer = new StateContainer(m_State);
216218
m_StateContainer.StateChanged += OnStateChanged;
217219

218220
rootVisualElement.Clear();
219221
if (!rootVisualElement.styleSheets.Contains(InputActionsEditorWindowUtils.theme))
220222
rootVisualElement.styleSheets.Add(InputActionsEditorWindowUtils.theme);
221223
m_View = new InputActionsEditorView(rootVisualElement, m_StateContainer, false, Save);
222224

223-
m_StateContainer.Initialize();
225+
m_StateContainer.Initialize(rootVisualElement.Q("action-editor"));
224226
}
225227

226228
private void OnStateChanged(InputActionsEditorState newState)

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/StateContainer.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,12 @@ internal class StateContainer
1111
{
1212
public event Action<InputActionsEditorState> StateChanged;
1313

14-
private readonly VisualElement m_RootVisualElement;
14+
private VisualElement m_RootVisualElement;
1515
private InputActionsEditorState m_State;
1616

17-
public StateContainer(VisualElement rootVisualElement, InputActionsEditorState initialState)
17+
public StateContainer(InputActionsEditorState initialState)
1818
{
19-
m_RootVisualElement = rootVisualElement;
2019
m_State = initialState;
21-
22-
rootVisualElement.Unbind();
23-
m_RootVisualElement.TrackSerializedObjectValue(initialState.serializedObject, so =>
24-
{
25-
StateChanged?.Invoke(m_State);
26-
});
27-
rootVisualElement.Bind(initialState.serializedObject);
2820
}
2921

3022
public void Dispatch(Command command)
@@ -51,9 +43,20 @@ public void Dispatch(Command command)
5143
});
5244
}
5345

54-
public void Initialize()
46+
public void Initialize(VisualElement rootVisualElement)
5547
{
48+
// We need to use a root element for the TrackSerializedObjectValue that is destroyed with the view.
49+
// Using a root element from the settings window would not enable the tracking callback to be destroyed or garbage collected.
50+
51+
m_RootVisualElement = rootVisualElement;
52+
53+
m_RootVisualElement.Unbind();
54+
m_RootVisualElement.TrackSerializedObjectValue(m_State.serializedObject, so =>
55+
{
56+
StateChanged?.Invoke(m_State);
57+
});
5658
StateChanged?.Invoke(m_State);
59+
rootVisualElement.Bind(m_State.serializedObject);
5760
}
5861

5962
/// <summary>

0 commit comments

Comments
 (0)