diff --git a/AppKit/CPView.j b/AppKit/CPView.j index df06eb78b..1f5b949aa 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -602,7 +602,8 @@ var CPViewHighDPIDrawingEnabled = YES; // We will have to adjust the z-index of all views starting at this index. var count = _subviews.length, - lastWindow; + lastWindow, + isNewAddOrMove = aSubview._superview !== self; // Dirty the key view loop, in case the window wants to auto recalculate it [[self window] _dirtyKeyViewLoop]; @@ -673,6 +674,9 @@ var CPViewHighDPIDrawingEnabled = YES; if (!_window && lastWindow) [aSubview _setWindow:nil]; + if (isNewAddOrMove) + [aSubview _postViewDidAppearNotification]; + // This method might be called before we are fully unarchived, in which case the theme state isn't set up yet // and none of the below matters anyhow. if (_themeState) @@ -735,6 +739,7 @@ var CPViewHighDPIDrawingEnabled = YES; // If the view is not hidden and one of its ancestors is hidden, // notify the view that it is now unhidden. [self _setSuperview:nil]; + [self _postViewDidDisappearNotification]; [self _notifyWindowDidResignKey]; [self _notifyViewDidResignFirstResponder]; @@ -1719,11 +1724,7 @@ var CPViewHighDPIDrawingEnabled = YES; _superview = aSuperview; - if (hasOldSuperview) - [self _postViewDidDisappearNotification]; - - if (hasNewSuperview) - [self _postViewDidAppearNotification]; + // Notifications are now posted manually from _insertSubview and _removeFromSuperview } - (void)_recursiveLostHiddenAncestor diff --git a/Tests/AppKit/CPViewTest.j b/Tests/AppKit/CPViewTest.j index 7c99fbe65..e3e1003d9 100644 --- a/Tests/AppKit/CPViewTest.j +++ b/Tests/AppKit/CPViewTest.j @@ -9,7 +9,20 @@ var updateTrackingAreasCalls, cursorUpdateCalls, involvedViewForMouseEntered, involvedViewForMouseExited, - involvedViewForCursorUpdate; + involvedViewForCursorUpdate, + windowPropertyWasNilInViewDidAppear; + +@implementation CPTestableViewController : CPViewController +{ +} + +- (void)viewDidAppear +{ + [super viewDidAppear]; + windowPropertyWasNilInViewDidAppear = ([self view] && [[self view] window] === nil); +} + +@end @implementation CPViewTest : OJTestCase { @@ -39,6 +52,7 @@ var updateTrackingAreasCalls, methodCalled = []; updateTrackingAreasCalls = 0; + windowPropertyWasNilInViewDidAppear = NO; [super setUp]; } @@ -1661,6 +1675,23 @@ var updateTrackingAreasCalls, [[CPApplication sharedApplication] sendEvent:anEvent]; } +- (void)testWindowIsSetBeforeViewDidAppear +{ + // 1. Create a view controller. This will also create its view. + var viewController = [[CPTestableViewController alloc] init]; + var controllerView = [viewController view]; + + // 2. Add the controller's view to the window's view hierarchy. + // This will trigger the chain of notifications, including _CPViewDidAppearNotification, + // which in turn calls -[CPViewController viewDidAppear]. + [[window contentView] addSubview:controllerView]; + + // 3. Check the flag set by our custom view controller. + // If the fix is correct, the window should have been set before viewDidAppear was called, + // so the flag should be NO. + [self assertFalse:windowPropertyWasNilInViewDidAppear message:@"The view's window property should be set before -[CPViewController viewDidAppear] is called."]; +} + @end @implementation CPTrackingAreaView : CPView