using System; using System.Linq; using UnityEditor; using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; using FullscreenEditor.Windows; namespace FullscreenEditor { /// Helper for getting fullscreen rectangles. public static class FullscreenRects { /// Represents a callback for user defined fullscreen rect calculation. /// The mode set in /// A rect calculated based on custom logic. /// Whether the rect calculated should be used or not. public delegate bool FullscreenRectCallback(RectSourceMode mode, out Rect rect); /// The number of monitors attached to this machine, returns -1 if the platform is not supported. public static int ScreenCount { get { if (!FullscreenUtility.IsWindows) return -1; const int SM_CMONITORS = 80; return User32.GetSystemMetrics(SM_CMONITORS); } } /// Custom callback to allow the user to specify their own logic to how fullscreens will be arranged. /// Check the documentation for usage examples. public static FullscreenRectCallback CustomRectCallback { get; set; } /// Returns a fullscreen rect /// The mode that will be used to retrieve the rect. /// The window that will be set fullscreen. public static Rect GetFullscreenRect(RectSourceMode mode, ScriptableObject targetWindow = null) { if (targetWindow != null && !targetWindow.IsOfType(typeof(EditorWindow)) && !targetWindow.IsOfType(Types.View)) { throw new ArgumentException("Target window must be of type EditorWindow or View or null", "targetWindow"); } if (CustomRectCallback != null) { var rect = new Rect(); var shouldUse = CustomRectCallback(mode, out rect); if (shouldUse) return rect; } switch (mode) { case RectSourceMode.MainDisplay: return GetMainDisplayRect(); case RectSourceMode.WindowDisplay: if (targetWindow == null || !FullscreenUtility.IsWindows) return GetMainDisplayRect(); var views = new ViewPyramid(targetWindow); var rect = views.Container.GetPropertyValue("position"); return GetDisplayBoundsAtPoint(rect.center); case RectSourceMode.AtMousePosition: return FullscreenUtility.IsWindows ? GetDisplayBoundsAtPoint(FullscreenUtility.MousePosition) : GetWorkAreaRect(true); case RectSourceMode.Span: return FullscreenUtility.IsWindows ? GetVirtualScreenBounds() : GetWorkAreaRect(true); case RectSourceMode.Custom: return GetCustomUserRect(); case RectSourceMode.Display1: return GetMonitorRect(0); case RectSourceMode.Display2: return GetMonitorRect(1); case RectSourceMode.Display3: return GetMonitorRect(2); case RectSourceMode.Display4: return GetMonitorRect(3); case RectSourceMode.Display5: return GetMonitorRect(4); case RectSourceMode.Display6: return GetMonitorRect(5); case RectSourceMode.Display7: return GetMonitorRect(6); case RectSourceMode.Display8: return GetMonitorRect(7); default: Logger.Warning("Invalid fullscreen mode, please fix this by changing the placement source mode in preferences."); return new Rect(Vector2.zero, Vector2.one * 300f); } } /// Returns a rect with the dimensions of the main screen. /// (Note that the position may not be right for multiple screen setups) public static Rect GetMainDisplayRect() { if (FullscreenUtility.IsWindows) { var mainDisplay = DisplayInfo .GetDisplays() .FirstOrDefault(d => d.PrimaryDisplay); if (mainDisplay != null) return mainDisplay.UnityCorrectedArea; Logger.Error("No main display??? This should not happen, falling back to Screen.currentResolution"); } // Screen.currentResolution returns the resolution of the screen where // the currently focused window is located, not the main display resolution. // This caused the bug #53 on windows. // The same behaviour was not tested on Linux as macOS return new Rect(0f, 0f, Screen.currentResolution.width, Screen.currentResolution.height); } /// Returns the rect of a given display index. public static Rect GetMonitorRect(int index) { if (!FullscreenUtility.IsWindows) return GetMainDisplayRect(); var d = DisplayInfo.GetDisplay(index); if (d == null) { Logger.Error("Display {0} not connected", index + 1); return GetMainDisplayRect(); } return d.UnityCorrectedArea; } /// Returns a rect defined by the user in the preferences. public static Rect GetCustomUserRect() { return FullscreenPreferences.CustomRect; } /// Returns a rect covering all the screen, except for the taskbar/dock. /// On Windows it adds a 4px border and does not account for scaling (can cause bugs when using scales different than 100%). /// On macOS this returns a fullscreen rect when the main window is maximized and mouseScreen is set to true. /// Should we get the rect on the screen where the mouse pointer is? public static Rect GetWorkAreaRect(bool mouseScreen) { return Types.ContainerWindow.InvokeMethod("FitRectToScreen", new Rect(Vector2.zero, Vector2.one * 10000f), true, mouseScreen); } /// Returns a rect covering all the screen, except for the taskbar/dock. /// On Windows it adds a 4px border and does not account for scaling (can cause bugs when using scales different than 100%). /// On macOS this returns a fullscreen rect when the main window is maximized and mouseScreen is set to true. /// The ContainerWindow that will be used as reference for calulating border error. /// Should we get the rect on the screen where the mouse pointer is? public static Rect GetWorkAreaRect(Object container, bool mouseScreen) { return container.InvokeMethod("FitWindowRectToScreen", new Rect(Vector2.zero, Vector2.one * 10000f), true, mouseScreen); } /// Returns the bounds rect of the screen that contains the given point. (Windows only) /// The point relative to public static Rect GetDisplayBoundsAtPoint(Vector2 point) { return InternalEditorUtility.GetBoundsOfDesktopAtPoint(point); } /// Full virtual screen bounds, spanning across all monitors. (Windows only) public static Rect GetVirtualScreenBounds() { if (!FullscreenUtility.IsWindows) throw new NotImplementedException(); const int SM_XVIRTUALSCREEN = 76; const int SM_YVIRTUALSCREEN = 77; const int SM_CXVIRTUALSCREEN = 78; const int SM_CYVIRTUALSCREEN = 79; var x = User32.GetSystemMetrics(SM_XVIRTUALSCREEN); var y = User32.GetSystemMetrics(SM_YVIRTUALSCREEN); var width = User32.GetSystemMetrics(SM_CXVIRTUALSCREEN); var height = User32.GetSystemMetrics(SM_CYVIRTUALSCREEN); var rect = new Rect { yMin = y, xMin = x, width = width, height = height, }; return FullscreenUtility.DpiCorrectedArea(rect); } } }