using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
// 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)]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
//some constants
const uint GW_HWNDNEXT = 2;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOACTIVATE = 0x0010;
private const int SWP_NOSENDCHANGING = 0x0400;
public static void Run(IntPtr windowHandle)
{
// Get the saved window info
Dictionary<IntPtr, WindowInfo> savedWindowInfo = new Dictionary<IntPtr, WindowInfo>();
foreach(WindowInfo info in System.Text.Json.JsonSerializer.Deserialize<List<WindowInfo>>(BFS.ScriptSettings.ReadValue("WindowInfoList")))
{
if(savedWindowInfo.ContainsKey(info.HandleAsPtr()))
continue;
savedWindowInfo.Add(info.HandleAsPtr(), info);
}
// A list to store the windows
List<IntPtr> windows = new List<IntPtr>();
// Enumerate through the monitors, starting with the focused window, and moving down
for(IntPtr window = BFS.Window.GetFocusedWindow(); ; window = GetWindow(window, GW_HWNDNEXT))
{
// Check to see if there are any windows left
if(window == IntPtr.Zero)
break;
// we don't care about windows we have no info about
if(!savedWindowInfo.ContainsKey(window))
continue;
// Store the window with its info
windows.Add(window);
}
// Bubble sort!
bool swapped;
for(int i = 0; i < windows.Count - 1; i++)
{
swapped = false;
for(int j = 0; j < windows.Count - i - 1; j++)
{
WindowInfo a = savedWindowInfo[windows[j]];
WindowInfo b = savedWindowInfo[windows[j+1]];
if(a.ZOrder <= b.ZOrder)
continue;
swapped = true;
SwapWindowZOrder(a.HandleAsPtr(), b.HandleAsPtr());
windows[j] = b.HandleAsPtr();
windows[j+1] = a.HandleAsPtr();
}
if(!swapped)
break;
}
// Restore state and positions
foreach(IntPtr window in windows)
{
WindowInfo saved = savedWindowInfo[window];
WindowInfo current = new WindowInfo(window, 0); // we dont care about the zorder here
if(saved.State != current.State)
{
if(saved.State == FormWindowState.Normal)
BFS.Window.Restore(window);
if(saved.State == FormWindowState.Minimized)
BFS.Window.Minimize(window);
if(saved.State == FormWindowState.Maximized)
BFS.Window.Maximize(window);
}
if(saved.Bounds != current.Bounds)
BFS.Window.SetSizeAndLocation(window, saved.Bounds.X, saved.Bounds.Y, saved.Bounds.Width, saved.Bounds.Height);
}
}
// A method to swap two window z orders
private static void SwapWindowZOrder(IntPtr a, IntPtr b)
{
SetWindowPos(a, b, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
SetWindowPos(b, a, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
}
private static bool IsDisplayFusionWindowOrHiddenExplorerWindow(IntPtr window)
{
// Ignore any DisplayFusion windows (title bar buttons, etc.)
// Ignore pesky hidden explorer.exe windows
string windowClass = BFS.Window.GetClass(window);
if((windowClass.StartsWith("DF", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("EdgeUiInputTopWndClass", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("EdgeUiInputWndClass", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("NativeHWNDHost", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ModeInputWnd", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("MetroGhostWindow", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ImmersiveLauncher", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ApplicationManager_ImmersiveShellWindow", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("Shell_TrayWnd", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("WorkerW", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("Progman", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("SearchPane", StringComparison.OrdinalIgnoreCase)))
{
return true;
}
return false;
}
public class WindowInfo
{
public long Handle { get; set; }
public FormWindowState State { get; set; }
public Rectangle Bounds { get; set; }
public int ZOrder { get; set; }
// for json deseriealization
public WindowInfo(){}
public WindowInfo(IntPtr handle, int zOrder)
{
this.Handle = handle.ToInt64();
if(BFS.Window.IsMinimized(handle))
this.State = FormWindowState.Minimized;
else if(BFS.Window.IsMaximized(handle))
this.State = FormWindowState.Maximized;
else
this.State = FormWindowState.Normal;
this.Bounds = BFS.Window.GetBounds(handle);
this.ZOrder = zOrder;
}
public IntPtr HandleAsPtr()
{
return new IntPtr(this.Handle);
}
}
}