From 54bc851159dee74397fd6dc0d1b2b5f28500994f Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 12 Mar 2013 21:49:15 -0400 Subject: [PATCH] Fixed: missing theme image, window sizing/moving was broken. After bbfaac5, all kinds of strange behavior occurred with window sizing and moving due to overzealous constraining. Cocoa does not constrain the frame of hidden windows. When a hidden window is ordered in, it is constrained to the usable screen content rect. A visible window has its height constrained when its frame is set. Its origin is constrained such that a minimum margin at the left, right and top is visible, and the top is constrained to be below the menu bar. This commit fixes a number of problems related to window moving and resizing that were introduced by bbfaac5: - Sheets are not constrained at all. - Moving a window does not constrain its size. In addition, when a window is moved, tracking is relative to the initial click point, which provides proper behavior when the movement is constrained and the mouse keeps moving. --- AppKit/CPWindow/CPWindow.j | 125 +++++++++++++----- AppKit/CPWindow/_CPWindowView.j | 49 ++----- .../Resources/window-standard-top-center.png | Bin 72 -> 612 bytes .../AttachedSheet2/SheetWindowController.j | 5 + 4 files changed, 108 insertions(+), 71 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 2980d8958..93716fa6a 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -56,7 +56,10 @@ var CPWindowSaveImage = nil, CPWindowResizeTime = 0.2, - CPWindowResizeStyleGlobalChangeNotification = @"CPWindowResizeStyleGlobalChangeNotification"; + CPWindowResizeStyleGlobalChangeNotification = @"CPWindowResizeStyleGlobalChangeNotification", + + CPWindowMinVisibleHorizontalMargin = 40, + CPWindowMinVisibleVerticalMargin = 2; /* Keys for which action messages will be sent by default when unhandled, e.g. complete:. @@ -642,50 +645,49 @@ CPTexturedBackgroundWindowMask */ - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate { - if (_CGRectEqualToRect(aFrame, _frame)) - return; + [self _setFrame:aFrame display:shouldDisplay animate:shouldAnimate constrainWidth:NO constrainHeight:YES]; +} - aFrame = _CGRectMakeCopy(aFrame); - - var value = aFrame.origin.x, +- (void)_setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate constrainWidth:(BOOL)shouldConstrainWidth constrainHeight:(BOOL)shouldConstrainHeight +{ + var frame = CGRectMakeCopy(aFrame), + value = frame.origin.x, delta = value - FLOOR(value); if (delta) - aFrame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value); + frame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value); - value = aFrame.origin.y; + value = frame.origin.y; delta = value - FLOOR(value); if (delta) - aFrame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value); + frame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value); - value = aFrame.size.width; + value = frame.size.width; delta = value - FLOOR(value); if (delta) - aFrame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value); + frame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value); - value = aFrame.size.height; + value = frame.size.height; delta = value - FLOOR(value); if (delta) - aFrame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value); + frame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value); - // In Cocoa, if a window is already visible, only its height is pinned - if (_isVisible) - aFrame = [self _pinFrame:aFrame toUsableScreenWidth:NO andHeight:YES]; + frame = [self _constrainFrame:frame toUsableScreenWidth:shouldConstrainWidth andHeight:shouldConstrainHeight]; if (shouldAnimate) { [_frameAnimation stopAnimation]; - _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:frame]; [_frameAnimation startAnimation]; } else { var origin = _frame.origin, - newOrigin = aFrame.origin, + newOrigin = frame.origin, originMoved = !_CGPointEqualToPoint(origin, newOrigin); if (originMoved) @@ -705,7 +707,7 @@ CPTexturedBackgroundWindowMask } var size = _frame.size, - newSize = aFrame.size; + newSize = frame.size; if (!_CGSizeEqualToSize(size, newSize)) { @@ -729,33 +731,80 @@ CPTexturedBackgroundWindowMask } } -- (CGRect)_pinFrame:(CGRect)aFrame toUsableScreenWidth:(BOOL)pinWidth andHeight:(BOOL)pinHeight +- (CGRect)_constrainFrame:(CGRect)aFrame toUsableScreenWidth:(BOOL)constrainWidth andHeight:(BOOL)constrainHeight { - if (!_constrainsToUsableScreen) - return CGRectMakeCopy(aFrame); + var frame = CGRectMakeCopy(aFrame); - var usableRect = [_platformWindow usableContentFrame], - frame = _CGRectMakeCopy(aFrame); + if (!_constrainsToUsableScreen || !_isVisible) + return frame; - if (pinWidth) + var usableRect = [_platformWindow usableContentFrame]; + + if (constrainWidth) { + // First move the frame right to ensure the left side is within the usable rect. frame.origin.x = MAX(frame.origin.x, usableRect.origin.x); - var maxX = MIN(_CGRectGetMaxX(frame), _CGRectGetMaxX(usableRect)); - frame.size.width = maxX - frame.origin.x; + // Now move the frame left so that the right side is within the usable rect. + var maxX = MIN(CGRectGetMaxX(frame), CGRectGetMaxX(usableRect)); + frame.origin.x = maxX - frame.size.width; + + // Finally, adjust the left + width to ensure the left side is within the usable rect. + var usableWidth = CGRectGetWidth(usableRect); + + if (CGRectGetWidth(frame) > usableWidth) + { + frame.origin.x = CGRectGetMinX(usableRect); + frame.size.width = usableWidth; + } } - if (pinHeight) + if (constrainHeight) { + // First move the frame down to ensure the top is within the usable rect. frame.origin.y = MAX(frame.origin.y, usableRect.origin.y); - var maxY = MIN(_CGRectGetMaxY(frame), _CGRectGetMaxY(usableRect)); - frame.size.height = maxY - frame.origin.y; + // Now move the frame up so that the bottom is within the usable rect. + var maxY = MIN(CGRectGetMaxY(frame), CGRectGetMaxY(usableRect)); + frame.origin.y = maxY - frame.size.height; + + // Finally, adjust the top + height to ensure the top is within the usable rect. + var usableHeight = CGRectGetHeight(usableRect); + + if (CGRectGetHeight(frame) > usableHeight) + { + frame.origin.y = CGRectGetMinY(usableRect); + frame.size.height = usableHeight; + } } return frame; } +- (CGRect)_constrainOriginOfFrame:(CGRect)aFrame +{ + var frame = CGRectMakeCopy(aFrame); + + if (!_constrainsToUsableScreen || !_isVisible) + return frame; + + /* + - CPWindowMinVisibleHorizontalMargin is kept onscreen at the left/right of the window. + - The top of the window is kept below the top of the usable content. + - The top of the contentView + CPWindowMinVisibleVerticalMargin is kept above the bottom of the usable content. + */ + var usableRect = [_platformWindow usableContentFrame], + maxUsableY = CGRectGetMaxY(usableRect) - CGRectGetMinY([_contentView frame]) - CPWindowMinVisibleVerticalMargin; + + frame.origin.x = MAX(frame.origin.x, CGRectGetMinX(usableRect) + CPWindowMinVisibleHorizontalMargin - CGRectGetWidth(frame)); + frame.origin.x = MIN(frame.origin.x, CGRectGetMaxX(usableRect) - CPWindowMinVisibleHorizontalMargin); + + frame.origin.y = MAX(frame.origin.y, CGRectGetMinY(usableRect)); + frame.origin.y = MIN(frame.origin.y, maxUsableY); + + return frame; +} + - (void)_moveChildWindows:(CGPoint)delta { [_childWindows enumerateObjectsUsingBlock:function(childWindow) @@ -792,7 +841,8 @@ CPTexturedBackgroundWindowMask */ - (void)setFrameOrigin:(CGPoint)anOrigin { - [self setFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO]; + var frame = [self _constrainOriginOfFrame:CGRectMake(anOrigin.x, anOrigin.y, _frame.size.width, _frame.size.height)]; + [self _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO]; // reposition sheet if ([self attachedSheet]) @@ -824,8 +874,8 @@ CPTexturedBackgroundWindowMask if ([self isSheet]) [_parentView orderFront:self]; - // Cocoa pins windows to the usable screen content during orderFront - [self setFrame:[self _pinFrame:_frame toUsableScreenWidth:YES andHeight:YES]]; + if (!_isVisible) + [self _setFrame:_frame display:YES animate:NO constrainWidth:YES constrainHeight:YES]; [_platformWindow orderFront:self]; [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; @@ -2557,8 +2607,7 @@ CPTexturedBackgroundWindowMask var sheetFrame = [aSheet frame]; _sheetContext = {"sheet": aSheet, "modalDelegate": aModalDelegate, "endSelector": aDidEndSelector, - "contextInfo": aContextInfo, "returnCode": -1, - "opened": NO}; + "contextInfo": aContextInfo, "returnCode": -1, "opened": NO, "savedConstrains": aSheet._constrainsToUsableScreen}; [self _attachSheetWindow]; } @@ -2570,6 +2619,7 @@ CPTexturedBackgroundWindowMask - (void)_attachSheetWindow { _sheetContext["isAttached"] = YES; + _sheetContext["sheet"]._constrainsToUsableScreen = NO; // it would be ideal to block here and spin an event loop, until attach is complete [CPTimer scheduledTimerWithTimeInterval:0.0 @@ -2633,6 +2683,7 @@ CPTexturedBackgroundWindowMask // Restore the state of window before it was sheetified sheet._isSheet = NO; [sheet._windowView _enableSheet:NO inWindow:self]; + sheet._constrainsToUsableScreen = _sheetContext["savedConstrains"]; // Close it [sheet orderOut:self]; @@ -2707,7 +2758,6 @@ CPTexturedBackgroundWindowMask endFrame = _CGRectMake(originX, endY, sheetFrame.size.width, sheetFrame.size.height); [sheet orderFront:self]; - [self _clipSheet:sheet]; [sheet setFrame:startFrame display:YES animate:NO]; @@ -2747,6 +2797,9 @@ CPTexturedBackgroundWindowMask endFrame = _CGRectMakeCopy(sheetFrame), contentOrigin = [self convertBaseToGlobal:[[self contentView] frame].origin]; + // Don't constrain sheets, they are controlled by the parent + sheet._constrainsToUsableScreen = NO; + [sheet setFrameOrigin:_CGPointMake(sheetFrame.origin.x, sheetFrame.origin.y - contentOrigin.y)]; [self _clipSheet:sheet]; diff --git a/AppKit/CPWindow/_CPWindowView.j b/AppKit/CPWindow/_CPWindowView.j index 85fd42b6e..4f1af0714 100644 --- a/AppKit/CPWindow/_CPWindowView.j +++ b/AppKit/CPWindow/_CPWindowView.j @@ -57,7 +57,7 @@ _CPWindowViewResizeSlop = 3; CGSize _toolbarOffset; // BOOL _isAnimatingToolbar; - CGRect _resizeFrame; + CGRect _cachedFrame; int _resizeRegion; CGPoint _mouseDraggedPoint; @@ -467,17 +467,17 @@ _CPWindowViewResizeSlop = 3; if (type === CPLeftMouseDown) { _mouseDraggedPoint = _CGPointMake(globalLocation.x, globalLocation.y); - _resizeFrame = _CGRectMakeCopy(frame); + _cachedFrame = _CGRectMakeCopy(frame); _cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame]; } else if (type === CPLeftMouseDragged) { var deltaX = globalLocation.x - _mouseDraggedPoint.x, deltaY = globalLocation.y - _mouseDraggedPoint.y, - startX = _CGRectGetMinX(_resizeFrame), - startY = _CGRectGetMinY(_resizeFrame), - startWidth = _CGRectGetWidth(_resizeFrame), - startHeight = _CGRectGetHeight(_resizeFrame), + startX = _CGRectGetMinX(_cachedFrame), + startY = _CGRectGetMinY(_cachedFrame), + startWidth = _CGRectGetWidth(_cachedFrame), + startHeight = _CGRectGetHeight(_cachedFrame), newX, newY, newWidth, @@ -631,61 +631,40 @@ _CPWindowViewResizeSlop = 3; newHeight = startHeight; } - [theWindow setFrame:_CGRectMake(newX, newY, newWidth, newHeight)]; + [theWindow _setFrame:_CGRectMake(newX, newY, newWidth, newHeight) display:YES animate:NO constrainWidth:NO constrainHeight:NO]; [self setCursorForLocation:location resizing:YES]; } [CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; } -- (CGPoint)_pointWithinScreenFrame:(CGPoint)aPoint -{ - // FIXME: this is WRONG, all of this is WRONG - if (![CPPlatform isBrowser]) - return aPoint; - - var visibleFrame = _cachedScreenFrame; - - if (!visibleFrame) - visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame]; - - var restrictedPoint = _CGPointMake(0, 0); - - restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), _CGRectGetMaxX(visibleFrame) - 4.0); - restrictedPoint.y = MIN(MAX(aPoint.y, _CGRectGetMinY(visibleFrame)), _CGRectGetMaxY(visibleFrame) - 8.0); - - return restrictedPoint; -} - - (void)trackMoveWithEvent:(CPEvent)anEvent { - if (![[self window] isMovable]) + var theWindow = [self window]; + + if (![theWindow isMovable]) return; var type = [anEvent type]; if (type === CPLeftMouseUp) { - _cachedScreenFrame = nil; return; } else if (type === CPLeftMouseDown) { - _mouseDraggedPoint = [[self window] convertBaseToGlobal:[anEvent locationInWindow]]; - _cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame]; + _mouseDraggedPoint = [theWindow convertBaseToGlobal:[anEvent locationInWindow]]; + _cachedFrame = _CGRectMakeCopy([theWindow frame]); } else if (type === CPLeftMouseDragged) { var theWindow = [self window], - frame = [theWindow frame], location = [theWindow convertBaseToGlobal:[anEvent locationInWindow]], deltaX = location.x - _mouseDraggedPoint.x, deltaY = location.y - _mouseDraggedPoint.y, - origin = [self _pointWithinScreenFrame:_CGPointMake(frame.origin.x + deltaX, - frame.origin.y + deltaY)]; - [theWindow setFrameOrigin:origin]; + origin = _CGPointMake(_cachedFrame.origin.x + deltaX, _cachedFrame.origin.y + deltaY); - _mouseDraggedPoint = [self _pointWithinScreenFrame:location]; + [theWindow setFrameOrigin:origin]; } [CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; diff --git a/AppKit/Themes/Aristo2/Resources/window-standard-top-center.png b/AppKit/Themes/Aristo2/Resources/window-standard-top-center.png index a564ec3c44a55d6e6729499a2a41edb6da3e1d51..0acc88870cc62412b8da80aed8ac602a13796ee0 100644 GIT binary patch delta 597 zcmV-b0;>H;m0EC2wp8x;=8FWQhbW?9;ba!ELWdK2BZ(?O2No`?gWm08f zWO;GPWjp`?0p@8`SaeuTOgdw4Z7yMCZ(?OGcx`Y10RR91D3P60OK#gR5WNb)Y+9fe zKe8x^h#DwTgl3^Oa169tSz=wG`ex{= zdLt}YiD#)2`1AD#1hPrs*Pz5@mx;CfbTH!a@OfDuHg(*?VQfXaL{J2astaK;Zea8WRE-^T<44jC=qT6N<3AY)0lhV4Q~F zbfAl7nkT-Ms7SCfZa^tF+l zm0E#Ou2yw4D;W$*I@I*ZrHhGP=Be=de|98%08LSlmBJTF+0riIUP zI{A2uOKHmP=8Q&u*V`14IBovRO@CFEal|A)EZ;*H>+3DK>`wMSL+Xw~nU*r5HS2{an^L HB{Ts5iuDhg diff --git a/Tests/Manual/AttachedSheet2/SheetWindowController.j b/Tests/Manual/AttachedSheet2/SheetWindowController.j index 298eefada..1630e3034 100644 --- a/Tests/Manual/AttachedSheet2/SheetWindowController.j +++ b/Tests/Manual/AttachedSheet2/SheetWindowController.j @@ -1,3 +1,8 @@ +@import +@import +@import +@import +@import @implementation SheetWindowController : CPWindowController {