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

Description
Moves the current window back and forth between the leftmost monitor and the center monitor in your setup, scaling its size and position proportionally to fit the target monitor's work area.
The window's current monitor is detected from its center point. Windows on the rightmost monitor are left in place. Otherwise, if the window is on the leftmost monitor, it moves to the center monitor, and vice versa. If it's on any other monitor (not leftmost, center, or rightmost), it's treated as being on the leftmost one, so the first move sends it to the center monitor.
Position and size are rescaled to preserve the window's relative placement on the new monitor, then clamped so it stays fully within the target's work area. A 500ms debounce prevents the same window from being moved twice in quick succession if the function is triggered rapidly. The move itself is posted asynchronously via SetWindowPos so the function returns immediately without blocking on the window manager.
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.
// Windows on the rightmost monitor are left in place.
// 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();
		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;
		// Windows on the rightmost monitor stay where they are
		if (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;
		}
	}
}