diff --git a/CHANGELOG.md b/CHANGELOG.md
index d753d206e5..7f2d45df58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,8 @@ This plugin has functionality that is common to both ReSharper and Rider. It als
* Fix issues with completion of Unity event functions ([RIDER-33167](https://youtrack.jetbrains.com/issue/RIDER-33167), [#1326](https://github.com/JetBrains/resharper-unity/pull/1326))
* Rider: Fix missing "Install Mono" notification ([#1329](https://github.com/JetBrains/resharper-unity/pull/1329))
+- Rider: Fix Clear on Play in Rider's Unity log viewer ([#1281](https://github.com/JetBrains/resharper-unity/issues/1281), [#1294](https://github.com/JetBrains/resharper-unity/pull/1294))
+- Unity window should get focus, when Rider is showing usages in it ([#1344](https://github.com/JetBrains/resharper-unity/pull/1344)
## 2019.2.2
diff --git a/resharper/.idea/.idea.resharper-unity/.idea/markdown-navigator/profiles_settings.xml b/resharper/.idea/.idea.resharper-unity/.idea/markdown-navigator/profiles_settings.xml
deleted file mode 100644
index db06266325..0000000000
--- a/resharper/.idea/.idea.resharper-unity/.idea/markdown-navigator/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/resharper/resharper-unity.sln.DotSettings b/resharper/resharper-unity.sln.DotSettings
index 41a21102f5..e017825e2d 100644
--- a/resharper/resharper-unity.sln.DotSettings
+++ b/resharper/resharper-unity.sln.DotSettings
@@ -38,6 +38,7 @@
True
True
True
+ True
True
True
True
diff --git a/resharper/resharper-unity/src/Rider/CodeInsights/UnityCodeInsightFieldUsageProvider.cs b/resharper/resharper-unity/src/Rider/CodeInsights/UnityCodeInsightFieldUsageProvider.cs
index 3037ede4a9..8cc75f97b2 100644
--- a/resharper/resharper-unity/src/Rider/CodeInsights/UnityCodeInsightFieldUsageProvider.cs
+++ b/resharper/resharper-unity/src/Rider/CodeInsights/UnityCodeInsightFieldUsageProvider.cs
@@ -54,6 +54,7 @@ public enum UnityPresentationType
private readonly UnitySceneDataLocalCache myUnitySceneDataLocalCache;
private readonly ITooltipManager myTooltipManager;
private readonly TextControlManager myTextControlManager;
+ private readonly UnityEditorProtocol myProtocol;
public override string ProviderId => "Unity serialized field";
public override string DisplayName => "Unity serialized field";
public override CodeLensAnchorKind DefaultAnchor => CodeLensAnchorKind.Right;
@@ -63,7 +64,7 @@ public enum UnityPresentationType
public UnityCodeInsightFieldUsageProvider(Lifetime lifetime, UnitySolutionTracker unitySolutionTracker, ConnectionTracker connectionTracker,
UnityApi unityApi, UnityHost host, BulbMenuComponent bulbMenu, IPsiFiles files, UnityHost unityHost, UnitySceneDataLocalCache sceneDataCache,
- ITooltipManager tooltipManager, TextControlManager textControlManager)
+ ITooltipManager tooltipManager, TextControlManager textControlManager, UnityEditorProtocol protocol)
: base(unitySolutionTracker, host, bulbMenu)
{
myLifetime = lifetime;
@@ -74,6 +75,7 @@ public UnityCodeInsightFieldUsageProvider(Lifetime lifetime, UnitySolutionTracke
myUnitySceneDataLocalCache = sceneDataCache;
myTooltipManager = tooltipManager;
myTextControlManager = textControlManager;
+ myProtocol = protocol;
}
private static (string guid, string propertyName)? GetAssetGuidAndPropertyName(ISolution solution, IDeclaredElement declaredElement)
@@ -177,7 +179,7 @@ public override void OnClick(CodeInsightsHighlighting highlighting, ISolution so
var value = (key as MonoBehaviourPropertyValueWithLocation).NotNull("value != null");
- UnityEditorFindUsageResultCreator.CreateRequestAndShow(myUnityHost, solution.SolutionDirectory, myUnitySceneDataLocalCache,
+ UnityEditorFindUsageResultCreator.CreateRequestAndShow(myProtocol, myUnityHost, myLifetime, solution.SolutionDirectory, myUnitySceneDataLocalCache,
value.Value.MonoBehaviour, value.File);
});
});
diff --git a/resharper/resharper-unity/src/Rider/UnityEditorFindUsageResultCreator.cs b/resharper/resharper-unity/src/Rider/UnityEditorFindUsageResultCreator.cs
index 4b187d23af..aa4e068018 100644
--- a/resharper/resharper-unity/src/Rider/UnityEditorFindUsageResultCreator.cs
+++ b/resharper/resharper-unity/src/Rider/UnityEditorFindUsageResultCreator.cs
@@ -4,6 +4,7 @@
using JetBrains.Application.Progress;
using JetBrains.Application.Threading;
using JetBrains.Application.Threading.Tasks;
+using JetBrains.Core;
using JetBrains.Lifetimes;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Host.Features.BackgroundTasks;
@@ -30,10 +31,13 @@ public class UnityEditorFindUsageResultCreator
private readonly UnitySceneDataLocalCache myUnitySceneDataLocalCache;
private readonly RiderBackgroundTaskHost myBackgroundTaskHost;
private readonly UnityHost myUnityHost;
+ private readonly UnityEditorProtocol myEditorProtocol;
private readonly FileSystemPath mySolutionDirectoryPath;
public UnityEditorFindUsageResultCreator(Lifetime lifetime, ISolution solution, SearchDomainFactory searchDomainFactory, IShellLocks locks,
- UnitySceneDataLocalCache sceneDataCache, UnityHost unityHost, UnityExternalFilesModuleFactory externalFilesModuleFactory, [CanBeNull] RiderBackgroundTaskHost backgroundTaskHost = null)
+ UnitySceneDataLocalCache sceneDataCache, UnityHost unityHost, UnityExternalFilesModuleFactory externalFilesModuleFactory,
+ UnityEditorProtocol editorProtocol,
+ [CanBeNull] RiderBackgroundTaskHost backgroundTaskHost = null)
{
myLifetime = lifetime;
mySolution = solution;
@@ -42,6 +46,7 @@ public UnityEditorFindUsageResultCreator(Lifetime lifetime, ISolution solution,
myBackgroundTaskHost = backgroundTaskHost;
myYamlSearchDomain = searchDomainFactory.CreateSearchDomain(externalFilesModuleFactory.PsiModule);
myUnityHost = unityHost;
+ myEditorProtocol = editorProtocol;
mySolutionDirectoryPath = solution.SolutionDirectory;
}
@@ -89,7 +94,7 @@ public void CreateRequestToUnity([NotNull] IDeclaredElement declaredElement, IPs
{
finder.FindAsync(new[] {declaredElement}, myYamlSearchDomain,
consumer, SearchPattern.FIND_USAGES ,pi,
- FinderSearchRoot.Empty, new UnityUsagesAsyncFinderCallback(lifetimeDef, consumer, myUnityHost, myLocks,
+ FinderSearchRoot.Empty, new UnityUsagesAsyncFinderCallback(lifetimeDef, myLifetime, consumer, myUnityHost, myEditorProtocol, myLocks,
declaredElement.ShortName, selectRequest, focusUnity));
}
});
@@ -109,16 +114,20 @@ public static FindUsageResultElement CreateRequest([NotNull] FileSystemPath solu
return new FindUsageResultElement(isPrefab, needExpand, pathFromAsset, fileName, consumer.NameParts.ToArray(), consumer.RootIndexes.ToArray());
}
- public static void CreateRequestAndShow([NotNull] UnityHost unityHost, [NotNull] FileSystemPath solutionDirPath, [NotNull]UnitySceneDataLocalCache unitySceneDataLocalCache,
+ public static void CreateRequestAndShow([NotNull] UnityEditorProtocol editor, UnityHost host, Lifetime lifetime, [NotNull] FileSystemPath solutionDirPath, [NotNull]UnitySceneDataLocalCache unitySceneDataLocalCache,
[NotNull] string anchor, IPsiSourceFile sourceFile, bool needExpand = false)
{
-
+ FindUsageResultElement request;
using (ReadLockCookie.Create())
{
- var request = CreateRequest(solutionDirPath, unitySceneDataLocalCache, anchor, sourceFile, needExpand);
- unityHost.PerformModelAction(t => t.ShowGameObjectOnScene.Fire(request));
+ request = CreateRequest(solutionDirPath, unitySceneDataLocalCache, anchor, sourceFile, needExpand);
}
- UnityFocusUtil.FocusUnity(unityHost.GetValue(t => t.UnityProcessId.Value));
+
+ host.PerformModelAction(a => a.AllowSetForegroundWindow.Start(Unit.Instance).Result.Advise(lifetime,
+ result =>
+ {
+ editor.UnityModel.Value.ShowGameObjectOnScene.Fire(request.ConvertToUnityModel());
+ }));
}
private static bool GetPathFromAssetFolder([NotNull] FileSystemPath solutionDirPath, [NotNull] IPsiSourceFile file,
@@ -181,50 +190,56 @@ public FindExecution Merge(IUnityYamlReference data)
private class UnityUsagesAsyncFinderCallback : IFinderAsyncCallback
{
- private readonly LifetimeDefinition myLifetimeDef;
+ private readonly LifetimeDefinition myProgressBarLifetimeDefinition;
+ private readonly Lifetime myComponentLifetime;
private readonly UnityUsagesFinderConsumer myConsumer;
private readonly UnityHost myUnityHost;
+ private readonly UnityEditorProtocol myEditorProtocol;
private readonly IShellLocks myShellLocks;
private readonly string myDisplayName;
private readonly FindUsageResultElement mySelected;
- private readonly bool myFocusUnity;
- public UnityUsagesAsyncFinderCallback(LifetimeDefinition lifetimeDef, UnityUsagesFinderConsumer consumer, UnityHost unityHost, IShellLocks shellLocks,
+ public UnityUsagesAsyncFinderCallback(LifetimeDefinition progressBarLifetimeDefinition, Lifetime componentLifetime, UnityUsagesFinderConsumer consumer, UnityHost unityHost, UnityEditorProtocol editorProtocol, IShellLocks shellLocks,
string displayName, FindUsageResultElement selected, bool focusUnity)
{
- myLifetimeDef = lifetimeDef;
+ myProgressBarLifetimeDefinition = progressBarLifetimeDefinition;
+ myComponentLifetime = componentLifetime;
myConsumer = consumer;
myUnityHost = unityHost;
+ myEditorProtocol = editorProtocol;
myShellLocks = shellLocks;
myDisplayName = displayName;
mySelected = selected;
- myFocusUnity = focusUnity;
}
public void Complete()
{
- myShellLocks.Tasks.StartNew(myLifetimeDef.Lifetime, Scheduling.MainGuard, () =>
+ myShellLocks.Tasks.StartNew(myComponentLifetime, Scheduling.MainGuard, () =>
{
if (myConsumer.Result.Count != 0)
{
-
- if (myFocusUnity)
- UnityFocusUtil.FocusUnity(myUnityHost.GetValue(t => t.UnityProcessId.Value));
-
- if (mySelected != null)
- myUnityHost.PerformModelAction(t => t.ShowGameObjectOnScene.Fire(mySelected));
- myUnityHost.PerformModelAction(t =>
- t.FindUsageResults.Fire(new FindUsageResult(myDisplayName, myConsumer.Result.ToArray())));
-
+ if (myEditorProtocol.UnityModel.Value == null) return;
+
+ myUnityHost.PerformModelAction(a => a.AllowSetForegroundWindow.Start(Unit.Instance).Result
+ .Advise(myComponentLifetime,
+ result =>
+ {
+ var model = myEditorProtocol.UnityModel.Value;
+ if (mySelected != null)
+ model.ShowGameObjectOnScene.Fire(mySelected.ConvertToUnityModel());
+ // pass all references to Unity TODO temp workaround, replace with async api
+ model.FindUsageResults.Fire(new FindUsageResult(myDisplayName,
+ myConsumer.Result.ToArray()).ConvertToUnityModel());
+ }));
}
-
- myLifetimeDef.Terminate();
+
+ myProgressBarLifetimeDefinition.Terminate();
});
}
public void Error(string message)
{
- myLifetimeDef.Terminate();
+ myProgressBarLifetimeDefinition.Terminate();
}
}
}
diff --git a/resharper/resharper-unity/src/Rider/UnityEditorProtocol.cs b/resharper/resharper-unity/src/Rider/UnityEditorProtocol.cs
index 8a816a0d9c..37b96e922f 100644
--- a/resharper/resharper-unity/src/Rider/UnityEditorProtocol.cs
+++ b/resharper/resharper-unity/src/Rider/UnityEditorProtocol.cs
@@ -186,19 +186,12 @@ private void CreateProtocols(FileSystemPath protocolInstancePath)
editor.UnityProcessId.View(lf, (_, pid) => myHost.PerformModelAction(t => t.UnityProcessId.Set(pid)));
// I have split this into groups, because want to use async api for finding reference and pass them via groups to Unity
- myHost.PerformModelAction(t => t.ShowGameObjectOnScene.Advise(lf, v => editor.ShowGameObjectOnScene.Fire(v.ConvertToUnityModel())));
myHost.PerformModelAction(t => t.ShowFileInUnity.Advise(lf, v => editor.ShowFileInUnity.Fire(v)));
myHost.PerformModelAction(t => t.ShowPreferences.Advise(lf, v =>
{
- if (t.UnityProcessId.HasValue())
- UnityFocusUtil.FocusUnity(t.UnityProcessId.Value);
-
editor.ShowPreferences.Fire();
}));
-
- // pass all references to Unity TODO temp workaround, replace with async api
- myHost.PerformModelAction(t => t.FindUsageResults.Advise(lf, v =>editor.FindUsageResults.Fire(v.ConvertToUnityModel())));
-
+
editor.EditorLogPath.Advise(lifetime,
s => myHost.PerformModelAction(a => a.EditorLogPath.SetValue(s)));
editor.PlayerLogPath.Advise(lifetime,
diff --git a/resharper/resharper-unity/src/UnityFocusUtil.cs b/resharper/resharper-unity/src/UnityFocusUtil.cs
deleted file mode 100644
index 60d21da4d9..0000000000
--- a/resharper/resharper-unity/src/UnityFocusUtil.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using JetBrains.Interop.WinApi;
-using JetBrains.Util;
-
-namespace JetBrains.ReSharper.Plugins.Unity
-{
- public static class UnityFocusUtil
- {
-
- [DllImport("User32.dll")]
- private static extern bool SwitchToThisWindow (IntPtr hwnd, bool fUnknown);
-
- public static void FocusUnity(int pid)
- {
- if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.Windows)
- {
- var process = Process.GetProcessById(pid);
- var hWnd = process.MainWindowHandle;
-
- SwitchToThisWindow(hWnd, true);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/rider/protocol/src/main/kotlin/model/rider/RdUnityModel.kt b/rider/protocol/src/main/kotlin/model/rider/RdUnityModel.kt
index 9a8f3c0a00..ae5ba0f281 100644
--- a/rider/protocol/src/main/kotlin/model/rider/RdUnityModel.kt
+++ b/rider/protocol/src/main/kotlin/model/rider/RdUnityModel.kt
@@ -89,12 +89,11 @@ object RdUnityModel : Ext(SolutionModel.Solution) {
property("ScriptCompilationDuringPlay", ScriptCompilationDuringPlay)
source("enableYamlParsing", void)
- signal("findUsageResults", FindUsageResult)
- signal("showGameObjectOnScene", FindUsageResultElement)
signal("showFileInUnity", string)
property("unityProcessId", int)
sink("onEditorModelOutOfSync", void)
callback("attachDebuggerToUnityEditor", void, bool)
+ callback("allowSetForegroundWindow", void, bool)
}
}
\ No newline at end of file
diff --git a/rider/src/main/kotlin/com/jetbrains/rider/plugins/unity/UnityHost.kt b/rider/src/main/kotlin/com/jetbrains/rider/plugins/unity/UnityHost.kt
index 762ee58eb9..d8fddb50a1 100644
--- a/rider/src/main/kotlin/com/jetbrains/rider/plugins/unity/UnityHost.kt
+++ b/rider/src/main/kotlin/com/jetbrains/rider/plugins/unity/UnityHost.kt
@@ -4,7 +4,9 @@ import com.intellij.execution.ProgramRunnerUtil
import com.intellij.execution.RunManager
import com.intellij.execution.executors.DefaultDebugExecutor
import com.intellij.ide.impl.ProjectUtil
+import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.wm.WindowManager
import com.intellij.util.BitUtil
import com.intellij.xdebugger.XDebuggerManager
@@ -26,11 +28,13 @@ import com.jetbrains.rider.plugins.unity.run.configurations.UnityAttachToEditorR
import com.jetbrains.rider.plugins.unity.run.configurations.UnityDebugConfigurationType
import com.jetbrains.rider.projectView.solution
import com.jetbrains.rider.util.idea.getComponent
+import com.sun.jna.Native
+import com.sun.jna.win32.StdCallLibrary
import java.awt.Frame
class UnityHost(project: Project, runManager: RunManager) : LifetimedProjectComponent(project) {
val model = project.solution.rdUnityModel
-
+ private val logger = Logger.getInstance(UnityHost::class.java)
val sessionInitialized = model.sessionInitialized
val unityState = model.editorState
@@ -89,11 +93,34 @@ class UnityHost(project: Project, runManager: RunManager) : LifetimedProjectComp
}
task
}
+
+ model.allowSetForegroundWindow.set { _, _ ->
+ val task = RdTask()
+ if (SystemInfo.isWindows) {
+ val id = model.unityProcessId.valueOrNull
+ if (id != null && id > 0)
+ task.set(user32.AllowSetForegroundWindow(id))
+ else
+ logger.warn("unityProcessId is null or 0")
+ }
+ else
+ task.set(true)
+
+ task
+ }
+
}
companion object {
fun getInstance(project: Project) = project.getComponent()
}
+
+ @Suppress("FunctionName")
+ private interface User32 : StdCallLibrary {
+ fun AllowSetForegroundWindow(id:Int) : Boolean
+ }
+
+ private val user32 = Native.load("user32", User32::class.java)
}
fun Project.isConnectedToEditor() = UnityHost.getInstance(this).sessionInitialized.valueOrDefault(false)
\ No newline at end of file
diff --git a/rider/src/main/resources/META-INF/plugin.xml b/rider/src/main/resources/META-INF/plugin.xml
index c4290fa208..c28483a011 100644
--- a/rider/src/main/resources/META-INF/plugin.xml
+++ b/rider/src/main/resources/META-INF/plugin.xml
@@ -265,6 +265,8 @@
Fixed:
+ - Rider: Fix Clear on Play in Rider's Unity log viewer (#1281, #1294)
+ - Unity window should get focus, when Rider is showing usages in it ([#1344](https://github.com/JetBrains/resharper-unity/pull/1344)
- Unity Editor: Fix exception calling EditorApplication.isPlaying on wrong thread (#1308)
diff --git a/unity/EditorPlugin/AfterUnity56/Navigation/Initialization.cs b/unity/EditorPlugin/AfterUnity56/Navigation/Initialization.cs
index 5bc86971c1..b88e7eac55 100644
--- a/unity/EditorPlugin/AfterUnity56/Navigation/Initialization.cs
+++ b/unity/EditorPlugin/AfterUnity56/Navigation/Initialization.cs
@@ -1,7 +1,8 @@
-using System;
-using System.Reflection;
+using System.Diagnostics;
+using System.Linq;
using JetBrains.Rider.Unity.Editor.Navigation;
using JetBrains.Rider.Unity.Editor.Navigation.Window;
+using JetBrains.Rider.Unity.Editor.NonUnity;
using UnityEditor;
using UnityEngine;
@@ -19,7 +20,10 @@ public static void OnModelInitializationHandler(UnityModelAndLifetime modelAndLi
{
MainThreadDispatcher.Instance.Queue(() =>
{
+ ExpandMinimizedUnityWindow();
+
EditorUtility.FocusProjectWindow();
+
if (findUsagesResult.IsPrefab)
{
ShowUtil.ShowFileUsage(findUsagesResult.FilePath);
@@ -60,5 +64,24 @@ public static void OnModelInitializationHandler(UnityModelAndLifetime modelAndLi
}
});
}
+
+ private static void ExpandMinimizedUnityWindow()
+ {
+ if (PluginSettings.SystemInfoRiderPlugin.operatingSystemFamily == OperatingSystemFamilyRider.Windows)
+ {
+ var topLevelWindows = User32Dll.GetTopLevelWindowHandles();
+ var windowHandles = topLevelWindows
+ .Where(hwnd => User32Dll.GetWindowProcessId(hwnd) == Process.GetCurrentProcess().Id).ToArray();
+
+ foreach (var windowHandle in windowHandles)
+ {
+ if (User32Dll.IsIconic(windowHandle))
+ {
+ User32Dll.ShowWindow(windowHandle, 9);
+ User32Dll.SetForegroundWindow(windowHandle);
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/unity/EditorPlugin/NonUnity/User32Dll.cs b/unity/EditorPlugin/NonUnity/User32Dll.cs
index e72a95480a..987fbb623f 100644
--- a/unity/EditorPlugin/NonUnity/User32Dll.cs
+++ b/unity/EditorPlugin/NonUnity/User32Dll.cs
@@ -53,5 +53,9 @@ public static List GetTopLevelWindowHandles()
[DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true,
ExactSpelling = true)]
public static extern uint ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("User32.dll")]
+ public static extern bool IsIconic(IntPtr handle);
+
}
}
\ No newline at end of file