package main // Placing a window on a set of monitors — the arithmetic, with no Win32 in it. // // Kept apart from the platform code so it can be tested: the fault it guards // against (a window that opens where nobody can see it) is reported as "OpsLog // does not start", is invisible by definition, and cannot be reproduced without // the reporter's screen layout. A table test can hold that layout. // screenRect is one monitor's work area, in virtual-desktop coordinates. type screenRect struct{ X, Y, W, H int } // screenRectOf is the same shape under the name the helpers below read with. type screenRectOf = screenRect // onAnyScreen reports whether a window would land where it can be seen and // grabbed on ONE of the screens. // // One of them, not their bounding box: monitors rarely tile the box they span, // and the leftover rectangles belong to no screen at all. A window in one of // those holes passes a bounding-box test and is invisible. func onAnyScreen(x, y, w, h int, screens []screenRectOf) bool { for _, r := range screens { if overlapsEnough(x, y, w, h, r.X, r.Y, r.W, r.H) { return true } } return false } // nearestScreen picks the screen whose centre is closest to the window's. func nearestScreen(x, y, w, h int, screens []screenRectOf) (screenRectOf, bool) { if len(screens) == 0 { return screenRectOf{}, false } best, bestDist := screens[0], int64(1)<<62 cx, cy := x+w/2, y+h/2 for _, r := range screens { rcx, rcy := r.X+r.W/2, r.Y+r.H/2 dx, dy := int64(cx-rcx), int64(cy-rcy) if d := dx*dx + dy*dy; d < bestDist { best, bestDist = r, d } } return best, true } // clampRectToScreens moves a window onto the nearest screen, keeping its size // where the screen can hold it. Returns the new position and whether it moved. func clampRectToScreens(x, y, w, h int, screens []screenRectOf) (int, int, bool) { best, ok := nearestScreen(x, y, w, h, screens) if !ok { return x, y, false } if w > best.W { w = best.W } if h > best.H { h = best.H } nx, ny := x, y if nx < best.X { nx = best.X } if ny < best.Y { ny = best.Y } if nx+w > best.X+best.W { nx = best.X + best.W - w } if ny+h > best.Y+best.H { ny = best.Y + best.H - h } return nx, ny, nx != x || ny != y }