Skip to content

Commit 28bf94a

Browse files
committed
Fix window positioning and maximization logic
The code to restore the window position and size from saved data did not handle the case of being maximized on a non-primary monitor, nor did it adjust the window position when the stored location was completely outside of all active monitors. This change addresses both these problems and removes some vestigal code around display affinity and always-on-top logic which we don't use.
1 parent 166d251 commit 28bf94a

3 files changed

Lines changed: 76 additions & 62 deletions

File tree

engine/core/core_video.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class core_video_c: public core_IVideo, public conCmdHandler_c {
4646
sys_IMain* sys;
4747

4848
conVar_c* vid_mode;
49-
conVar_c* vid_display;
5049
conVar_c* vid_fullscreen;
5150
conVar_c* vid_resizable;
5251
conVar_c* vid_last;
@@ -69,7 +68,6 @@ core_video_c::core_video_c(sys_IMain* sysHnd)
6968
: conCmdHandler_c(sysHnd->con), sys(sysHnd)
7069
{
7170
vid_mode = sys->con->Cvar_Add("vid_mode", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFMODE, -1, VID_NUMMODES-1);
72-
vid_display = sys->con->Cvar_Add("vid_display", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFDISPLAY, -1, 15);
7371
vid_fullscreen = sys->con->Cvar_Add("vid_fullscreen", CV_ARCHIVE, CFG_VID_DEFFULLSCREEN);
7472
vid_resizable = sys->con->Cvar_Add("vid_resizable", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFRESIZABLE, 0, 3);
7573
vid_last = sys->con->Cvar_Add("vid_last", CV_ARCHIVE, "");
@@ -100,15 +98,13 @@ void core_video_c::Apply(bool shown)
10098
}
10199
}
102100
}
103-
set.display = vid_display->intVal;
104101
if (vid_mode->intVal >= 0) {
105102
set.mode[0] = (std::max)(vid_modeList[vid_mode->intVal][0], CFG_VID_MINWIDTH);
106103
set.mode[1] = (std::max)(vid_modeList[vid_mode->intVal][1], CFG_VID_MINHEIGHT);
107104
} else {
108105
set.mode[0] = 0;
109106
set.mode[1] = 0;
110107
}
111-
set.depth = 0;
112108
set.minSize[0] = CFG_VID_MINWIDTH;
113109
set.minSize[1] = CFG_VID_MINHEIGHT;
114110
sys->video->Apply(&set);

