Add window size and position persistence#22
Conversation
Co-authored-by: ForLoopCodes <89027512+ForLoopCodes@users.noreply.github.com>
…narios Co-authored-by: ForLoopCodes <89027512+ForLoopCodes@users.noreply.github.com>
…et_cast Co-authored-by: ForLoopCodes <89027512+ForLoopCodes@users.noreply.github.com>
Co-authored-by: ForLoopCodes <89027512+ForLoopCodes@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds persistence of the main window’s last normal position and size to the existing registry-backed settings system, so LegacyNotepad restores geometry across launches (similar to native Notepad).
Changes:
- Added window geometry fields (
windowX,windowY,windowWidth,windowHeight) toAppStatewith defaults. - Implemented
LoadWindowSettings()/SaveWindowSettings()to read/write geometry underHKCU\Software\LegacyNotepad. - Wired geometry load before
CreateWindowExW()and geometry save onWM_DESTROYusingGetWindowPlacement().rcNormalPosition.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/modules/settings.h |
Exposes window settings load/save APIs. |
src/modules/settings.cpp |
Implements registry persistence for window X/Y/Width/Height and basic off-screen validation. |
src/main.cpp |
Loads geometry on startup; captures/saves geometry on shutdown; uses persisted geometry when creating the main window. |
src/core/types.h |
Extends AppState with persisted window geometry fields and defaults. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| DWORD width = 0; | ||
| size = sizeof(width); | ||
| if (RegQueryValueExW(hKey, WINDOW_WIDTH_VALUE, nullptr, nullptr, reinterpret_cast<LPBYTE>(&width), &size) == ERROR_SUCCESS) | ||
| { | ||
| if (width > 0) | ||
| { | ||
| g_state.windowWidth = static_cast<int>(width); | ||
| } | ||
| } | ||
|
|
||
| DWORD height = 0; | ||
| size = sizeof(height); | ||
| if (RegQueryValueExW(hKey, WINDOW_HEIGHT_VALUE, nullptr, nullptr, reinterpret_cast<LPBYTE>(&height), &size) == ERROR_SUCCESS) | ||
| { | ||
| if (height > 0) | ||
| { | ||
| g_state.windowHeight = static_cast<int>(height); | ||
| } | ||
| } |
There was a problem hiding this comment.
LoadWindowSettings() assigns registry REG_DWORD width/height directly to int after only checking > 0. If the stored DWORD exceeds INT_MAX, the cast can wrap to a negative int, which can make CreateWindowExW fail or create invalid geometry. Please bound-check the DWORDs (e.g., <= INT_MAX and within a reasonable min/max) before casting/assigning, and consider resetting to defaults when out of range.
| // Validate that the window position is visible on at least one monitor | ||
| RECT rc = {g_state.windowX, g_state.windowY, g_state.windowX + g_state.windowWidth, g_state.windowY + g_state.windowHeight}; | ||
| HMONITOR hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONULL); |
There was a problem hiding this comment.
The RECT construction uses g_state.windowX + g_state.windowWidth and g_state.windowY + g_state.windowHeight in signed arithmetic. If registry values are large/corrupted, these additions can overflow int, which is undefined behavior in C++. Consider using a wider intermediate type and clamping to LONG range (or validating inputs) before building the RECT for MonitorFromRect().
Implements window geometry persistence to registry, matching native Notepad behavior.
Implementation
windowX,windowY,windowWidth,windowHeighttoAppStatewith 640×480 defaultLoadWindowSettings()/SaveWindowSettings()functions write toHKEY_CURRENT_USER\Software\LegacyNotepadCreateWindowExW(), save onWM_DESTROYusingGetWindowPlacement().rcNormalPositionEdge Cases
static_cast<int>(DWORD)round-tripMonitorFromRect()validation resets toCW_USEDEFAULTif no monitor intersectionrcNormalPositionso window doesn't reopen maximized unintentionallyRegistry keys:
WindowX,WindowY,WindowWidth,WindowHeight(REG_DWORD)Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.