diff options
Diffstat (limited to 'WarframeClock/OverlayWindowBase.cs')
-rw-r--r-- | WarframeClock/OverlayWindowBase.cs | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/WarframeClock/OverlayWindowBase.cs b/WarframeClock/OverlayWindowBase.cs new file mode 100644 index 0000000..87cea8a --- /dev/null +++ b/WarframeClock/OverlayWindowBase.cs @@ -0,0 +1,141 @@ +using System; +using System.Diagnostics; +using System.Windows; +using System.Windows.Interop; + +namespace WarframeClock +{ + public class OverlayWindowBase : Window + { + private IntPtr _windowHandle; + private bool _xTopmost; + private IntPtr _targetWindowHandle; + private Native.Rect _parentBounds; + + public OverlayWindowBase() + { + _xTopmost = false; + } + + protected bool AdjustOverlay() + { + if (_windowHandle == IntPtr.Zero) + _windowHandle = new WindowInteropHelper(this).EnsureHandle(); + + if (!GetTargetWindow(out var newBounds)) + { + if (IsVisible) + { + Logging("Hide overlay; target window disappeared"); + Hide(); + } + return false; + } + + // Set top-most flag if the target window is foreground. Move to + // behind the current foreground window otherwise. + var currentActiveWindow = Native.GetForegroundWindow(); + if (currentActiveWindow != IntPtr.Zero && + (!IsVisible || currentActiveWindow == _targetWindowHandle != _xTopmost)) + { + // Setting Topmost to false brings the overlay to just + // behind the other top-most window -- above the foreground + // window. This is not what we want to do here. + // So, let's use SetWindowPos directly instead. + if (currentActiveWindow == _targetWindowHandle) + { + Logging("Overlay is now top-most"); + _xTopmost = true; + } + else + { + Logging($"Overlay is now non-top-most, behind {currentActiveWindow}"); + _xTopmost = false; + } + + uint flags = + 0x0001 /* SWP_NOSIZE */ | + 0x0002 /* SWP_NOMOVE */ | + 0x0008 /* SWP_NOREDRAW */ | + 0x0010 /* SWP_NOACTIVATE */ | + 0x0200 /* SWP_NOOWNERZORDER */ | + 0x0400 /* SWP_NOSENDCHANGING */; + Native.SetWindowPos(_windowHandle, _xTopmost ? (IntPtr)(-1) : currentActiveWindow, 0, 0, 0, 0, flags); + } + + // Adjust window position + if (!IsVisible || + _parentBounds.Left != newBounds.Left || _parentBounds.Right != newBounds.Right || + _parentBounds.Top != newBounds.Top || _parentBounds.Bottom != newBounds.Bottom) + { + _parentBounds = newBounds; + + var width = _parentBounds.Right - _parentBounds.Left; + var height = _parentBounds.Bottom - _parentBounds.Top; + + // Do not use window.Left (and so on) because they're DPI-aware. + // We don't want that.... + Logging($"Move overlay to: l={_parentBounds.Left};t={_parentBounds.Top};w={width};h={height}"); + Native.SetWindowPos(_windowHandle, IntPtr.Zero, _parentBounds.Left, _parentBounds.Top, width, height, + 0x0004 /* SWP_NOZORDER */); + } + if (!IsVisible) + { + Logging("Show overlay"); + Show(); + } + + return true; + } + + private bool GetTargetWindow(out Native.Rect bounds) + { + if (_targetWindowHandle == IntPtr.Zero) + { + foreach (var process in Process.GetProcesses()) + { + if (_targetWindowHandle == IntPtr.Zero && + (process.ProcessName == "Warframe" || process.ProcessName == "Warframe.x64")) + { + try + { + _targetWindowHandle = process.MainWindowHandle; + if (_targetWindowHandle != IntPtr.Zero) + { + Logging($"Found a process with name={process.ProcessName}; " + + $"MainWindowHandle={_targetWindowHandle}"); + } + } + catch (Exception) + { + // Ignore errors; maybe the process is just exiting. Let's retry during the next cycle. + } + } + + process.Dispose(); + } + } + + if (_targetWindowHandle == IntPtr.Zero) + { + // Suppress compile error; caller must not use the value + bounds = new Native.Rect(); + return false; + } + + if (!Native.GetWindowRect(_targetWindowHandle, out bounds)) + { + Logging("GetWindowRect failed; aborting this cycle"); + _targetWindowHandle = IntPtr.Zero; + return false; + } + + return true; + } + + private static void Logging(string message) + { + Console.WriteLine($"OverlayWindowBase: {message}"); + } + } +} |