Processing Ajax...

Title

Message

Confirm

Confirm

Confirm

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure?
Save up to 50% on our desktop apps during our big Summer Sale!Save up to 50% on our desktop apps during our big Summer Sale, including DisplayFusion, ClipboardFusion, FileSeek, LogFusion, TrayStatus, and VoiceBot!Save up to 50% on our desktop apps during our big Summer Sale!

Toggle Window Between Leftmost and Center Monitor v2

Description
Toggles the focused window between the leftmost and center monitor,
scaling size and position to fit the target monitor's work area.
With three or more monitors, windows on the rightmost monitor are left in place.
With exactly two monitors, toggles between the left and right monitor.
Generated with Anthropic Fable 5.
Language
C#.net
Minimum Version
Created By
Yirg
Contributors
-
Date Created
3d ago
Date Last Modified
3d ago

Scripted Function (Macro) Code

// DisplayFusion Scripted Function
// Toggles the focused window between the leftmost and center monitor,
// scaling size and position to fit the target monitor's work area.
// With three or more monitors, windows on the rightmost monitor are left in place.
// With exactly two monitors, toggles between the left and right monitor.
// Generated with Anthropic Fable 5.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
public static class DisplayFusionFunction
{
	[DllImport("user32.dll")]
	private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
		int X, int Y, int cx, int cy, uint uFlags);
	private const uint SWP_NOZORDER = 0x0004;
	private const uint SWP_NOACTIVATE = 0x0010;
	private const uint SWP_ASYNCWINDOWPOS = 0x4000;
	// In-memory lock state, persists between runs while DisplayFusion
	// keeps the compiled function loaded. No disk I/O.
	private static readonly object SyncRoot = new object();
	private static readonly Dictionary<IntPtr, long> LastMoveTicks = new Dictionary<IntPtr, long>();
	public static void Run(IntPtr windowHandle)
	{
		if (windowHandle == IntPtr.Zero)
			return;
		// Reject re-triggers arriving within this window
		int quietPeriodMs = 500;
		lock (SyncRoot)
		{
			long lastTicks;
			if (LastMoveTicks.TryGetValue(windowHandle, out lastTicks))
			{
				double elapsedMs = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - lastTicks).TotalMilliseconds;
				if (elapsedMs >= 0 && elapsedMs < quietPeriodMs)
					return;
			}
			LastMoveTicks[windowHandle] = DateTime.UtcNow.Ticks;
		}
		// Sort monitors left to right by X position
		Rectangle[] monitors = BFS.Monitor.GetMonitorWorkAreas()
			.OrderBy(m => m.X)
			.ToArray();
		// Nothing to toggle between on a single monitor
		if (monitors.Length < 2)
			return;
		int leftmostIndex = 0;
		int centerIndex = monitors.Length / 2;
		int rightmostIndex = monitors.Length - 1;
		Rectangle window = BFS.Window.GetBounds(windowHandle);
		Point windowCenter = new Point(
			window.X + (window.Width / 2),
			window.Y + (window.Height / 2));
		int currentIndex = -1;
		for (int i = 0; i < monitors.Length; i++)
		{
			if (monitors[i].Contains(windowCenter))
			{
				currentIndex = i;
				break;
			}
		}
		if (currentIndex == -1)
			currentIndex = leftmostIndex;
		// With three or more monitors, windows on the rightmost monitor stay where they are.
		// With exactly two monitors, the right monitor is the toggle partner, so no guard.
		if (monitors.Length > 2 && currentIndex == rightmostIndex)
			return;
		int targetIndex = (currentIndex == leftmostIndex) ? centerIndex : leftmostIndex;
		if (targetIndex == currentIndex)
			return;
		Rectangle current = monitors[currentIndex];
		Rectangle target = monitors[targetIndex];
		double scaleX = (double)target.Width / current.Width;
		double scaleY = (double)target.Height / current.Height;
		int windowX = target.X + (int)Math.Round((window.X - current.X) * scaleX);
		int windowY = target.Y + (int)Math.Round((window.Y - current.Y) * scaleY);
		int windowW = (int)Math.Round(window.Width * scaleX);
		int windowH = (int)Math.Round(window.Height * scaleY);
		if (windowW > target.Width)
			windowW = target.Width;
		if (windowH > target.Height)
			windowH = target.Height;
		if (windowX + windowW > target.Right)
			windowX = target.Right - windowW;
		if (windowY + windowH > target.Bottom)
			windowY = target.Bottom - windowH;
		if (windowX < target.X)
			windowX = target.X;
		if (windowY < target.Y)
			windowY = target.Y;
		// Async move: posts the request and returns immediately
		SetWindowPos(windowHandle, IntPtr.Zero, windowX, windowY, windowW, windowH,
			SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
		lock (SyncRoot)
		{
			LastMoveTicks[windowHandle] = DateTime.UtcNow.Ticks;
		}
	}
}