diff --git a/Intersect.Client.Core/Intersect.Client.Core.csproj b/Intersect.Client.Core/Intersect.Client.Core.csproj index 1cff05557b..976e522cb8 100644 --- a/Intersect.Client.Core/Intersect.Client.Core.csproj +++ b/Intersect.Client.Core/Intersect.Client.Core.csproj @@ -87,6 +87,7 @@ + diff --git a/Intersect.Client.Core/MonoGame/IntersectGame.cs b/Intersect.Client.Core/MonoGame/IntersectGame.cs index b0df9d0ed9..89c8a0da6f 100644 --- a/Intersect.Client.Core/MonoGame/IntersectGame.cs +++ b/Intersect.Client.Core/MonoGame/IntersectGame.cs @@ -17,6 +17,7 @@ using Microsoft.Xna.Framework.Graphics; using System.Diagnostics; using System.Reflection; +using HarmonyLib; using Intersect.Client.Framework.Database; using Intersect.Client.Framework.Graphics; using Intersect.Client.ThirdParty; @@ -25,6 +26,7 @@ using MainMenu = Intersect.Client.Interface.Menu.MainMenu; using Intersect.Logging; using Intersect.Client.Interface.Shared; +using Intersect.Client.MonoGame.NativeInterop; namespace Intersect.Client.MonoGame; @@ -557,9 +559,28 @@ internal partial class MonoGameRunner : IPlatformRunner /// public void Start(IClientContext context, Action postStartupAction) { - using (var game = new IntersectGame(context, postStartupAction)) + var assemblyMonoGameFramework = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(assembly => assembly.FullName?.StartsWith("MonoGame.Framework") ?? false); + var typeInternalSdl = assemblyMonoGameFramework?.GetType("Sdl"); + var methodSdlInit = typeInternalSdl?.GetMethod("Init"); + + var harmonyPatch = new Harmony(typeof(MonoGameRunner).Assembly.FullName ?? "Intersect.Client.Core"); + harmonyPatch.Patch(methodSdlInit, postfix: SymbolExtensions.GetMethodInfo(() => SdlInitPost())); + + using var game = new IntersectGame(context, postStartupAction); + game.Run(); + } + + private static void SdlInitPost() + { + if (PlatformHelper.CurrentPlatform != Platform.Linux) + { + return; + } + + if (!Sdl2.SDL_SetHint(Sdl2.SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, false)) { - game.Run(); + LegacyLogging.Logger?.Warn("Failed to set X11 Compositor hint"); } } } diff --git a/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Hints.cs b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Hints.cs new file mode 100644 index 0000000000..f3612a26be --- /dev/null +++ b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Hints.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; +using System.Text; + +namespace Intersect.Client.MonoGame.NativeInterop; + +public partial class Sdl2 +{ + public const string SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR = "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate int SDL_SetHint_d(byte* name, byte* value); + + private static SDL_SetHint_d SDL_SetHint_f = Loader.Functions.LoadFunction(nameof(SDL_SetHint)); + + public static unsafe bool SDL_SetHint(string name, string value) + { + fixed (byte* pValue = Encoding.UTF8.GetBytes(value)) + { + fixed (byte* pName = Encoding.UTF8.GetBytes(name)) + { + return SDL_SetHint_f(pName, pValue) != 0; + } + } + } + + public static bool SDL_SetHint(string name, bool value) => SDL_SetHint(name, value ? "1" : "0"); +} \ No newline at end of file diff --git a/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Video.cs b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Video.cs index 8469f07089..c2aa52f6ce 100644 --- a/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Video.cs +++ b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.Video.cs @@ -12,7 +12,7 @@ public partial class Sdl2 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int SDL_GetDisplayBounds_d(int displayIndex, SDL_Rect * rect); - + private static SDL_GetDisplayBounds_d SDL_GetDisplayBounds_f = Loader.Functions.LoadFunction(nameof(SDL_GetDisplayBounds)); @@ -33,7 +33,7 @@ public static unsafe bool TryGetDisplayBounds(int displayIndex, out SDL_Rect bou return SDL_GetDisplayBounds_f(displayIndex, boundsPointer) == 0; } } - + public static SDL_Rect[] GetDisplayBounds() { var displayCount = SDL_GetNumVideoDisplays(); diff --git a/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.cs b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.cs index a83aa514e4..7e27bf2a3a 100644 --- a/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.cs +++ b/Intersect.Client.Core/MonoGame/NativeInterop/Sdl2.cs @@ -21,7 +21,7 @@ public static unsafe string SDL_GetError() { throw new PlatformNotSupportedException(); } - + var textBytes = SDL_GetError_f(); var endTextBytes = textBytes; while (*endTextBytes != default) @@ -36,21 +36,23 @@ public static unsafe string SDL_GetError() [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate void SDL_free_d(void* ptr); - private static SDL_free_d SDL_free = Loader.Functions.LoadFunction(nameof(SDL_free)); - + private static SDL_free_d? SDL_free_f = Loader.Functions.LoadFunction(nameof(SDL_free_f)); + + private static unsafe void SDL_free(void* ptr) => SDL_free_f!(ptr); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate byte* SDL_GetClipboardText_d(); - private static SDL_GetClipboardText_d SDL_GetClipboardText_f = + private static SDL_GetClipboardText_d? SDL_GetClipboardText_f = Loader.Functions.LoadFunction(nameof(SDL_GetClipboardText)); public static unsafe string SDL_GetClipboardText() { - if (SDL_GetClipboardText_f == default || SDL_free == default) + if (SDL_GetClipboardText_f == default || SDL_free_f == default) { throw new PlatformNotSupportedException(); } - + var textBytes = SDL_GetClipboardText_f(); var endTextBytes = textBytes; while (*endTextBytes != default) @@ -62,11 +64,11 @@ public static unsafe string SDL_GetClipboardText() SDL_free(textBytes); return text; } - + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int SDL_SetClipboardText_d(byte* text); - private static SDL_SetClipboardText_d SDL_SetClipboardText_f = + private static SDL_SetClipboardText_d? SDL_SetClipboardText_f = Loader.Functions.LoadFunction(nameof(SDL_SetClipboardText)); public static unsafe bool SDL_SetClipboardText(string text) @@ -75,7 +77,7 @@ public static unsafe bool SDL_SetClipboardText(string text) { throw new PlatformNotSupportedException(); } - + fixed (byte* textBytes = Encoding.UTF8.GetBytes(text)) { return SDL_SetClipboardText_f(textBytes) == 0; @@ -83,5 +85,6 @@ public static unsafe bool SDL_SetClipboardText(string text) } public static bool IsClipboardSupported => SDL_GetClipboardText_f != default && - SDL_SetClipboardText_f != default && SDL_free != default; + SDL_SetClipboardText_f != default && + SDL_free_f != default; }