using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
// The 'windowHandle' parameter will contain the window handle for the:
// - Active window when run by hotkey
// - Window Location target when run by a Window Location rule
// - TitleBar Button owner when run by a TitleBar Button
// - Jump List owner when run from a Taskbar Jump List
// - Currently focused window if none of these match
public static class DisplayFusionFunction
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
const uint GW_HWNDNEXT = 2;
public static void Run(IntPtr windowHandle)
{
//the monitor ids that will contain the windows you want to swap
/////////////////////////////////////////////////////////////////////////
//to change the two monitors that this script uses, change these values//
/////////////////////////////////////////////////////////////////////////
uint firstMonitor = 1;
uint secondMonitor = 2;
//a collection to store our topmost windows
Dictionary<uint, IntPtr> topMostWindowOnMonitor = new Dictionary<uint, IntPtr>();
topMostWindowOnMonitor.Add(firstMonitor, IntPtr.Zero);
topMostWindowOnMonitor.Add(secondMonitor, IntPtr.Zero);
//store all visable windows in a HashSet for quick access
// Old version used dictionary with empty value, and meligned the lafck of HashSets //
HashSet<IntPtr> visableWindows = new HashSet<IntPtr>();
foreach (IntPtr window in BFS.Window.GetVisibleWindowHandles())
visableWindows.Add(window);
//enumerate through the monitors, starting with the focused window, and moving down
//only enumerate if we havn't found the windows yet
for (IntPtr window = BFS.Window.GetFocusedWindow(); (topMostWindowOnMonitor[firstMonitor] == IntPtr.Zero) || (topMostWindowOnMonitor[secondMonitor] == IntPtr.Zero); window = GetWindow(window, GW_HWNDNEXT))
{
//check to see if there are no windows left
if (window == IntPtr.Zero) break;
//if it isn't a visable window, continue
if (!visableWindows.Contains(window)) continue ;
//check if it's a displayfusion window. if so, skip it.
//this will avoid adding titlebar buttons and other things
if (BFS.Window.GetClass(window).StartsWith("DF", StringComparison.Ordinal)) continue ;
//get the monitor this window is in
uint monitor = BFS.Monitor.GetMonitorIDByWindow(window);
//if the monitor isn't in our collection, get the next window
if (!topMostWindowOnMonitor.ContainsKey(monitor)) continue ;
//if we already found a top window for this monitor, continue
if (topMostWindowOnMonitor[monitor] != IntPtr.Zero) continue ;
//set the top window for this monitor
topMostWindowOnMonitor[monitor] = window;
}
//if we didn't find two topmost windows, do nothing
if ((topMostWindowOnMonitor[firstMonitor] == IntPtr.Zero) || (topMostWindowOnMonitor[secondMonitor] == IntPtr.Zero)) return;
//swap the windows
BFS.Window.MoveToMonitor(firstMonitor, topMostWindowOnMonitor[secondMonitor]);
BFS.Window.MoveToMonitor(secondMonitor, topMostWindowOnMonitor[firstMonitor]);
}
}