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?

Snap Last Two Windows Side by Side (Commander-style)

Description
Splits the two most recently focused resizable windows into left/right halves, keeping each on its current side. Skips dialogs and compensates for invisible borders so edges sit flush.
Language
C#.net
Minimum Version
Created By
Yirg
Contributors
-
Date Created
13d ago
Date Last Modified
13d ago

Scripted Function (Macro) Code

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;

// DisplayFusion Scripted Function
// Splits the two most recently focused "real" windows across the current monitor:
// - Most recently focused window -> RIGHT half
// - Previously focused window    -> LEFT half
// Only considers windows that can be maximized/restored (WS_MAXIMIZEBOX).
// Dialogs and tool windows are ignored.

public static class DisplayFusionFunction
{
    [DllImport("user32.dll")]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("dwmapi.dll")]
    private static extern int DwmGetWindowAttribute(IntPtr hWnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    private const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;

    private const int GWL_STYLE = -16;
    private const int GWL_EXSTYLE = -20;

    private const int WS_MAXIMIZEBOX = 0x00010000;
    private const int WS_CAPTION     = 0x00C00000;
    private const int WS_EX_TOOLWINDOW = 0x00000080;
    private const int WS_EX_DLGMODALFRAME = 0x00000001;

    public static void Run(IntPtr windowHandle)
    {
        // Handles are returned in Z-order: topmost (last focused) first
        IntPtr[] handles = BFS.Window.GetVisibleWindowHandles();

        List<IntPtr> candidates = new List<IntPtr>();
        foreach (IntPtr h in handles)
        {
            if (IsEligible(h))
            {
                candidates.Add(h);
                if (candidates.Count == 2)
                    break;
            }
        }

        if (candidates.Count < 2)
        {
            BFS.Dialog.ShowMessageInfo("Couldn't find two eligible windows to split.");
            return;
        }

        IntPtr lastFocused = candidates[0];
        IntPtr previous    = candidates[1];

        // Decide which window goes where based on their current horizontal
        // centers. Only when the two centers are identical do we fall back to
        // focus order (previous -> left, last focused -> right).
        IntPtr leftWindow;
        IntPtr rightWindow;

        int lastCenter = GetHorizontalCenter(lastFocused);
        int prevCenter = GetHorizontalCenter(previous);

        if (lastCenter < prevCenter)
        {
            leftWindow  = lastFocused;
            rightWindow = previous;
        }
        else if (lastCenter > prevCenter)
        {
            leftWindow  = previous;
            rightWindow = lastFocused;
        }
        else
        {
            leftWindow  = previous;
            rightWindow = lastFocused;
        }

        // Use the monitor of the most recently focused window
        Rectangle monitor = BFS.Monitor.GetMonitorWorkAreaByWindow(lastFocused);

        int halfWidth = monitor.Width / 2;

        Rectangle left  = new Rectangle(monitor.X, monitor.Y, halfWidth, monitor.Height);
        Rectangle right = new Rectangle(monitor.X + halfWidth, monitor.Y, monitor.Width - halfWidth, monitor.Height);

        PlaceWindow(leftWindow, left);
        PlaceWindow(rightWindow, right);

        // Bring both to front, last focused on top
        BFS.Window.Focus(previous);
        BFS.Window.Focus(lastFocused);
    }

    // Horizontal center of the window's visible frame, falling back to the
    // standard window rect if the DWM frame isn't available.
    private static int GetHorizontalCenter(IntPtr h)
    {
        RECT frameRect = new RECT();
        if (DwmGetWindowAttribute(h, DWMWA_EXTENDED_FRAME_BOUNDS, out frameRect, Marshal.SizeOf(typeof(RECT))) == 0)
            return frameRect.Left + ((frameRect.Right - frameRect.Left) / 2);

        RECT windowRect = new RECT();
        if (GetWindowRect(h, out windowRect))
            return windowRect.Left + ((windowRect.Right - windowRect.Left) / 2);

        return 0;
    }

    private static bool IsEligible(IntPtr h)
    {
        // Skip windows without a title (often background/system windows)
        string title = BFS.Window.GetText(h);
        if (string.IsNullOrEmpty(title))
            return false;

        int style = GetWindowLong(h, GWL_STYLE);
        int exStyle = GetWindowLong(h, GWL_EXSTYLE);

        // Must have a maximize/restore box
        if ((style & WS_MAXIMIZEBOX) == 0)
            return false;

        // Must be a normal captioned window
        if ((style & WS_CAPTION) != WS_CAPTION)
            return false;

        // Skip tool windows and dialog-framed windows
        if ((exStyle & WS_EX_TOOLWINDOW) != 0)
            return false;
        if ((exStyle & WS_EX_DLGMODALFRAME) != 0)
            return false;

        return true;
    }

    private static void PlaceWindow(IntPtr h, Rectangle bounds)
    {
        // Restore first so the size/position actually applies
        if (BFS.Window.IsMaximized(h) || BFS.Window.IsMinimized(h))
            BFS.Window.Restore(h);

        // Compensate for the invisible resize borders (DWM extended frame).
        // The visible frame (extended frame bounds) is smaller than the
        // window rect, so we expand the target rect by the difference
        // on each side to make the visible edges sit flush.
        RECT windowRect = new RECT();
        RECT frameRect = new RECT();

        bool haveRects = false;
        if (GetWindowRect(h, out windowRect))
        {
            if (DwmGetWindowAttribute(h, DWMWA_EXTENDED_FRAME_BOUNDS, out frameRect, Marshal.SizeOf(typeof(RECT))) == 0)
                haveRects = true;
        }

        int leftOffset = 0, topOffset = 0, rightOffset = 0, bottomOffset = 0;
        if (haveRects)
        {
            leftOffset   = frameRect.Left   - windowRect.Left;    // usually positive
            topOffset    = frameRect.Top    - windowRect.Top;     // usually 0
            rightOffset  = windowRect.Right - frameRect.Right;    // usually positive
            bottomOffset = windowRect.Bottom - frameRect.Bottom;  // usually positive
        }

        BFS.Window.SetSizeAndLocation(
            h,
            bounds.X - leftOffset,
            bounds.Y - topOffset,
            bounds.Width + leftOffset + rightOffset,
            bounds.Height + topOffset + bottomOffset);
    }
}