AppKit: Store the window delegate's resize size in the window frame

A window stored the proposed size in its frame before asking its delegate through windowWillResize:toSize:, and gave the delegate's size only to the window view. When the delegate enlarged the size, hit testing used the smaller frame, so the window could no longer be moved or resized.

* CPWindow/CPWindow.j: Ask the delegate before storing the new size, and store the size it returns in the frame.
* CPWindow/_CPWindowView.j: Ask the delegate during a user resize, and move the origin by the delegate's adjustment when resizing from the left or top edge, so that the opposite edge stays in place.
* Tests/Manual/TextEditor/Resources/DocumentWindow.xib: Make the document window's content view resize with the window.
* Tests/Manual/TextEditor/WORKLIST.md: Remove the entry for this defect, record the minimum window size behaviour as tested, and add the content view resizing setting that does not reach the cib.
This commit is contained in:
David Richardson committed 2026-10-23 15:21:23 -06:00
1 parent 41a7004a53
commit c1f8c8ceb3
4 files changed
+32 -6

No files matched your search

+4 -3
View File
@@ -800,14 +800,15 @@ CPTexturedBackgroundWindowMask
var size = _frame.size,
newSize = frame.size;
// The delegate may change the proposed size, so ask it before the size is stored in _frame.
if (!_isAnimating && !CGSizeEqualToSize(size, newSize))
newSize = [self _sendDelegateWindowWillResizeToSize:CGSizeMakeCopy(newSize)];
if (!CGSizeEqualToSize(size, newSize))
{
size.width = newSize.width;
size.height = newSize.height;
if (!_isAnimating)
size = [self _sendDelegateWindowWillResizeToSize:size];
[_windowView setFrameSize:size];
if (_hasShadow)
+22
View File
@@ -715,6 +715,28 @@ _CPWindowViewResizeSlop = 3;
frame.size.height += dy;
}
// Let the delegate adjust the size. When resizing from the left or top, move the origin
// by the adjustment so that the edge opposite the one being dragged stays in place.
var delegateSize = [theWindow _sendDelegateWindowWillResizeToSize:CGSizeMakeCopy(frame.size)];
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionTopLeft:
case _CPWindowViewResizeRegionLeft:
case _CPWindowViewResizeRegionBottomLeft:
frame.origin.x -= delegateSize.width - frame.size.width;
}
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionTopLeft:
case _CPWindowViewResizeRegionTop:
case _CPWindowViewResizeRegionTopRight:
frame.origin.y -= delegateSize.height - frame.size.height;
}
frame.size = delegateSize;
[theWindow _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
[self setCursorForLocation:location resizing:YES];
}
@@ -20,7 +20,7 @@
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1050"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView appearanceType="aqua" fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="H3c-yb-ZSJ">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
+5 -2
View File
@@ -9,7 +9,6 @@ TextEditor is a document-based test application and a tutorial. When the app use
- **The Window menu does not list document windows.** It has no items to show or change the active window. AppKit has no equivalent of the Cocoa windows menu support in `NSApplication`: `windowsMenu`, `addWindowsItem:title:filename:`, `changeWindowsItem:title:filename:`, `removeWindowsItem:` and `arrangeInFront:`. nib2cib marks the menu as `_CPWindowsMenu` (`Tools/nib2cib/NSMenu.j:31`), but nothing in AppKit reads that name.
- **AppKit ignores `CPBundleDisplayName`.** Cocoa uses `CFBundleDisplayName` for the name that the user sees, and `CFBundleName` as the short name. AppKit reads only `CPBundleName`: for the About panel title (`CPApplication.j:389`) and for the browser tab title (`_CPMenuBarWindow.j:106`). Both should use `CPBundleDisplayName`, with `CPBundleName` as the fallback.
- **The Show Toolbar menu item does not show the toolbar state.** `-[CPWindow toggleToolbarShown:]` works (`CPWindow.j:2758`), but `CPWindow` has no `validateMenuItem:`. In Cocoa, `NSWindow` validates this item: it changes the title between "Show Toolbar" and "Hide Toolbar", and disables the item when the window has no toolbar. `CPMenu` already asks the target through `validateMenuItem:` (`CPMenu.j:699`), so the fix is a `validateMenuItem:` in `CPWindow` that handles `toggleToolbarShown:` and returns `YES` for every other action.
- **The window ignores the delegate's size for its own frame.** In `_setFrame:display:animate:constrainWidth:constrainHeight:`, `size` refers to `_frame.size`, which already holds the proposed size. The result of `windowWillResize:toSize:` replaces the local variable only, and goes to the window view (`CPWindow.j:799` to `811`). So when the delegate returns a different size, the window view takes that size, but `_frame` keeps the proposed size. The platform window chooses the window for a mouse event by testing `_frame` (`containsPoint:` and `_isValidMousePoint:`, `CPWindow.j:3832` to `3845`). So after the user shrinks a document window to its minimum, clicks on most of the visible window miss it, and the window can no longer be moved or resized. Resizing the browser window does not repair the frame. The fix: the size returned by the delegate must become `_frame.size`.
- **The "save changes" alert is modal for the whole app.** `CPDocument` shows it with `runModal` (`CPDocument.j:903`). Cocoa attaches it as a sheet to the document window, so that only that document is blocked.
- **Save cannot work without a server.** With no file URL, Save uses `CPSavePanel`, which falls back to `window.prompt` (`CPSavePanel.j:79`). `CPDocument` then sends an HTTP POST. A storage facade is needed, with local (IndexedDB) and remote (HTTP) implementations.
@@ -44,6 +43,10 @@ TextEditor is a document-based test application and a tutorial. When the app use
- **Images in text.** AppKit has no general `CPTextAttachment` class, only the table attachment `_CPTableTextAttachment`. The RTF parser and producer do not handle `\pict`.
- **Lists.** There is no `CPTextList`, and `CPParagraphStyle` has no `textLists`.
### nib2cib
- **The content view's resizing setting does not reach the cib.** Making the document window's content view resize with the window in `DocumentWindow.xib` produces a byte-identical `DocumentWindow.cib`. CPView omits the autoresizing mask from the archive only when it is `CPViewNotSizable` (`CPView.j:4016`), so the content view is archived as not sizable. Not yet determined whether `ibtool` or nib2cib drops the setting. The app still behaves correctly, because the window resizes its content view itself.
### Platform
- **Key equivalents on platforms other than macOS.** Filed as an issue.
@@ -67,5 +70,5 @@ TextEditor is a document-based test application and a tutorial. When the app use
- Text colour through `CPColorPanel`.
- Paragraph indents through the ruler markers.
- The "save changes" alert when a document closes.
- A minimum size for document windows, through the window delegate.
- A minimum size for document windows, through the window delegate. The window stops at the minimum while the pointer keeps moving, as in macOS, and it can still be moved and resized afterwards.
- Builds with both the legacy toolchain and capp-build.