2026-04-12 23:08:09 -04:00
--- Engine/Plugins/Developer/VisualStudioCodeSourceCodeAccess/Source/VisualStudioCodeSourceCodeAccess/Private/VisualStudioCodeSourceCodeAccessor.cpp.orig 2026-04-12 22:58:34.075320964 -0400
+++ Engine/Plugins/Developer/VisualStudioCodeSourceCodeAccess/Source/VisualStudioCodeSourceCodeAccess/Private/VisualStudioCodeSourceCodeAccessor.cpp 2026-04-12 23:03:40.139226303 -0400
2026-03-02 16:26:19 -05:00
@@ -149,7 +149,7 @@
FString SolutionDir = GetSolutionPath();
TArray<FString> Args;
Args.Add(MakePath(SolutionDir));
- Args.Add(TEXT("-g ") + MakePath(FullPath) + FString::Printf(TEXT(":%d:%d"), LineNumber, ColumnNumber));
+ Args.Add(TEXT("-g ") + MakePath(FullPath + FString::Printf(TEXT(":%d:%d"), LineNumber, ColumnNumber)));
return Launch(Args);
}
2026-04-12 23:08:09 -04:00
--- Engine/Source/Editor/UnrealEd/Private/SourceCodeNavigation.cpp.orig 2026-04-12 22:58:34.169323705 -0400
+++ Engine/Source/Editor/UnrealEd/Private/SourceCodeNavigation.cpp 2026-04-12 23:04:02.208867909 -0400
2026-03-02 16:26:19 -05:00
@@ -463,7 +463,7 @@
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>("SourceCodeAccess");
ISourceCodeAccessor& SourceCodeAccessor = SourceCodeAccessModule.GetAccessor();
-#if PLATFORM_WINDOWS
+#if PLATFORM_WINDOWS || PLATFORM_LINUX
FString SourceFileName;
uint32 SourceLineNumber = 1;
uint32 SourceColumnNumber = 0;
@@ -622,8 +622,8 @@
}
UE_LOG(LogSelectionDetails, Warning, TEXT("NavigateToFunctionSource: Unable to look up symbol: %s in module:%s"), *FunctionSymbolName, *FunctionModuleName);
-
-#endif // PLATFORM_WINDOWS
+
+#endif // PLATFORM_WINDOWS || PLATFORM_LINUX
}
2026-04-12 23:08:09 -04:00
--- Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp.orig 2026-04-12 22:58:34.254326184 -0400
+++ Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp 2025-11-10 23:34:18.481701126 -0500
2025-06-19 18:01:05 -04:00
@@ -299,6 +299,9 @@
2026-03-02 16:26:19 -05:00
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1"); // When relative mouse mode is active, don't hide cursor.
2024-11-05 20:26:39 -05:00
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "0"); // Don't warp the cursor to the center in relative mouse mode.
+ // Unreal does its own dynamic capturing, we don't need SDL to do it.
+ SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
+
// If we're rendering offscreen, use the "dummy" SDL video driver
if (FParse::Param(FCommandLine::Get(), TEXT("RenderOffScreen")) && !getenv("SDL_VIDEODRIVER"))
{
2026-04-12 23:08:09 -04:00
--- Engine/Source/Runtime/Core/Private/Unix/UnixPlatformStackWalk.cpp.orig 2026-04-12 22:58:34.349328955 -0400
+++ Engine/Source/Runtime/Core/Private/Unix/UnixPlatformStackWalk.cpp 2026-04-12 23:05:56.395187515 -0400
2026-03-02 16:26:19 -05:00
@@ -15,6 +15,7 @@
#include "HAL/ExceptionHandling.h"
#include "HAL/PlatformProcess.h"
#include "HAL/PlatformTime.h"
+#include "Modules/ModuleManager.h"
2026-05-05 16:26:49 -04:00
#include "AutoRTFM.h"
2026-03-02 16:26:19 -05:00
#include <link.h>
@@ -1060,3 +1061,69 @@
}
ReportLock.Unlock();
}
+
+bool FUnixPlatformStackWalk::GetFunctionDefinitionLocation(const FString& FunctionSymbolName, const FString& FunctionModuleName, FString& OutPathname, uint32& OutLineNumber, uint32& OutColumnNumber)
+{
+ // Find the .so path for this module.
+ FString ModulePath;
+ TArray<FModuleStatus> AllModules;
+ FModuleManager::Get().QueryModules(AllModules);
+ for (const FModuleStatus& Status : AllModules)
+ {
+ if (FPaths::GetBaseFilename(Status.FilePath) == FunctionModuleName)
+ {
+ ModulePath = Status.FilePath;
+ break;
+ }
+ }
+ if (ModulePath.IsEmpty())
+ {
+ return false;
+ }
+
+ // Debug symbols are in a separate .debug file alongside the .so.
+ FString DebugPath = FPaths::ChangeExtension(ModulePath, TEXT("debug"));
+ if (!FPaths::FileExists(DebugPath))
+ {
+ return false;
+ }
+
+ // Use lldb to look up the source file and line number.
+ // Run: lldb -b -o "image lookup -v -n ClassName::FuncName" <debug_file>
+ FString LldbParams = FString::Printf(TEXT("-b -o \"image lookup -v -n %s\" \"%s\""), *FunctionSymbolName, *DebugPath);
+ int32 ReturnCode = 0;
+ FString AllOutput;
+ FString Errors;
+ FPlatformProcess::ExecProcess(TEXT("/usr/bin/lldb"), *LldbParams, &ReturnCode, &AllOutput, &Errors);
+ if (ReturnCode != 0)
+ {
+ return false;
+ }
+
+ // Parse the LineEntry from lldb verbose output.
+ // Format: "LineEntry: [0x...-0x...): /path/to/file.cpp:132"
+ TArray<FString> Lines;
+ AllOutput.ParseIntoArrayLines(Lines);
+ for (const FString& Line : Lines)
+ {
+ FString Trimmed = Line.TrimStartAndEnd();
+ if (!Trimmed.StartsWith(TEXT("LineEntry:")))
+ continue;
+
+ int32 ParenIndex = Trimmed.Find(TEXT("): "));
+ if (ParenIndex == INDEX_NONE)
+ continue;
+ FString FileAndLine = Trimmed.Mid(ParenIndex + 3);
+
+ int32 ColonIndex;
+ if (!FileAndLine.FindLastChar(TCHAR(':'), ColonIndex))
+ continue;
+
+ OutPathname = FileAndLine.Left(ColonIndex);
+ OutLineNumber = FCString::Atoi(*FileAndLine.Mid(ColonIndex + 1));
+ OutColumnNumber = 0;
+ return true;
+ }
+
+ return false;
+}
2026-04-12 23:08:09 -04:00
--- Engine/Source/Runtime/Core/Public/Unix/UnixPlatformStackWalk.h.orig 2026-04-12 22:58:34.451331930 -0400
+++ Engine/Source/Runtime/Core/Public/Unix/UnixPlatformStackWalk.h 2026-04-12 23:06:10.273590986 -0400
2026-03-02 16:26:19 -05:00
@@ -24,6 +24,8 @@
static CORE_API void ThreadStackWalkAndDump(ANSICHAR* HumanReadableString, SIZE_T HumanReadableStringSize, int32 IgnoreCount, uint32 ThreadId);
static CORE_API int32 GetProcessModuleCount();
static CORE_API int32 GetProcessModuleSignatures(FStackWalkModuleInfo *ModuleSignatures, const int32 ModuleSignaturesSize);
+
+ static CORE_API bool GetFunctionDefinitionLocation(const FString& FunctionSymbolName, const FString& FunctionModuleName, FString& OutPathname, uint32& OutLineNumber, uint32& OutColumnNumber);
};
typedef FUnixPlatformStackWalk FPlatformStackWalk;
2026-05-07 04:11:37 -04:00
--- Engine/Source/Runtime/ApplicationCore/Public/Linux/LinuxApplication.h.orig 2026-05-05 21:15:20.644087179 -0400
+++ Engine/Source/Runtime/ApplicationCore/Public/Linux/LinuxApplication.h 2026-05-05 21:15:38.654613091 -0400
@@ -265,6 +265,12 @@
/** The input device Id of the controller that can be used to find the matching ULocalPlayer */
FInputDeviceId DeviceId;
+ /** SDL gamepad type string (e.g. "ps4", "xboxone"), used as HardwareDeviceIdentifier in FInputDeviceScope */
+ FName GamepadType;
+
+ /** SDL gamepad name (human-readable device name), used as InputDeviceName in FInputDeviceScope */
+ FName GamepadName;
+
/** Store axis values from events here to be handled once per frame. */
TMap<FGamepadKeyNames::Type, float> AxisEvents;
--- Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxApplication.cpp.orig 2026-05-05 21:15:20.646317814 -0400
+++ Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxApplication.cpp 2026-05-05 23:13:59.528028910 -0400
@@ -13,6 +13,13 @@
#include "IHapticDevice.h"
#include "GenericPlatform/GenericPlatformInputDeviceMapper.h"
+namespace UE::LinuxInput
+{
+ static const FName InputClassName = TEXT("LinuxApplication");
+ static const FString KBMInputHardwareName = TEXT("KBM");
+ static const FString TouchInputHardwareName = TEXT("MobileTouch");
+}
+
//
// GameController thresholds
//
@@ -320,6 +327,7 @@
{
case SDL_EVENT_KEY_DOWN:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
const SDL_KeyboardEvent &KeyEvent = Event.key;
SDL_Keycode KeySym = KeyEvent.key;
const uint32 CharCode = CharCodeFromSDLKeySym(KeySym);
@@ -342,6 +350,7 @@
break;
case SDL_EVENT_KEY_UP:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
const SDL_KeyboardEvent &KeyEvent = Event.key;
const SDL_Keycode KeySym = KeyEvent.key;
const uint32 CharCode = CharCodeFromSDLKeySym(KeySym);
@@ -352,6 +361,7 @@
break;
case SDL_EVENT_TEXT_INPUT:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
// Slate now gets all its text from here, I hope.
const bool bIsRepeated = false; //Event.key.repeat != 0;
const FString TextStr(UTF8_TO_TCHAR(Event.text.text));
@@ -363,6 +373,7 @@
break;
case SDL_EVENT_MOUSE_MOTION:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
SDL_MouseMotionEvent motionEvent = Event.motion;
FLinuxCursor *LinuxCursor = (FLinuxCursor*)Cursor.Get();
LinuxCursor->InvalidateCaches();
@@ -406,6 +417,7 @@
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
SDL_MouseButtonEvent buttonEvent = Event.button;
EMouseButtons::Type button;
@@ -484,6 +496,7 @@
break;
case SDL_EVENT_MOUSE_WHEEL:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::KBMInputHardwareName);
SDL_MouseWheelEvent *WheelEvent = &Event.wheel;
float Amount = (float)WheelEvent->y * fMouseWheelScrollAccel;
@@ -515,6 +528,7 @@
SDLControllerState &ControllerState = ControllerStates[caxisEvent.which];
FPlatformUserId UserId = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerState.DeviceId);
+ FInputDeviceScope InputScope(nullptr, ControllerState.GamepadName, ControllerState.DeviceId.GetId(), ControllerState.GamepadType.ToString());
switch (caxisEvent.axis)
{
@@ -740,15 +754,17 @@
if (Button != FGamepadKeyNames::Invalid)
{
- FPlatformUserId UserId = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerStates[cbuttonEvent.which].DeviceId);
+ SDLControllerState& ButtonControllerState = ControllerStates[cbuttonEvent.which];
+ FPlatformUserId UserId = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ButtonControllerState.DeviceId);
+ FInputDeviceScope InputScope(nullptr, ButtonControllerState.GamepadName, ButtonControllerState.DeviceId.GetId(), ButtonControllerState.GamepadType.ToString());
if(cbuttonEvent.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN)
{
- MessageHandler->OnControllerButtonPressed(Button, UserId, ControllerStates[cbuttonEvent.which].DeviceId, false);
+ MessageHandler->OnControllerButtonPressed(Button, UserId, ButtonControllerState.DeviceId, false);
}
else
{
- MessageHandler->OnControllerButtonReleased(Button, UserId, ControllerStates[cbuttonEvent.which].DeviceId, false);
+ MessageHandler->OnControllerButtonReleased(Button, UserId, ButtonControllerState.DeviceId, false);
}
}
}
@@ -1018,6 +1034,7 @@
case SDL_EVENT_FINGER_DOWN:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::TouchInputHardwareName);
UE_LOG(LogLinuxWindow, Verbose, TEXT("Finger %llu is down at (%f, %f)"), Event.tfinger.fingerID, Event.tfinger.x, Event.tfinger.y);
// touch events can have no window associated with them, in that case ignore (with a warning)
@@ -1053,6 +1070,7 @@
break;
case SDL_EVENT_FINGER_UP:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::TouchInputHardwareName);
UE_LOG(LogLinuxWindow, Verbose, TEXT("Finger %llu is up at (%f, %f)"), Event.tfinger.fingerID, Event.tfinger.x, Event.tfinger.y);
// touch events can have no window associated with them, in that case ignore (with a warning)
@@ -1087,6 +1105,7 @@
break;
case SDL_EVENT_FINGER_MOTION:
{
+ FInputDeviceScope InputScope(nullptr, UE::LinuxInput::InputClassName, IPlatformInputDeviceMapper::Get().GetDefaultInputDevice().GetId(), UE::LinuxInput::TouchInputHardwareName);
// touch events can have no window associated with them, in that case ignore (with a warning)
if (LIKELY(!bWindowlessEvent))
{
@@ -1196,6 +1215,7 @@
IPlatformInputDeviceMapper& Mapper = IPlatformInputDeviceMapper::Get();
for(auto ControllerIt = ControllerStates.CreateIterator(); ControllerIt; ++ControllerIt)
{
+ FInputDeviceScope InputScope(nullptr, ControllerIt.Value().GamepadName, ControllerIt.Value().DeviceId.GetId(), ControllerIt.Value().GamepadType.ToString());
for(auto Event = ControllerIt.Value().AxisEvents.CreateConstIterator(); Event; ++Event)
{
FPlatformUserId UserId = Mapper.GetUserForInputDevice(ControllerIt.Value().DeviceId);
@@ -2075,6 +2095,9 @@
UE_LOG(LogLinux, Verbose, TEXT("Adding controller %i '%s'"), FirstUnusedIndex, UTF8_TO_TCHAR(SDL_GetGamepadName(Controller)));
auto& ControllerState = ControllerStates.Add(Id);
ControllerState.Controller = Controller;
+ ControllerState.GamepadName = FName(UTF8_TO_TCHAR(SDL_GetGamepadName(Controller)));
+ const char* GamepadTypeStr = SDL_GetGamepadStringForType(SDL_GetGamepadType(Controller));
+ ControllerState.GamepadType = FName(GamepadTypeStr ? UTF8_TO_TCHAR(GamepadTypeStr) : TEXT("unknown"));
FPlatformUserId UserId = FPlatformUserId::CreateFromInternalId(FirstUnusedIndex);
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(FirstUnusedIndex, UserId, ControllerState.DeviceId);