void SetWindowSizeAndFitToScreen(wxTopLevelWindow* tlw, wxPoint pos, wxSize size, wxSize default_size) { if (tlw->IsMaximized()) return; // NOTE: Positions can be negative and still be valid. Coordinates are relative to the // primary monitor so if the primary monitor is in the middle then (-1000, 10) is a // valid position on the monitor to the left of the primary. (This does not apply to // sizes obviously) wxRect screen_geometry; wxRect window_geometry{pos, size}; if (wxDisplay::GetCount() > 1) screen_geometry = GetVirtualScreenGeometry(); else screen_geometry = wxDisplay(0).GetClientArea(); // Initialize the default size if it is wxDefaultSize or otherwise negative. default_size.DecTo(screen_geometry.GetSize()); default_size.IncTo(tlw->GetMinSize()); if (!default_size.IsFullySpecified()) default_size.SetDefaults(wxDisplay(0).GetClientArea().GetSize() / 2); // If the position we're given doesn't make sense then go with the current position. // (Assuming the window was created with wxDefaultPosition then this should be reasonable) if (pos.x - screen_geometry.GetLeft() < -1000 || pos.y - screen_geometry.GetTop() < -1000 || pos.x - screen_geometry.GetRight() > 1000 || pos.y - screen_geometry.GetBottom() > 1000) { window_geometry.SetPosition(tlw->GetPosition()); } // If the window is bigger than all monitors combined, or negative (uninitialized) then reset it. if (window_geometry.IsEmpty() || window_geometry.GetWidth() > screen_geometry.GetWidth() || window_geometry.GetHeight() > screen_geometry.GetHeight()) { window_geometry.SetSize(default_size); } // Check if the window entirely lives on a single monitor without spanning. // If the window does not span multiple screens then we should constrain it within that // single monitor instead of the entire virtual desktop space. // The benefit to doing this is that we can account for the OS X menu bar and Windows task // bar which are treated as invisible when only looking at the virtual desktop instead of // an individual screen. if (wxDisplay::GetCount() > 1) { // SPECIAL CASE: If the window is entirely outside the visible area of the desktop then we // put it back on the primary (zero) monitor. wxRect monitor_intersection{window_geometry}; int the_monitor = 0; if (!monitor_intersection.Intersect(screen_geometry).IsEmpty()) { std::array<int, 4> monitors{{wxDisplay::GetFromPoint(monitor_intersection.GetTopLeft()), wxDisplay::GetFromPoint(monitor_intersection.GetTopRight()), wxDisplay::GetFromPoint(monitor_intersection.GetBottomLeft()), wxDisplay::GetFromPoint(monitor_intersection.GetBottomRight())}}; the_monitor = wxNOT_FOUND; bool intersected = false; for (int one_monitor : monitors) { if (one_monitor == the_monitor || one_monitor == wxNOT_FOUND) continue; if (the_monitor != wxNOT_FOUND) { // The window is spanning multiple screens. the_monitor = wxNOT_FOUND; break; } the_monitor = one_monitor; intersected = true; } // If we get wxNOT_FOUND for all corners then there are holes in the virtual desktop and the // entire window is lost in one. (e.g. 3 monitors in an 'L', window in top-right) if (!intersected) the_monitor = 0; } if (the_monitor != wxNOT_FOUND) { // We'll only use the client area of this monitor if the window will actually fit. // (It may not fit if the window is spilling off the edge so it isn't entirely visible) wxRect client_area{wxDisplay(the_monitor).GetClientArea()}; if (client_area.GetWidth() >= window_geometry.GetWidth() && client_area.GetHeight() >= window_geometry.GetHeight()) { screen_geometry = client_area; } } } // The window SHOULD be small enough to fit on the screen, but it might be spilling off an edge // so we'll snap it to the nearest edge as necessary. if (!screen_geometry.Contains(window_geometry)) { // NOTE: The order is important here, if the window *is* too big to fit then it will snap to // the top-left corner. int spill_x = std::max(0, window_geometry.GetRight() - screen_geometry.GetRight()); int spill_y = std::max(0, window_geometry.GetBottom() - screen_geometry.GetBottom()); window_geometry.Offset(-spill_x, -spill_y); if (window_geometry.GetTop() < screen_geometry.GetTop()) window_geometry.SetTop(screen_geometry.GetTop()); if (window_geometry.GetLeft() < screen_geometry.GetLeft()) window_geometry.SetLeft(screen_geometry.GetLeft()); } tlw->SetSize(window_geometry, wxSIZE_ALLOW_MINUS_ONE); }