engine/system/sys_video.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
// Video settings flags
1212
enum vidFlags_e {
13-
VID_TOPMOST = 0x02,
1413
VID_RESIZABLE = 0x04,
1514
VID_MAXIMIZE = 0x08,
1615
VID_USESAVED = 0x10,
@@ -29,9 +28,7 @@ struct sys_vidSave_s {
2928
struct sys_vidSet_s {
3029
bool shown = false; // Show window?
3130
int flags = 0; // Flags
32-
int display = 0; // Display number
33-
int mode[2] = {}; // Resolution or window size
34-
int depth = 0; // Bit depth
31+
int mode[2] = {}; // Window size
3532
int minSize[2] = {}; // Minimum size for resizable windows
3633
sys_vidSave_s save; // Saved state
3734
};

engine/system/win/sys_video.cpp

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -296,109 +296,114 @@ int sys_video_c::Apply(sys_vidSet_s* set)
296296
}
297297
priMon = 0;
298298

299+
struct WindowRect {
300+
int left, top;
301+
int right, bottom;
302+
};
303+
299304
// Determine which monitor to create window on
300-
if (cur.display >= numMon) {
301-
sys->con->Warning("display #%d doesn't exist (max display number is %d)", cur.display, numMon - 1);
302-
cur.display = 0;
303-
}
304-
else if (cur.display < 0) {
305-
// Use monitor containing the mouse cursor if available, otherwise primary monitor
306-
cur.display = 0;
307-
if (auto curPos = PlatformGetCursorPos()) {
308-
auto [curX, curY] = *curPos;
309-
for (int m = 0; m < numMon; ++m) {
310-
int right = mon[m].left + mon[m].width;
311-
int bottom = mon[m].top + mon[m].height;
312-
if (curX >= mon[m].left && curY >= mon[m].top && curX < right && curY < bottom) {
313-
cur.display = m;
314-
break;
315-
}
305+
// Use monitor containing the mouse cursor if available, otherwise primary monitor
306+
int display = 0;
307+
if (auto curPos = PlatformGetCursorPos()) {
308+
auto [curX, curY] = *curPos;
309+
for (int m = 0; m < numMon; ++m) {
310+
int right = mon[m].left + mon[m].width;
311+
int bottom = mon[m].top + mon[m].height;
312+
if (curX >= mon[m].left && curY >= mon[m].top && curX < right && curY < bottom) {
313+
display = m;
314+
break;
316315
}
317316
}
318317
}
319-
defRes[0] = mon[cur.display].width;
320-
defRes[1] = mon[cur.display].height;
318+
defRes[0] = mon[display].width;
319+
defRes[1] = mon[display].height;
321320

322321
minSize[0] = minSize[1] = 0;
323322

324-
if (sys->debuggerRunning) {
325-
// Force topmost off if debugger is attached
326-
cur.flags &= ~VID_TOPMOST;
327-
}
328323
if (cur.mode[0] == 0) {
329324
// Use default resolution if one isn't specified
330325
Vector2Copy(defRes, cur.mode);
331326
}
332327
Vector2Copy(cur.mode, vid.size);
333328
Vector2Copy(defRes, scrSize);
334329

335-
struct WindowRect {
336-
int left, top;
337-
int right, bottom;
338-
};
339-
340330
// Get window rectangle
341-
WindowRect wrec;
331+
WindowRect wrec{};
332+
std::optional<int> intersectedMonitor;
342333
if (cur.flags & VID_USESAVED) {
343-
// TODO(LV): Move offscreen windows to a monitor.
344-
wrec.left = cur.save.pos[0];
345-
wrec.top = cur.save.pos[1];
346334
if (cur.save.maximised) {
347335
cur.flags |= VID_MAXIMIZE;
348336
}
349337
else {
350338
cur.mode[0] = cur.save.size[0];
351339
cur.mode[1] = cur.save.size[1];
352340
}
341+
342+
wrec.left = cur.save.pos[0];
343+
wrec.top = cur.save.pos[1];
344+
wrec.right = wrec.left + cur.mode[0];
345+
wrec.bottom = wrec.top + cur.mode[1];
346+
347+
for (int m = 0; m < numMon; ++m) {
348+
WindowRect drec{ mon[m].left, mon[m].top };
349+
drec.right = drec.left + mon[m].width;
350+
drec.bottom = drec.top + mon[m].height;
351+
352+
// A.lo < B.hi && A.hi > B.lo (half-open rects)
353+
bool intersectsDisplay = drec.left < wrec.right && drec.top < wrec.bottom && drec.right > wrec.left && drec.bottom > wrec.top;
354+
if (!intersectedMonitor && intersectsDisplay) {
355+
intersectedMonitor = m;
356+
break;
357+
}
358+
}
353359
}
354-
else {
355-
wrec.left = (scrSize[0] - cur.mode[0]) / 2 + mon[cur.display].left;
356-
wrec.top = (scrSize[1] - cur.mode[1]) / 2 + mon[cur.display].top;
360+
361+
if (!intersectedMonitor) {
362+
wrec.left = (scrSize[0] - cur.mode[0]) / 2 + mon[display].left;
363+
wrec.top = (scrSize[1] - cur.mode[1]) / 2 + mon[display].top;
357364
}
358365
vid.pos[0] = wrec.left;
359366
vid.pos[1] = wrec.top;
360-
wrec.right = wrec.left + cur.mode[0];
361-
wrec.bottom = wrec.top + cur.mode[1];
362-
// TODO(LV): Verify that stored coordinates are aligned right.
363367

364368
if (initialised) {
365-
glfwSetWindowSize(wnd, cur.mode[0], cur.mode[1]);
369+
if (!!glfwGetWindowAttrib(wnd, GLFW_MAXIMIZED)) {
370+
glfwRestoreWindow(wnd);
371+
}
372+
glfwSetWindowPos(wnd, wrec.left, wrec.top);
373+
glfwSetWindowSize(wnd, wrec.right - wrec.left, wrec.bottom - wrec.top);
374+
if (cur.flags & VID_MAXIMIZE) {
375+
glfwMaximizeWindow(wnd);
376+
}
366377
if (cur.shown) {
367378
glfwShowWindow(wnd);
368379
sys->conWin->SetForeground();
369380
}
381+
else {
382+
glfwHideWindow(wnd);
383+
}
370384
}
371385
else {
372386
glfwWindowHint(GLFW_RESIZABLE, !!(cur.flags & VID_RESIZABLE));
373-
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
374-
glfwWindowHint(GLFW_FLOATING, !!(cur.flags & VID_TOPMOST));
375-
glfwWindowHint(GLFW_MAXIMIZED, !!(cur.flags & VID_MAXIMIZE));
387+
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Start hidden to not flash the user with a stock window.
388+
glfwWindowHint(GLFW_MAXIMIZED, GLFW_FALSE); // Start restored in order to position the window before maximizing.
376389
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
377390
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
378391
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
379392
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
380393
glfwWindowHint(GLFW_DEPTH_BITS, 24);
381394
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
395+
382396
wnd = glfwCreateWindow(cur.mode[0], cur.mode[1], curTitle, nullptr, nullptr);
383397
if (!wnd) {
384398
char const* errDesc = "Unknown error";
385399
glfwGetError(&errDesc);
386400
sys->con->Printf("Could not create window, %s\n", errDesc);
387401
}
388402

389-
{
390-
sys_programIcons_c icons;
391-
if (icons.Size() > 0) {
392-
glfwSetWindowIcon(wnd, (int)icons.Size(), icons.Data());
393-
}
394-
}
395403
glfwMakeContextCurrent(wnd);
396404
gladLoadGLES2(glfwGetProcAddress);
397405

398-
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
399-
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
400-
glfwSwapBuffers(wnd);
401-
406+
// Set up all our window callbacks
402407
glfwSetWindowUserPointer(wnd, sys);
403408
glfwSetCursorEnterCallback(wnd, [](GLFWwindow* wnd, int entered) {
404409
auto sys = (sys_main_c*)glfwGetWindowUserPointer(wnd);
@@ -544,11 +549,27 @@ int sys_video_c::Apply(sys_vidSet_s* set)
544549
auto sys = (sys_main_c*)glfwGetWindowUserPointer(wnd);
545550
sys->video->vid.dpiScale = xScale;
546551
});
547-
}
548552

549-
glfwSetWindowSizeLimits(wnd, cur.minSize[0], cur.minSize[1], GLFW_DONT_CARE, GLFW_DONT_CARE);
553+
// Adjust window look and position
554+
{
555+
sys_programIcons_c icons;
556+
if (icons.Size() > 0) {
557+
glfwSetWindowIcon(wnd, (int)icons.Size(), icons.Data());
558+
}
559+
}
560+
glfwSetWindowSizeLimits(wnd, cur.minSize[0], cur.minSize[1], GLFW_DONT_CARE, GLFW_DONT_CARE);
561+
glfwSetWindowPos(wnd, vid.pos[0], vid.pos[1]);
562+
if (!!(cur.flags & VID_MAXIMIZE)) {
563+
glfwMaximizeWindow(wnd);
564+
}
565+
glfwShowWindow(wnd);
566+
567+
// Clear early to avoid flash
568+
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
569+
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
570+
glfwSwapBuffers(wnd);
571+
}
550572

551-
glfwSetWindowPos(wnd, vid.pos[0], vid.pos[1]);
552573
glfwGetFramebufferSize(wnd, &vid.fbSize[0], &vid.fbSize[1]);
553574
glfwGetWindowSize(wnd, &vid.size[0], &vid.size[1]);
554575
glfwGetWindowContentScale(wnd, &sys->video->vid.dpiScale, nullptr);

0 commit comments

Comments
 (0)