Skip to content

Commit e1aecfe

Browse files
Ryanmello07claude
andcommitted
app: clamp the flyout position to the monitor it is anchored on
The window's bottom-right was placed at the tray anchor with no bounds check, so it landed at (-1136,-875) on a two-monitor desktop -- entirely off both screens, while the tray still reported the app as open and the only way back was Task Manager. Any anchor near a top or left edge does it: the taskbar can be moved, the icon may live in the overflow flyout, a secondary monitor can sit at negative coordinates, and the window can be taller than the screen it is anchored on. Clamp into the work area of the monitor under the anchor, preferring the TOP-LEFT to stay visible when the window is larger than that area, and log the anchor/size/result so an off-screen placement is diagnosable from the log instead of from a missing window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 0fb4402 commit e1aecfe

1 file changed

Lines changed: 31 additions & 2 deletions

File tree

app/src/App/AppController.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "AppController.h"
55

6+
#include <algorithm>
67
#include <string_view>
78

89
#include <winrt/Microsoft.UI.Windowing.h>
@@ -259,8 +260,36 @@ void AppController::ShowWindowImpl(const POINT* anchor) {
259260
auto appWindow = winrt::Microsoft::UI::Windowing::AppWindow::GetFromWindowId(windowId);
260261
auto size = appWindow.Size();
261262
// place the window's bottom-right near the tray icon (bottom-right corner)
262-
winrt::Windows::Graphics::PointInt32 pos{anchor->x - size.Width,
263-
anchor->y - size.Height};
263+
int x = anchor->x - size.Width;
264+
int y = anchor->y - size.Height;
265+
266+
// ...then clamp into the WORK AREA of the monitor the anchor is on, or
267+
// the window lands where nobody can see it. Unclamped, this put the
268+
// window at (-1136,-875) on a two-monitor desktop -- entirely off both
269+
// screens, with the tray still saying the app was open. Every anchor
270+
// near a top or left edge does it: the taskbar is not always bottom
271+
// right (it can be moved, and the icon may live in the overflow flyout),
272+
// a secondary monitor can sit at negative coordinates, and the window
273+
// can be taller than the screen it is anchored on. MONITOR_DEFAULTTONEAREST
274+
// keeps a bogus anchor on a real monitor rather than failing.
275+
POINT anchorPt{anchor->x, anchor->y};
276+
HMONITOR mon = ::MonitorFromPoint(anchorPt, MONITOR_DEFAULTTONEAREST);
277+
MONITORINFO mi{};
278+
mi.cbSize = sizeof(mi);
279+
if (mon && ::GetMonitorInfoW(mon, &mi)) {
280+
const RECT& work = mi.rcWork;
281+
// max() after min() so a window larger than the work area still has
282+
// its TOP-LEFT on screen (the title bar and close button) rather than
283+
// its bottom-right
284+
x = (std::max)(static_cast<long>(work.left),
285+
(std::min)(x, work.right - size.Width));
286+
y = (std::max)(static_cast<long>(work.top),
287+
(std::min)(y, work.bottom - size.Height));
288+
}
289+
290+
winrt::Windows::Graphics::PointInt32 pos{x, y};
291+
LogInfo("app: window anchor ({},{}) size {}x{} -> position ({},{})",
292+
anchor->x, anchor->y, size.Width, size.Height, pos.X, pos.Y);
264293
appWindow.Move(pos);
265294
}
266295
}

0 commit comments

Comments
 (0)