![]() |
API 0.9.5
|
00001 /* 00002 * CPWindow.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00025 00026 /* 00027 Borderless window mask option. 00028 @global 00029 @class CPWindow 00030 */ 00031 CPBorderlessWindowMask = 0; 00032 /* 00033 Titled window mask option. 00034 @global 00035 @class CPWindow 00036 */ 00037 CPTitledWindowMask = 1 << 0; 00038 /* 00039 Closeable window mask option. 00040 @global 00041 @class CPWindow 00042 */ 00043 CPClosableWindowMask = 1 << 1; 00044 /* 00045 Miniaturizabe window mask option. 00046 @global 00047 @class CPWindow 00048 */ 00049 CPMiniaturizableWindowMask = 1 << 2; 00050 /* 00051 Resizable window mask option. 00052 @global 00053 @class CPWindow 00054 */ 00055 CPResizableWindowMask = 1 << 3; 00056 /* 00057 Textured window mask option. 00058 @global 00059 @class CPWindow 00060 */ 00061 CPTexturedBackgroundWindowMask = 1 << 8; 00062 /* 00063 @global 00064 @class CPWindow 00065 */ 00066 CPBorderlessBridgeWindowMask = 1 << 20; 00067 /* 00068 @global 00069 @class CPWindow 00070 */ 00071 CPHUDBackgroundWindowMask = 1 << 21; 00072 00073 CPWindowNotSizable = 0; 00074 CPWindowMinXMargin = 1; 00075 CPWindowWidthSizable = 2; 00076 CPWindowMaxXMargin = 4; 00077 CPWindowMinYMargin = 8; 00078 CPWindowHeightSizable = 16; 00079 CPWindowMaxYMargin = 32; 00080 00081 CPBackgroundWindowLevel = -1; 00082 /* 00083 Default level for windows 00084 @group CPWindowLevel 00085 @global 00086 */ 00087 CPNormalWindowLevel = 0; 00088 /* 00089 Floating palette type window 00090 @group CPWindowLevel 00091 @global 00092 */ 00093 CPFloatingWindowLevel = 3; 00094 /* 00095 Submenu type window 00096 @group CPWindowLevel 00097 @global 00098 */ 00099 CPSubmenuWindowLevel = 3; 00100 /* 00101 For a torn-off menu 00102 @group CPWindowLevel 00103 @global 00104 */ 00105 CPTornOffMenuWindowLevel = 3; 00106 /* 00107 For the application's main menu 00108 @group CPWindowLevel 00109 @global 00110 */ 00111 CPMainMenuWindowLevel = 24; 00112 /* 00113 Status window level 00114 @group CPWindowLevel 00115 @global 00116 */ 00117 CPStatusWindowLevel = 25; 00118 /* 00119 Level for a modal panel 00120 @group CPWindowLevel 00121 @global 00122 */ 00123 CPModalPanelWindowLevel = 8; 00124 /* 00125 Level for a pop up menu 00126 @group CPWindowLevel 00127 @global 00128 */ 00129 CPPopUpMenuWindowLevel = 101; 00130 /* 00131 Level for a window being dragged 00132 @group CPWindowLevel 00133 @global 00134 */ 00135 CPDraggingWindowLevel = 500; 00136 /* 00137 Level for the screens saver 00138 @group CPWindowLevel 00139 @global 00140 */ 00141 CPScreenSaverWindowLevel = 1000; 00142 00143 /* 00144 The receiver is removed from the screen list and hidden. 00145 @global 00146 @class CPWindowOrderingMode 00147 */ 00148 CPWindowOut = 0; 00149 /* 00150 The receiver is placed directly in front of the window specified. 00151 @global 00152 @class CPWindowOrderingMode 00153 */ 00154 CPWindowAbove = 1; 00155 /* 00156 The receiver is placed directly behind the window specified. 00157 @global 00158 @class CPWindowOrderingMode 00159 */ 00160 CPWindowBelow = 2; 00161 00162 CPWindowWillCloseNotification = @"CPWindowWillCloseNotification"; 00163 CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification"; 00164 CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification"; 00165 CPWindowDidBecomeKeyNotification = @"CPWindowDidBecomeKeyNotification"; 00166 CPWindowDidResignKeyNotification = @"CPWindowDidResignKeyNotification"; 00167 CPWindowDidResizeNotification = @"CPWindowDidResizeNotification"; 00168 CPWindowDidMoveNotification = @"CPWindowDidMoveNotification"; 00169 CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification"; 00170 CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification"; 00171 CPWindowDidMiniaturizeNotification = @"CPWindowDidMiniaturizeNotification"; 00172 CPWindowWillMiniaturizeNotification = @"CPWindowWillMiniaturizeNotification"; 00173 CPWindowDidDeminiaturizeNotification = @"CPWindowDidDeminiaturizeNotification"; 00174 00175 CPWindowShadowStyleStandard = 0; 00176 CPWindowShadowStyleMenu = 1; 00177 CPWindowShadowStylePanel = 2; 00178 00179 var SHADOW_MARGIN_LEFT = 20.0, 00180 SHADOW_MARGIN_RIGHT = 19.0, 00181 SHADOW_MARGIN_TOP = 10.0, 00182 SHADOW_MARGIN_BOTTOM = 10.0, 00183 SHADOW_DISTANCE = 5.0, 00184 00185 _CPWindowShadowColor = nil; 00186 00187 var CPWindowSaveImage = nil, 00188 CPWindowSavingImage = nil, 00189 00190 CPWindowResizeTime = 0.2; 00191 00192 /* 00193 Keys for which action messages will be sent by default when unhandled, e.g. complete:. 00194 */ 00195 var CPWindowActionMessageKeys = [ 00196 CPLeftArrowFunctionKey, 00197 CPRightArrowFunctionKey, 00198 CPUpArrowFunctionKey, 00199 CPDownArrowFunctionKey, 00200 CPPageUpFunctionKey, 00201 CPPageDownFunctionKey, 00202 CPHomeFunctionKey, 00203 CPEndFunctionKey, 00204 CPEscapeFunctionKey 00205 ]; 00206 00253 @implementation CPWindow : CPResponder 00254 { 00255 CPPlatformWindow _platformWindow; 00256 00257 int _windowNumber; 00258 unsigned _styleMask; 00259 CGRect _frame; 00260 int _level; 00261 BOOL _isVisible; 00262 BOOL _isMiniaturized; 00263 BOOL _isAnimating; 00264 BOOL _hasShadow; 00265 BOOL _isMovableByWindowBackground; 00266 BOOL _isMovable; 00267 unsigned _shadowStyle; 00268 BOOL _showsResizeIndicator; 00269 00270 BOOL _isDocumentEdited; 00271 BOOL _isDocumentSaving; 00272 00273 CPImageView _shadowView; 00274 00275 CPView _windowView; 00276 CPView _contentView; 00277 CPView _toolbarView; 00278 00279 CPArray _mouseEnteredStack; 00280 CPView _leftMouseDownView; 00281 CPView _rightMouseDownView; 00282 00283 CPToolbar _toolbar; 00284 CPResponder _firstResponder; 00285 CPResponder _initialFirstResponder; 00286 id _delegate; 00287 00288 CPString _title; 00289 00290 BOOL _acceptsMouseMovedEvents; 00291 BOOL _ignoresMouseEvents; 00292 00293 CPWindowController _windowController; 00294 00295 CGSize _minSize; 00296 CGSize _maxSize; 00297 00298 CPUndoManager _undoManager; 00299 CPURL _representedURL; 00300 00301 CPSet _registeredDraggedTypes; 00302 CPArray _registeredDraggedTypesArray; 00303 CPCountedSet _inclusiveRegisteredDraggedTypes; 00304 00305 CPButton _defaultButton; 00306 BOOL _defaultButtonEnabled; 00307 00308 BOOL _autorecalculatesKeyViewLoop; 00309 BOOL _keyViewLoopIsDirty; 00310 00311 BOOL _sharesChromeWithPlatformWindow; 00312 00313 // Bridge Support 00314 #if PLATFORM(DOM) 00315 DOMElement _DOMElement; 00316 #endif 00317 00318 unsigned _autoresizingMask; 00319 00320 BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; 00321 00322 BOOL _isFullPlatformWindow; 00323 _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; 00324 00325 CPDictionary _sheetContext; 00326 CPWindow _parentView; 00327 BOOL _isSheet; 00328 00329 _CPWindowFrameAnimation _frameAnimation; 00330 } 00331 00332 /* 00333 Private initializer for Objective-J 00334 @ignore 00335 */ 00336 + (void)initialize 00337 { 00338 if (self != [CPWindow class]) 00339 return; 00340 00341 var bundle = [CPBundle bundleForClass:[CPWindow class]]; 00342 00343 CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)] 00344 } 00345 00346 - (id)init 00347 { 00348 return [self initWithContentRect:_CGRectMakeZero() styleMask:CPTitledWindowMask]; 00349 } 00350 00366 - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask 00367 { 00368 self = [super init]; 00369 00370 if (self) 00371 { 00372 var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask]; 00373 00374 _frame = [windowViewClass frameRectForContentRect:aContentRect]; 00375 00376 [self _setSharesChromeWithPlatformWindow:![CPPlatform isBrowser]]; 00377 00378 if ([CPPlatform isBrowser]) 00379 [self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]]; 00380 else 00381 { 00382 // give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost. 00383 if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0) 00384 { 00385 var visibleFrame = [[[CPScreen alloc] init] visibleFrame]; 00386 _frame.size.height = MIN(768.0, visibleFrame.size.height); 00387 _frame.size.width = MIN(1024.0, visibleFrame.size.width); 00388 _frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2; 00389 _frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2; 00390 } 00391 [self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]]; 00392 [self platformWindow]._only = self; 00393 } 00394 00395 _isFullPlatformWindow = NO; 00396 _registeredDraggedTypes = [CPSet set]; 00397 _registeredDraggedTypesArray = []; 00398 _isSheet = NO; 00399 _acceptsMouseMovedEvents = YES; 00400 _isMovable = YES; 00401 00402 // Set up our window number. 00403 _windowNumber = [CPApp._windows count]; 00404 CPApp._windows[_windowNumber] = self; 00405 00406 _styleMask = aStyleMask; 00407 00408 [self setLevel:CPNormalWindowLevel]; 00409 00410 _minSize = CGSizeMake(0.0, 0.0); 00411 _maxSize = CGSizeMake(1000000.0, 1000000.0); 00412 00413 // Create our border view which is the actual root of our view hierarchy. 00414 _windowView = [[windowViewClass alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)) styleMask:aStyleMask]; 00415 00416 [_windowView _setWindow:self]; 00417 [_windowView setNextResponder:self]; 00418 00419 [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask]; 00420 00421 // Create a generic content view. 00422 [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; 00423 [self setInitialFirstResponder:[self contentView]]; 00424 00425 _firstResponder = self; 00426 00427 #if PLATFORM(DOM) 00428 _DOMElement = document.createElement("div"); 00429 00430 _DOMElement.style.position = "absolute"; 00431 _DOMElement.style.visibility = "visible"; 00432 _DOMElement.style.zIndex = 0; 00433 00434 if (![self _sharesChromeWithPlatformWindow]) 00435 { 00436 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame)); 00437 } 00438 00439 CPDOMDisplayServerSetStyleSize(_DOMElement, 1, 1); 00440 CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement); 00441 #endif 00442 00443 [self setNextResponder:CPApp]; 00444 00445 [self setHasShadow:aStyleMask !== CPBorderlessWindowMask]; 00446 00447 if (aStyleMask & CPBorderlessBridgeWindowMask) 00448 [self setFullPlatformWindow:YES]; 00449 00450 _defaultButtonEnabled = YES; 00451 _keyViewLoopIsDirty = YES; 00452 00453 [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask]; 00454 } 00455 00456 return self; 00457 } 00458 00459 - (CPPlatformWindow)platformWindow 00460 { 00461 return _platformWindow; 00462 } 00463 00469 - (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow 00470 { 00471 var wasVisible = [self isVisible]; 00472 00473 // we have to close it first, otherwise we get a DOM exception. 00474 if (wasVisible) 00475 [self close]; 00476 00477 _platformWindow = aPlatformWindow; 00478 [_platformWindow _setTitle:_title window:self]; 00479 00480 if (wasVisible) 00481 [self orderFront:self]; 00482 } 00483 00484 00488 + (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask 00489 { 00490 if (aStyleMask & CPHUDBackgroundWindowMask) 00491 return _CPHUDWindowView; 00492 00493 else if (aStyleMask === CPBorderlessWindowMask) 00494 return _CPBorderlessWindowView; 00495 00496 else if (aStyleMask & CPDocModalWindowMask) 00497 return _CPDocModalWindowView; 00498 00499 return _CPStandardWindowView; 00500 } 00501 00502 + (Class)_windowViewClassForFullPlatformWindowStyleMask:(unsigned)aStyleMask 00503 { 00504 return _CPBorderlessBridgeWindowView; 00505 } 00506 00507 - (void)awakeFromCib 00508 { 00509 _keyViewLoopIsDirty = ![self _hasKeyViewLoop]; 00510 } 00511 00512 - (void)_setWindowView:(CPView)aWindowView 00513 { 00514 if (_windowView === aWindowView) 00515 return; 00516 00517 var oldWindowView = _windowView; 00518 00519 _windowView = aWindowView; 00520 00521 if (oldWindowView) 00522 { 00523 [oldWindowView _setWindow:nil]; 00524 [oldWindowView noteToolbarChanged]; 00525 00526 #if PLATFORM(DOM) 00527 CPDOMDisplayServerRemoveChild(_DOMElement, oldWindowView._DOMElement); 00528 #endif 00529 } 00530 00531 if (_windowView) 00532 { 00533 #if PLATFORM(DOM) 00534 CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement); 00535 #endif 00536 00537 var contentRect = [_contentView convertRect:[_contentView bounds] toView:nil]; 00538 00539 contentRect.origin = [self convertBaseToGlobal:contentRect.origin]; 00540 00541 [_windowView _setWindow:self]; 00542 [_windowView setNextResponder:self]; 00543 [_windowView addSubview:_contentView]; 00544 [_windowView setTitle:_title]; 00545 [_windowView noteToolbarChanged]; 00546 [_windowView setShowsResizeIndicator:[self showsResizeIndicator]]; 00547 00548 [self setFrame:[self frameRectForContentRect:contentRect]]; 00549 } 00550 } 00551 00558 - (void)setFullPlatformWindow:(BOOL)shouldBeFullPlatformWindow 00559 { 00560 if (![_platformWindow supportsFullPlatformWindows]) 00561 return; 00562 00563 shouldBeFullPlatformWindow = !!shouldBeFullPlatformWindow; 00564 00565 if (_isFullPlatformWindow === shouldBeFullPlatformWindow) 00566 return; 00567 00568 _isFullPlatformWindow = shouldBeFullPlatformWindow; 00569 00570 if (_isFullPlatformWindow) 00571 { 00572 _fullPlatformWindowSession = _CPWindowFullPlatformWindowSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]); 00573 00574 var fullPlatformWindowViewClass = [[self class] _windowViewClassForFullPlatformWindowStyleMask:_styleMask], 00575 windowView = [[fullPlatformWindowViewClass alloc] initWithFrame:CGRectMakeZero() styleMask:_styleMask]; 00576 00577 [self _setWindowView:windowView]; 00578 00579 [self setLevel:CPBackgroundWindowLevel]; 00580 [self setHasShadow:NO]; 00581 [self setAutoresizingMask:CPWindowWidthSizable | CPWindowHeightSizable]; 00582 [self setFrame:[_platformWindow visibleFrame]]; 00583 } 00584 else 00585 { 00586 var windowView = _fullPlatformWindowSession.windowView; 00587 00588 [self _setWindowView:windowView]; 00589 00590 [self setLevel:_fullPlatformWindowSession.level]; 00591 [self setHasShadow:_fullPlatformWindowSession.hasShadow]; 00592 [self setAutoresizingMask:CPWindowNotSizable]; 00593 00594 [self setFrame:[windowView frameRectForContentRect:_fullPlatformWindowSession.contentRect]]; 00595 } 00596 } 00597 00601 - (BOOL)isFullPlatformWindow 00602 { 00603 return _isFullPlatformWindow; 00604 } 00605 00609 - (unsigned)styleMask 00610 { 00611 return _styleMask; 00612 } 00613 00632 + (CGRect)frameRectForContentRect:(CGRect)aContentRect styleMask:(unsigned)aStyleMask 00633 { 00634 return [[[self class] _windowViewClassForStyleMask:aStyleMask] frameRectForContentRect:aContentRect]; 00635 } 00636 00641 - (CGRect)contentRectForFrameRect:(CGRect)aFrame 00642 { 00643 return [_windowView contentRectForFrameRect:aFrame]; 00644 } 00645 00651 - (CGRect)frameRectForContentRect:(CGRect)aContentRect 00652 { 00653 return [_windowView frameRectForContentRect:aContentRect]; 00654 } 00655 00659 - (CGRect)frame 00660 { 00661 return _CGRectMakeCopy(_frame); 00662 } 00663 00671 - (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate 00672 { 00673 aFrame.size.width = MIN(MAX(aFrame.size.width, _minSize.width), _maxSize.width) 00674 aFrame.size.height = MIN(MAX(aFrame.size.height, _minSize.height), _maxSize.height); 00675 [self setFrame:aFrame display:shouldDisplay animate:shouldAnimate]; 00676 } 00677 00685 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate 00686 { 00687 aFrame = _CGRectMakeCopy(aFrame); 00688 00689 var value = aFrame.origin.x, 00690 delta = value - FLOOR(value); 00691 00692 if (delta) 00693 aFrame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value); 00694 00695 value = aFrame.origin.y; 00696 delta = value - FLOOR(value); 00697 00698 if (delta) 00699 aFrame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value); 00700 00701 value = aFrame.size.width; 00702 delta = value - FLOOR(value); 00703 00704 if (delta) 00705 aFrame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value); 00706 00707 value = aFrame.size.height; 00708 delta = value - FLOOR(value); 00709 00710 if (delta) 00711 aFrame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value); 00712 00713 if (shouldAnimate) 00714 { 00715 [_frameAnimation stopAnimation]; 00716 _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; 00717 00718 [_frameAnimation startAnimation]; 00719 } 00720 else 00721 { 00722 var origin = _frame.origin, 00723 newOrigin = aFrame.origin; 00724 00725 if (!_CGPointEqualToPoint(origin, newOrigin)) 00726 { 00727 origin.x = newOrigin.x; 00728 origin.y = newOrigin.y; 00729 00730 #if PLATFORM(DOM) 00731 if (![self _sharesChromeWithPlatformWindow]) 00732 { 00733 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, origin.x, origin.y); 00734 } 00735 #endif 00736 00737 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMoveNotification object:self]; 00738 } 00739 00740 var size = _frame.size, 00741 newSize = aFrame.size; 00742 00743 if (!_CGSizeEqualToSize(size, newSize)) 00744 { 00745 size.width = newSize.width; 00746 size.height = newSize.height; 00747 00748 [_windowView setFrameSize:size]; 00749 00750 if (_hasShadow) 00751 [_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)]; 00752 00753 if (!_isAnimating) 00754 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self]; 00755 } 00756 00757 if ([self _sharesChromeWithPlatformWindow]) 00758 [_platformWindow setContentRect:_frame]; 00759 } 00760 } 00761 00767 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay 00768 { 00769 [self _setClippedFrame:aFrame display:shouldDisplay animate:NO]; 00770 } 00771 00776 - (void)setFrame:(CGRect)aFrame 00777 { 00778 [self _setClippedFrame:aFrame display:YES animate:NO]; 00779 } 00780 00785 - (void)setFrameOrigin:(CGPoint)anOrigin 00786 { 00787 [self _setClippedFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO]; 00788 } 00789 00794 - (void)setFrameSize:(CGSize)aSize 00795 { 00796 [self _setClippedFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO]; 00797 } 00798 00803 - (void)orderFront:(id)aSender 00804 { 00805 #if PLATFORM(DOM) 00806 [_platformWindow orderFront:self]; 00807 [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; 00808 #endif 00809 00810 if (_firstResponder === self || !_firstResponder) 00811 [self makeFirstResponder:[self initialFirstResponder]]; 00812 00813 if (!CPApp._keyWindow) 00814 [self makeKeyWindow]; 00815 00816 if (!CPApp._mainWindow) 00817 [self makeMainWindow]; 00818 } 00819 00820 /* 00821 Makes the receiver the last window in the screen ordering. 00822 @param aSender the object that requested this 00823 @ignore 00824 */ 00825 - (void)orderBack:(id)aSender 00826 { 00827 //[_platformWindow order:CPWindowBelow 00828 } 00829 00834 - (void)orderOut:(id)aSender 00835 { 00836 #if PLATFORM(DOM) 00837 if ([self _sharesChromeWithPlatformWindow]) 00838 [_platformWindow orderOut:self]; 00839 #endif 00840 00841 if ([_delegate respondsToSelector:@selector(windowWillClose:)]) 00842 [_delegate windowWillClose:self]; 00843 00844 #if PLATFORM(DOM) 00845 [_platformWindow order:CPWindowOut window:self relativeTo:nil]; 00846 #endif 00847 00848 [self _updateMainAndKeyWindows]; 00849 } 00850 00856 - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber 00857 { 00858 #if PLATFORM(DOM) 00859 [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; 00860 #endif 00861 } 00862 00867 - (void)setLevel:(int)aLevel 00868 { 00869 if (aLevel === _level) 00870 return; 00871 00872 [_platformWindow moveWindow:self fromLevel:_level toLevel:aLevel]; 00873 00874 _level = aLevel; 00875 00876 if ([self _sharesChromeWithPlatformWindow]) 00877 [_platformWindow setLevel:aLevel]; 00878 } 00879 00883 - (int)level 00884 { 00885 return _level; 00886 } 00887 00891 - (BOOL)isVisible 00892 { 00893 return _isVisible; 00894 } 00895 00899 - (BOOL)showsResizeIndicator 00900 { 00901 return _showsResizeIndicator; 00902 } 00903 00908 - (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator 00909 { 00910 shouldShowResizeIndicator = !!shouldShowResizeIndicator; 00911 00912 if (_showsResizeIndicator === shouldShowResizeIndicator) 00913 return; 00914 00915 _showsResizeIndicator = shouldShowResizeIndicator; 00916 [_windowView setShowsResizeIndicator:[self showsResizeIndicator]]; 00917 } 00918 00922 - (CGSize)resizeIndicatorOffset 00923 { 00924 return [_windowView resizeIndicatorOffset]; 00925 } 00926 00931 - (void)setResizeIndicatorOffset:(CGSize)anOffset 00932 { 00933 [_windowView setResizeIndicatorOffset:anOffset]; 00934 } 00935 00941 - (void)setContentView:(CPView)aView 00942 { 00943 if (_contentView) 00944 [_contentView removeFromSuperview]; 00945 00946 var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); 00947 00948 // During init the initial first responder is set to the contentView 00949 // if it hasn't changed in the mean time we need to update that reference 00950 // to the new contentView 00951 if ([self initialFirstResponder] === _contentView) 00952 [self setInitialFirstResponder:aView]; 00953 00954 _contentView = aView; 00955 [_contentView setFrame:[self contentRectForFrameRect:bounds]]; 00956 00957 [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 00958 [_windowView addSubview:_contentView]; 00959 } 00960 00964 - (CPView)contentView 00965 { 00966 return _contentView; 00967 } 00968 00973 - (void)setAlphaValue:(float)aValue 00974 { 00975 [_windowView setAlphaValue:aValue]; 00976 } 00977 00981 - (float)alphaValue 00982 { 00983 return [_windowView alphaValue]; 00984 } 00985 00990 - (void)setBackgroundColor:(CPColor)aColor 00991 { 00992 [_windowView setBackgroundColor:aColor]; 00993 } 00994 00998 - (CPColor)backgroundColor 00999 { 01000 return [_windowView backgroundColor]; 01001 } 01002 01008 - (void)setMinSize:(CGSize)aSize 01009 { 01010 if (CGSizeEqualToSize(_minSize, aSize)) 01011 return; 01012 01013 _minSize = CGSizeCreateCopy(aSize); 01014 01015 var size = CGSizeMakeCopy([self frame].size), 01016 needsFrameChange = NO; 01017 01018 if (size.width < _minSize.width) 01019 { 01020 size.width = _minSize.width; 01021 needsFrameChange = YES; 01022 } 01023 01024 if (size.height < _minSize.height) 01025 { 01026 size.height = _minSize.height; 01027 needsFrameChange = YES; 01028 } 01029 01030 if (needsFrameChange) 01031 [self setFrameSize:size]; 01032 } 01033 01037 - (CGSize)minSize 01038 { 01039 return _minSize; 01040 } 01041 01048 - (void)setMaxSize:(CGSize)aSize 01049 { 01050 if (CGSizeEqualToSize(_maxSize, aSize)) 01051 return; 01052 01053 _maxSize = CGSizeCreateCopy(aSize); 01054 01055 var size = CGSizeMakeCopy([self frame].size), 01056 needsFrameChange = NO; 01057 01058 if (size.width > _maxSize.width) 01059 { 01060 size.width = _maxSize.width; 01061 needsFrameChange = YES; 01062 } 01063 01064 if (size.height > _maxSize.height) 01065 { 01066 size.height = _maxSize.height; 01067 needsFrameChange = YES; 01068 } 01069 01070 if (needsFrameChange) 01071 [self setFrameSize:size]; 01072 } 01073 01077 - (CGSize)maxSize 01078 { 01079 return _maxSize; 01080 } 01081 01085 - (BOOL)hasShadow 01086 { 01087 return _hasShadow; 01088 } 01089 01090 - (void)_updateShadow 01091 { 01092 if ([self _sharesChromeWithPlatformWindow]) 01093 { 01094 if (_shadowView) 01095 { 01096 #if PLATFORM(DOM) 01097 CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement); 01098 #endif 01099 _shadowView = nil; 01100 } 01101 01102 [_platformWindow setHasShadow:_hasShadow]; 01103 01104 return; 01105 } 01106 01107 if (_hasShadow && !_shadowView) 01108 { 01109 var bounds = [_windowView bounds]; 01110 01111 _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, 01112 SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)]; 01113 01114 if (!_CPWindowShadowColor) 01115 { 01116 var bundle = [CPBundle bundleForClass:[CPWindow class]]; 01117 01118 _CPWindowShadowColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: 01119 [ 01120 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow0.png"] size:CGSizeMake(20.0, 19.0)], 01121 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow1.png"] size:CGSizeMake(1.0, 19.0)], 01122 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow2.png"] size:CGSizeMake(19.0, 19.0)], 01123 01124 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow3.png"] size:CGSizeMake(20.0, 1.0)], 01125 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow4.png"] size:CGSizeMake(1.0, 1.0)], 01126 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow5.png"] size:CGSizeMake(19.0, 1.0)], 01127 01128 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow6.png"] size:CGSizeMake(20.0, 18.0)], 01129 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow7.png"] size:CGSizeMake(1.0, 18.0)], 01130 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow8.png"] size:CGSizeMake(19.0, 18.0)] 01131 ]]]; 01132 } 01133 01134 [_shadowView setBackgroundColor:_CPWindowShadowColor]; 01135 [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 01136 01137 #if PLATFORM(DOM) 01138 CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement); 01139 #endif 01140 } 01141 else if (!_hasShadow && _shadowView) 01142 { 01143 #if PLATFORM(DOM) 01144 CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement); 01145 #endif 01146 _shadowView = nil; 01147 } 01148 } 01149 01154 - (void)setHasShadow:(BOOL)shouldHaveShadow 01155 { 01156 if (_hasShadow === shouldHaveShadow) 01157 return; 01158 01159 _hasShadow = shouldHaveShadow; 01160 01161 [self _updateShadow]; 01162 } 01163 01175 - (void)setShadowStyle:(unsigned)aStyle 01176 { 01177 _shadowStyle = aStyle; 01178 01179 [[self platformWindow] setShadowStyle:_shadowStyle]; 01180 } 01181 01186 - (void)setDelegate:(id)aDelegate 01187 { 01188 var defaultCenter = [CPNotificationCenter defaultCenter]; 01189 01190 [defaultCenter removeObserver:_delegate name:CPWindowDidResignKeyNotification object:self]; 01191 [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeKeyNotification object:self]; 01192 [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeMainNotification object:self]; 01193 [defaultCenter removeObserver:_delegate name:CPWindowDidResignMainNotification object:self]; 01194 [defaultCenter removeObserver:_delegate name:CPWindowDidMoveNotification object:self]; 01195 [defaultCenter removeObserver:_delegate name:CPWindowDidResizeNotification object:self]; 01196 01197 _delegate = aDelegate; 01198 _delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)]; 01199 01200 if ([_delegate respondsToSelector:@selector(windowDidResignKey:)]) 01201 [defaultCenter 01202 addObserver:_delegate 01203 selector:@selector(windowDidResignKey:) 01204 name:CPWindowDidResignKeyNotification 01205 object:self]; 01206 01207 if ([_delegate respondsToSelector:@selector(windowDidBecomeKey:)]) 01208 [defaultCenter 01209 addObserver:_delegate 01210 selector:@selector(windowDidBecomeKey:) 01211 name:CPWindowDidBecomeKeyNotification 01212 object:self]; 01213 01214 if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) 01215 [defaultCenter 01216 addObserver:_delegate 01217 selector:@selector(windowDidBecomeMain:) 01218 name:CPWindowDidBecomeMainNotification 01219 object:self]; 01220 01221 if ([_delegate respondsToSelector:@selector(windowDidResignMain:)]) 01222 [defaultCenter 01223 addObserver:_delegate 01224 selector:@selector(windowDidResignMain:) 01225 name:CPWindowDidResignMainNotification 01226 object:self]; 01227 01228 if ([_delegate respondsToSelector:@selector(windowDidMove:)]) 01229 [defaultCenter 01230 addObserver:_delegate 01231 selector:@selector(windowDidMove:) 01232 name:CPWindowDidMoveNotification 01233 object:self]; 01234 01235 if ([_delegate respondsToSelector:@selector(windowDidResize:)]) 01236 [defaultCenter 01237 addObserver:_delegate 01238 selector:@selector(windowDidResize:) 01239 name:CPWindowDidResizeNotification 01240 object:self]; 01241 } 01242 01246 - (id)delegate 01247 { 01248 return _delegate; 01249 } 01250 01255 - (void)setWindowController:(CPWindowController)aWindowController 01256 { 01257 _windowController = aWindowController; 01258 } 01259 01263 - (CPWindowController)windowController 01264 { 01265 return _windowController; 01266 } 01267 01268 - (void)doCommandBySelector:(SEL)aSelector 01269 { 01270 if ([_delegate respondsToSelector:aSelector]) 01271 [_delegate performSelector:aSelector]; 01272 else 01273 [super doCommandBySelector:aSelector]; 01274 } 01275 01276 - (BOOL)acceptsFirstResponder 01277 { 01278 return NO; 01279 } 01280 01281 - (CPView)initialFirstResponder 01282 { 01283 return _initialFirstResponder; 01284 } 01285 01286 - (void)setInitialFirstResponder:(CPView)aView 01287 { 01288 _initialFirstResponder = aView; 01289 } 01290 01298 - (BOOL)makeFirstResponder:(CPResponder)aResponder 01299 { 01300 if (_firstResponder === aResponder) 01301 return YES; 01302 01303 if (![_firstResponder resignFirstResponder]) 01304 return NO; 01305 01306 if (!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder]) 01307 { 01308 _firstResponder = self; 01309 01310 return NO; 01311 } 01312 01313 _firstResponder = aResponder; 01314 01315 return YES; 01316 } 01317 01321 - (CPResponder)firstResponder 01322 { 01323 return _firstResponder; 01324 } 01325 01326 - (BOOL)acceptsMouseMovedEvents 01327 { 01328 return _acceptsMouseMovedEvents; 01329 } 01330 01331 - (void)setAcceptsMouseMovedEvents:(BOOL)shouldAcceptMouseMovedEvents 01332 { 01333 _acceptsMouseMovedEvents = shouldAcceptMouseMovedEvents; 01334 } 01335 01336 - (BOOL)ignoresMouseEvents 01337 { 01338 return _ignoresMouseEvents; 01339 } 01340 01341 - (void)setIgnoresMouseEvents:(BOOL)shouldIgnoreMouseEvents 01342 { 01343 _ignoresMouseEvents = shouldIgnoreMouseEvents; 01344 } 01345 01346 // Managing Titles 01347 01351 - (CPString)title 01352 { 01353 return _title; 01354 } 01355 01359 - (void)setTitle:(CPString)aTitle 01360 { 01361 _title = aTitle; 01362 01363 [_windowView setTitle:aTitle]; 01364 [_platformWindow _setTitle:_title window:self]; 01365 01366 [self _synchronizeMenuBarTitleWithWindowTitle]; 01367 } 01368 01372 - (void)setTitleWithRepresentedFilename:(CPString)aFilePath 01373 { 01374 [self setRepresentedFilename:aFilePath]; 01375 [self setTitle:[aFilePath lastPathComponent]]; 01376 } 01377 01381 - (void)setRepresentedFilename:(CPString)aFilePath 01382 { 01383 // FIXME: urls vs filepaths and all. 01384 [self setRepresentedURL:aFilePath]; 01385 } 01386 01390 - (CPString)representedFilename 01391 { 01392 return _representedURL; 01393 } 01394 01398 - (void)setRepresentedURL:(CPURL)aURL 01399 { 01400 _representedURL = aURL; 01401 } 01402 01406 - (CPURL)representedURL 01407 { 01408 return _representedURL; 01409 } 01410 01411 - (CPScreen)screen 01412 { 01413 return [[CPScreen alloc] init]; 01414 } 01415 01416 // Moving 01417 01422 - (void)setMovableByWindowBackground:(BOOL)shouldBeMovableByWindowBackground 01423 { 01424 _isMovableByWindowBackground = shouldBeMovableByWindowBackground; 01425 } 01426 01430 - (BOOL)isMovableByWindowBackground 01431 { 01432 return _isMovableByWindowBackground; 01433 } 01434 01439 - (void)setMovable:(BOOL)shouldBeMovable 01440 { 01441 _isMovable = shouldBeMovable; 01442 } 01443 01447 - (void)isMovable 01448 { 01449 return _isMovable; 01450 } 01451 01455 - (void)center 01456 { 01457 if (_isFullPlatformWindow) 01458 return; 01459 01460 var size = [self frame].size, 01461 containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size; 01462 01463 var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0); 01464 01465 if (origin.x < 0.0) 01466 origin.x = 0.0; 01467 01468 if (origin.y < 0.0) 01469 origin.y = 0.0; 01470 01471 [self setFrameOrigin:origin]; 01472 } 01473 01478 - (void)sendEvent:(CPEvent)anEvent 01479 { 01480 var type = [anEvent type], 01481 point = [anEvent locationInWindow]; 01482 01483 switch (type) 01484 { 01485 case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent]; 01486 01487 case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; 01488 01489 case CPKeyDown: if ([anEvent charactersIgnoringModifiers] === CPTabCharacter) 01490 { 01491 if ([anEvent modifierFlags] & CPShiftKeyMask) 01492 [self selectPreviousKeyView:self]; 01493 else 01494 [self selectNextKeyView:self]; 01495 01496 return; 01497 } 01498 else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter) 01499 return [self selectPreviousKeyView:self]; 01500 01501 [[self firstResponder] keyDown:anEvent]; 01502 01503 // Trigger the default button if needed 01504 // FIXME: Is this only applicable in a sheet? See isse: #722. 01505 if (![self disableKeyEquivalentForDefaultButton]) 01506 { 01507 var defaultButton = [self defaultButton], 01508 keyEquivalent = [defaultButton keyEquivalent], 01509 modifierMask = [defaultButton keyEquivalentModifierMask]; 01510 01511 if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask]) 01512 [[self defaultButton] performClick:self]; 01513 } 01514 01515 return; 01516 01517 case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; 01518 01519 case CPLeftMouseUp: 01520 case CPRightMouseUp: var hitTestedView = _leftMouseDownView, 01521 selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:); 01522 01523 if (!hitTestedView) 01524 hitTestedView = [_windowView hitTest:point]; 01525 01526 [hitTestedView performSelector:selector withObject:anEvent]; 01527 01528 _leftMouseDownView = nil; 01529 01530 return; 01531 case CPLeftMouseDown: 01532 case CPRightMouseDown: _leftMouseDownView = [_windowView hitTest:point]; 01533 01534 if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder]) 01535 [self makeFirstResponder:_leftMouseDownView]; 01536 01537 [CPApp activateIgnoringOtherApps:YES]; 01538 01539 var theWindow = [anEvent window], 01540 selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:); 01541 01542 if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey]) 01543 return [_leftMouseDownView performSelector:selector withObject:anEvent]; 01544 else 01545 { 01546 // FIXME: delayed ordering? 01547 [self makeKeyAndOrderFront:self]; 01548 01549 if ([_leftMouseDownView acceptsFirstMouse:anEvent]) 01550 return [_leftMouseDownView performSelector:selector withObject:anEvent]; 01551 } 01552 break; 01553 01554 case CPLeftMouseDragged: 01555 case CPRightMouseDragged: if (!_leftMouseDownView) 01556 return [[_windowView hitTest:point] mouseDragged:anEvent]; 01557 01558 var selector; 01559 if (type == CPRightMouseDragged) 01560 { 01561 selector = @selector(rightMouseDragged:) 01562 if (![_leftMouseDownView respondsToSelector:selector]) 01563 selector = nil; 01564 } 01565 01566 if (!selector) 01567 selector = @selector(mouseDragged:) 01568 01569 return [_leftMouseDownView performSelector:selector withObject:anEvent]; 01570 01571 case CPMouseMoved: if (!_acceptsMouseMovedEvents) 01572 return; 01573 01574 if (!_mouseEnteredStack) 01575 _mouseEnteredStack = []; 01576 01577 var hitTestView = [_windowView hitTest:point]; 01578 01579 if ([_mouseEnteredStack count] && [_mouseEnteredStack lastObject] === hitTestView) 01580 return [hitTestView mouseMoved:anEvent]; 01581 01582 var view = hitTestView, 01583 mouseEnteredStack = []; 01584 01585 while (view) 01586 { 01587 mouseEnteredStack.unshift(view); 01588 01589 view = [view superview]; 01590 } 01591 01592 var deviation = MIN(_mouseEnteredStack.length, mouseEnteredStack.length); 01593 01594 while (deviation--) 01595 if (_mouseEnteredStack[deviation] === mouseEnteredStack[deviation]) 01596 break; 01597 01598 var index = deviation + 1, 01599 count = _mouseEnteredStack.length; 01600 01601 if (index < count) 01602 { 01603 var event = [CPEvent mouseEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0]; 01604 01605 for (; index < count; ++index) 01606 [_mouseEnteredStack[index] mouseExited:event]; 01607 } 01608 01609 index = deviation + 1; 01610 count = mouseEnteredStack.length; 01611 01612 if (index < count) 01613 { 01614 var event = [CPEvent mouseEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0]; 01615 01616 for (; index < count; ++index) 01617 [mouseEnteredStack[index] mouseEntered:event]; 01618 } 01619 01620 _mouseEnteredStack = mouseEnteredStack; 01621 01622 [hitTestView mouseMoved:anEvent]; 01623 } 01624 } 01625 01629 - (int)windowNumber 01630 { 01631 return _windowNumber; 01632 } 01633 01638 - (void)becomeKeyWindow 01639 { 01640 CPApp._keyWindow = self; 01641 01642 if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)]) 01643 [_firstResponder becomeKeyWindow]; 01644 01645 [[CPNotificationCenter defaultCenter] 01646 postNotificationName:CPWindowDidBecomeKeyNotification 01647 object:self]; 01648 } 01649 01654 - (BOOL)canBecomeKeyWindow 01655 { 01656 return YES; 01657 } 01658 01662 - (BOOL)isKeyWindow 01663 { 01664 return [CPApp keyWindow] == self; 01665 } 01666 01671 - (void)makeKeyAndOrderFront:(id)aSender 01672 { 01673 [self orderFront:self]; 01674 01675 [self makeKeyWindow]; 01676 [self makeMainWindow]; 01677 } 01678 01682 - (void)makeKeyWindow 01683 { 01684 if ([CPApp keyWindow] === self || ![self canBecomeKeyWindow]) 01685 return; 01686 01687 [[CPApp keyWindow] resignKeyWindow]; 01688 [self becomeKeyWindow]; 01689 } 01690 01694 - (void)resignKeyWindow 01695 { 01696 if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)]) 01697 [_firstResponder resignKeyWindow]; 01698 01699 if (CPApp._keyWindow === self) 01700 CPApp._keyWindow = nil; 01701 01702 [[CPNotificationCenter defaultCenter] 01703 postNotificationName:CPWindowDidResignKeyNotification 01704 object:self]; 01705 } 01706 01717 - (void)dragImage:(CPImage)anImage at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack 01718 { 01719 [[CPDragServer sharedDragServer] dragImage:anImage fromWindow:self at:[self convertBaseToGlobal:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack]; 01720 } 01721 01722 - (void)_noteRegisteredDraggedTypes:(CPSet)pasteboardTypes 01723 { 01724 if (!pasteboardTypes) 01725 return; 01726 01727 if (!_inclusiveRegisteredDraggedTypes) 01728 _inclusiveRegisteredDraggedTypes = [CPCountedSet set]; 01729 01730 [_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes]; 01731 } 01732 01733 - (void)_noteUnregisteredDraggedTypes:(CPSet)pasteboardTypes 01734 { 01735 if (!pasteboardTypes) 01736 return; 01737 01738 [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]; 01739 01740 if ([_inclusiveRegisteredDraggedTypes count] === 0) 01741 _inclusiveRegisteredDraggedTypes = nil; 01742 } 01743 01754 - (void)dragView:(CPView)aView at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack 01755 { 01756 [[CPDragServer sharedDragServer] dragView:aView fromWindow:self at:[self convertBaseToGlobal:viewLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack]; 01757 } 01758 01763 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes 01764 { 01765 if (!pasteboardTypes) 01766 return; 01767 01768 [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; 01769 [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; 01770 [self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; 01771 01772 _registeredDraggedTypesArray = nil; 01773 } 01774 01779 - (CPArray)registeredDraggedTypes 01780 { 01781 if (!_registeredDraggedTypesArray) 01782 _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; 01783 01784 return _registeredDraggedTypesArray; 01785 } 01786 01790 - (void)unregisterDraggedTypes 01791 { 01792 [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; 01793 01794 _registeredDraggedTypes = [CPSet set]; 01795 _registeredDraggedTypesArray = []; 01796 } 01797 01798 // Accessing Editing Status 01799 01804 - (void)setDocumentEdited:(BOOL)isDocumentEdited 01805 { 01806 if (_isDocumentEdited == isDocumentEdited) 01807 return; 01808 01809 _isDocumentEdited = isDocumentEdited; 01810 01811 [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0]; 01812 01813 [_windowView setDocumentEdited:isDocumentEdited]; 01814 } 01815 01819 - (BOOL)isDocumentEdited 01820 { 01821 return _isDocumentEdited; 01822 } 01823 01824 - (void)setDocumentSaving:(BOOL)isDocumentSaving 01825 { 01826 if (_isDocumentSaving == isDocumentSaving) 01827 return; 01828 01829 _isDocumentSaving = isDocumentSaving; 01830 01831 [self _synchronizeSaveMenuWithDocumentSaving]; 01832 01833 [_windowView windowDidChangeDocumentSaving]; 01834 } 01835 01836 - (BOOL)isDocumentSaving 01837 { 01838 return _isDocumentSaving; 01839 } 01840 01841 /* @ignore */ 01842 - (void)_synchronizeSaveMenuWithDocumentSaving 01843 { 01844 if (![self isMainWindow]) 01845 return; 01846 01847 var mainMenu = [CPApp mainMenu], 01848 index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."]; 01849 01850 if (index == CPNotFound) 01851 return; 01852 01853 var item = [mainMenu itemAtIndex:index]; 01854 01855 if (_isDocumentSaving) 01856 { 01857 CPWindowSaveImage = [item image]; 01858 01859 [item setTitle:@"Saving..."]; 01860 [item setImage:CPWindowSavingImage]; 01861 [item setEnabled:NO]; 01862 } 01863 else 01864 { 01865 [item setTitle:@"Save"]; 01866 [item setImage:CPWindowSaveImage]; 01867 [item setEnabled:YES]; 01868 } 01869 } 01870 01871 // Minimizing Windows 01872 01877 - (void)performMiniaturize:(id)aSender 01878 { 01879 //FIXME show stuff 01880 [self miniaturize:aSender]; 01881 } 01882 01887 - (void)miniaturize:(id)sender 01888 { 01889 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillMiniaturizeNotification object:self]; 01890 01891 [[self platformWindow] miniaturize:sender]; 01892 01893 [self _updateMainAndKeyWindows]; 01894 01895 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self]; 01896 01897 _isMiniaturized = YES; 01898 } 01899 01903 - (void)deminiaturize:(id)sender 01904 { 01905 [[self platformWindow] deminiaturize:sender]; 01906 01907 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidDeminiaturizeNotification object:self]; 01908 01909 _isMiniaturized = NO; 01910 } 01911 01915 - (void)isMiniaturized 01916 { 01917 return _isMiniaturized; 01918 } 01919 01920 // Closing Windows 01921 01926 - (void)performClose:(id)aSender 01927 { 01928 if (!(_styleMask & CPClosableWindowMask)) 01929 return; 01930 01931 if ([self isFullBridge]) 01932 { 01933 var event = [CPApp currentEvent]; 01934 01935 if ([event type] === CPKeyDown && [event characters] === "w" && ([event modifierFlags] & CPPlatformActionKeyMask)) 01936 { 01937 [[self platformWindow] _propagateCurrentDOMEvent:YES]; 01938 return; 01939 } 01940 } 01941 01942 // Only send ONE windowShouldClose: message. 01943 if ([_delegate respondsToSelector:@selector(windowShouldClose:)]) 01944 { 01945 if (![_delegate windowShouldClose:self]) 01946 return; 01947 } 01948 01949 // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true). 01950 else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self]) 01951 return; 01952 01953 var documents = [_windowController documents]; 01954 if ([documents count]) 01955 { 01956 var index = [documents indexOfObject:[_windowController document]]; 01957 01958 [documents[index] shouldCloseWindowController:_windowController 01959 delegate:self 01960 shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) 01961 contextInfo:{documents:[documents copy], visited:0, index:index}]; 01962 } 01963 else 01964 [self close]; 01965 } 01966 01967 - (void)_windowControllerContainingDocument:(CPDocument)document shouldClose:(BOOL)shouldClose contextInfo:(Object)context 01968 { 01969 if (shouldClose) 01970 { 01971 var windowController = [self windowController], 01972 documents = context.documents, 01973 count = [documents count], 01974 visited = ++context.visited, 01975 index = ++context.index % count; 01976 01977 [document removeWindowController:windowController]; 01978 01979 if (visited < count) 01980 { 01981 [windowController setDocument:documents[index]]; 01982 01983 [documents[index] shouldCloseWindowController:_windowController 01984 delegate:self 01985 shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) 01986 contextInfo:context]; 01987 } 01988 else 01989 [self close]; 01990 } 01991 } 01992 01997 - (void)close 01998 { 01999 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillCloseNotification object:self]; 02000 02001 [self orderOut:nil]; 02002 } 02003 02004 // Managing Main Status 02008 - (BOOL)isMainWindow 02009 { 02010 return [CPApp mainWindow] == self; 02011 } 02012 02016 - (BOOL)canBecomeMainWindow 02017 { 02018 // FIXME: Also check if we can resize and titlebar. 02019 if ([self isVisible]) 02020 return YES; 02021 02022 return NO; 02023 } 02024 02028 - (void)makeMainWindow 02029 { 02030 if ([CPApp mainWindow] === self || ![self canBecomeMainWindow]) 02031 return; 02032 02033 [[CPApp mainWindow] resignMainWindow]; 02034 [self becomeMainWindow]; 02035 } 02036 02040 - (void)becomeMainWindow 02041 { 02042 CPApp._mainWindow = self; 02043 02044 [self _synchronizeMenuBarTitleWithWindowTitle]; 02045 [self _synchronizeSaveMenuWithDocumentSaving]; 02046 02047 [[CPNotificationCenter defaultCenter] 02048 postNotificationName:CPWindowDidBecomeMainNotification 02049 object:self]; 02050 } 02051 02055 - (void)resignMainWindow 02056 { 02057 [[CPNotificationCenter defaultCenter] 02058 postNotificationName:CPWindowDidResignMainNotification 02059 object:self]; 02060 02061 if (CPApp._mainWindow === self) 02062 CPApp._mainWindow = nil; 02063 } 02064 02065 - (void)_updateMainAndKeyWindows 02066 { 02067 var allWindows = [CPApp orderedWindows], 02068 windowCount = [allWindows count]; 02069 02070 if ([self isKeyWindow]) 02071 { 02072 var keyWindow = [CPApp keyWindow]; 02073 [self resignKeyWindow]; 02074 02075 if (keyWindow && keyWindow !== self && [keyWindow canBecomeKeyWindow]) 02076 [keyWindow makeKeyWindow]; 02077 else 02078 { 02079 var mainMenu = [CPApp mainMenu], 02080 menuBarClass = objj_getClass("_CPMenuBarWindow"), 02081 menuWindow; 02082 02083 for (var i = 0; i < windowCount; i++) 02084 { 02085 var currentWindow = allWindows[i]; 02086 02087 if ([currentWindow isKindOfClass:menuBarClass]) 02088 menuWindow = currentWindow; 02089 02090 if (currentWindow === self || currentWindow === menuWindow) 02091 continue; 02092 02093 if ([currentWindow isVisible] && [currentWindow canBecomeKeyWindow]) 02094 { 02095 [currentWindow makeKeyWindow]; 02096 break; 02097 } 02098 } 02099 02100 if (![CPApp keyWindow]) 02101 [menuWindow makeKeyWindow]; 02102 } 02103 } 02104 02105 if ([self isMainWindow]) 02106 { 02107 var mainWindow = [CPApp mainWindow]; 02108 [self resignMainWindow]; 02109 02110 if (mainWindow && mainWindow !== self && [mainWindow canBecomeMainWindow]) 02111 [mainWindow makeMainWindow]; 02112 else 02113 { 02114 var mainMenu = [CPApp mainMenu], 02115 menuBarClass = objj_getClass("_CPMenuBarWindow"), 02116 menuWindow; 02117 02118 for (var i = 0; i < windowCount; i++) 02119 { 02120 var currentWindow = allWindows[i]; 02121 02122 if ([currentWindow isKindOfClass:menuBarClass]) 02123 menuWindow = currentWindow; 02124 02125 if (currentWindow === self || currentWindow === menuWindow) 02126 continue; 02127 02128 if ([currentWindow isVisible] && [currentWindow canBecomeMainWindow]) 02129 { 02130 [currentWindow makeMainWindow]; 02131 break; 02132 } 02133 } 02134 } 02135 } 02136 } 02137 02138 // Managing Toolbars 02142 - (CPToolbar)toolbar 02143 { 02144 return _toolbar; 02145 } 02146 02151 - (void)setToolbar:(CPToolbar)aToolbar 02152 { 02153 if (_toolbar === aToolbar) 02154 return; 02155 02156 // If this has an owner, dump it! 02157 [[aToolbar _window] setToolbar:nil]; 02158 02159 // This is no longer out toolbar. 02160 [_toolbar _setWindow:nil]; 02161 02162 _toolbar = aToolbar; 02163 02164 // THIS is our toolbar. 02165 [_toolbar _setWindow:self]; 02166 02167 [self _noteToolbarChanged]; 02168 } 02169 02170 - (void)toggleToolbarShown:(id)aSender 02171 { 02172 var toolbar = [self toolbar]; 02173 02174 [toolbar setVisible:![toolbar isVisible]]; 02175 } 02176 02177 - (void)_noteToolbarChanged 02178 { 02179 var frame = CGRectMakeCopy([self frame]), 02180 newFrame; 02181 02182 [_windowView noteToolbarChanged]; 02183 02184 if (_isFullPlatformWindow) 02185 newFrame = [_platformWindow visibleFrame]; 02186 else 02187 { 02188 newFrame = CGRectMakeCopy([self frame]); 02189 02190 newFrame.origin = frame.origin; 02191 } 02192 02193 [self setFrame:newFrame]; 02194 /* 02195 [_windowView setAnimatingToolbar:YES]; 02196 [self setFrame:frame]; 02197 [self setFrame:newFrame display:YES animate:YES]; 02198 [_windowView setAnimatingToolbar:NO]; 02199 */ 02200 } 02201 02202 - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve 02203 { 02204 [_frameAnimation stopAnimation]; 02205 _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; 02206 [_frameAnimation setDelegate:delegate]; 02207 [_frameAnimation setAnimationCurve:curve]; 02208 [_frameAnimation setDuration:duration]; 02209 [_frameAnimation startAnimation]; 02210 } 02211 02212 - (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame 02213 { 02214 return CPWindowResizeTime; 02215 } 02216 02217 /* @ignore */ 02218 - (void)_setAttachedSheetFrameOrigin 02219 { 02220 // Position the sheet above the contentRect. 02221 var attachedSheet = [self attachedSheet]; 02222 var contentRect = [[self contentView] frame], 02223 sheetFrame = CGRectMakeCopy([attachedSheet frame]); 02224 02225 sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); 02226 sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); 02227 02228 [attachedSheet setFrame:sheetFrame display:YES animate:NO]; 02229 } 02230 02231 /* @ignore */ 02232 - (void)_attachSheet:(CPWindow)aSheet modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo 02233 { 02234 var sheetFrame = [aSheet frame]; 02235 02236 _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; 02237 02238 [self _attachSheetWindow:aSheet]; 02239 } 02240 02241 /* @ignore */ 02242 - (void)_attachSheetWindow:(CPWindow)aSheet 02243 { 02244 var sheetFrame = [aSheet frame], 02245 frame = [self frame], 02246 sheetContent = [aSheet contentView]; 02247 02248 [self _setUpMasksForView:sheetContent]; 02249 02250 aSheet._isSheet = YES; 02251 aSheet._parentView = self; 02252 02253 var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2), 02254 originy = frame.origin.y + [[self contentView] frame].origin.y, 02255 startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), 02256 endFrame = CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height); 02257 02258 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; 02259 [CPApp runModalForWindow:aSheet]; 02260 02261 [aSheet orderFront:self]; 02262 [aSheet setFrame:startFrame display:YES animate:NO]; 02263 _sheetContext["opened"] = YES; 02264 02265 [aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut]; 02266 02267 // Should run the main loop here until _isAnimating = FALSE 02268 [aSheet becomeKeyWindow]; 02269 } 02270 02271 /* @ignore */ 02272 - (void)_detachSheetWindow 02273 { 02274 var sheet = [self attachedSheet], 02275 startFrame = [sheet frame], 02276 endFrame = CGRectMakeCopy(startFrame); 02277 02278 endFrame.size.height = 0; 02279 02280 _sheetContext["frame"] = startFrame; 02281 02282 var sheetContent = [sheet contentView]; 02283 [self _setUpMasksForView:sheetContent]; 02284 02285 _sheetContext["opened"] = NO; 02286 [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn]; 02287 } 02288 02289 /* @ignore */ 02290 - (void)animationDidEnd:(id)anim 02291 { 02292 var sheet = _sheetContext["sheet"]; 02293 if (anim._window != sheet) 02294 return; 02295 02296 var sheetContent = [sheet contentView]; 02297 02298 if (_sheetContext["opened"] === YES) 02299 { 02300 [self _restoreMasksForView:sheetContent]; 02301 return; 02302 } 02303 02304 [CPApp stopModal]; 02305 [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; 02306 02307 [sheet orderOut:self]; 02308 02309 var lastFrame = _sheetContext["frame"]; 02310 [sheet setFrame:lastFrame]; 02311 02312 [self _restoreMasksForView:sheetContent]; 02313 02314 var delegate = _sheetContext["modalDelegate"], 02315 endSelector = _sheetContext["endSelector"], 02316 returnCode = _sheetContext["returnCode"], 02317 contextInfo = _sheetContext["contextInfo"]; 02318 02319 _sheetContext = nil; 02320 sheet._parentView = nil; 02321 02322 if (delegate != nil && endSelector != nil) 02323 objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo); 02324 } 02325 02326 - (void)_setUpMasksForView:(CPView)aView 02327 { 02328 var views = [aView subviews]; 02329 02330 [views addObject:aView]; 02331 02332 for (var i = 0, count = [views count]; i < count; i++) 02333 { 02334 var view = [views objectAtIndex:i], 02335 mask = [view autoresizingMask], 02336 maskToAdd = (mask & CPViewMinYMargin) ? 128 : CPViewMinYMargin; 02337 02338 [view setAutoresizingMask:(mask | maskToAdd)]; 02339 } 02340 } 02341 02342 - (void)_restoreMasksForView:(CPView)aView 02343 { 02344 var views = [aView subviews]; 02345 02346 [views addObject:aView]; 02347 02348 for (var i = 0, count = [views count]; i < count; i++) 02349 { 02350 var view = [views objectAtIndex:i], 02351 mask = [view autoresizingMask], 02352 maskToRemove = (mask & 128) ? 128 : CPViewMinYMargin; 02353 02354 [view setAutoresizingMask:(mask & (~ maskToRemove))]; 02355 } 02356 } 02357 02361 - (CPWindow)attachedSheet 02362 { 02363 if (_sheetContext === nil) 02364 return nil; 02365 02366 return _sheetContext["sheet"]; 02367 } 02368 02372 - (BOOL)isSheet 02373 { 02374 return _isSheet; 02375 } 02376 02377 // 02378 /* 02379 Used privately. 02380 @ignore 02381 */ 02382 - (BOOL)becomesKeyOnlyIfNeeded 02383 { 02384 return NO; 02385 } 02386 02391 - (BOOL)worksWhenModal 02392 { 02393 return NO; 02394 } 02395 02396 - (BOOL)performKeyEquivalent:(CPEvent)anEvent 02397 { 02398 // FIXME: should we be starting at the root, in other words _windowView? 02399 // The evidence seems to point to no... 02400 return [[self contentView] performKeyEquivalent:anEvent]; 02401 } 02402 02403 - (void)keyDown:(CPEvent)anEvent 02404 { 02405 // It's not clear why we do performKeyEquivalent again here... 02406 // Perhaps to allow something to happen between sendEvent: and keyDown:? 02407 if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) 02408 return; 02409 02410 // Apple's documentation is inconsistent with their behavior here. According to the docs 02411 // an event going of the responder chain is passed to the input system as a last resort. 02412 // However, the only methods I could get Cocoa to call automatically are 02413 // moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete: 02414 // Unhandled events just travel further up the responder chain _past_ the window. 02415 if (![self _processKeyboardUIKey:anEvent]) 02416 [super keyDown:anEvent]; 02417 } 02418 02419 /* 02420 @ignore 02421 Interprets the key event for action messages and sends the action message down the responder chain 02422 Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages. 02423 We deviate from this by sending (the default) scrollPageUp:, scrollPageDown:, scrollToBeginningOfDocument: and scrollToEndOfDocument: for pageUp, pageDown, home and end keys. 02424 @param anEvent the event to handle. 02425 @return YES if the key event was handled, NO if no responder handled the key event 02426 */ 02427 - (BOOL)_processKeyboardUIKey:(CPEvent)anEvent 02428 { 02429 var character = [anEvent charactersIgnoringModifiers]; 02430 02431 if (![CPWindowActionMessageKeys containsObject:character]) 02432 return NO; 02433 02434 var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0]; 02435 02436 if ([selectors count] <= 0) 02437 return NO; 02438 02439 if (character !== CPEscapeFunctionKey) 02440 { 02441 var selector = [selectors objectAtIndex:0]; 02442 return [[self firstResponder] tryToPerform:selector with:self]; 02443 } 02444 else 02445 { 02446 // Cocoa sends complete: for the escape key (in stead of the default cancelOperation:) 02447 // This is also the only action that is not sent directly to the first responder, but through doCommandBySelector. 02448 // The difference is that doCommandBySelector: will also send the action to the window and application delegates. 02449 [[self firstResponder] doCommandBySelector:@selector(complete:)]; 02450 } 02451 02452 return NO; 02453 } 02454 02455 - (void)_dirtyKeyViewLoop 02456 { 02457 if (_autorecalculatesKeyViewLoop) 02458 _keyViewLoopIsDirty = YES; 02459 } 02460 02461 - (BOOL)_hasKeyViewLoop 02462 { 02463 var views = allViews(self), 02464 index = [views count]; 02465 02466 while (index--) 02467 if ([views[index] nextKeyView]) 02468 return YES; 02469 02470 return NO; 02471 } 02472 02473 - (void)recalculateKeyViewLoop 02474 { 02475 var views = allViews(self); 02476 02477 [views sortUsingFunction:keyViewComparator context:nil]; 02478 02479 var index = 0, 02480 count = [views count]; 02481 02482 for (; index < count; ++index) 02483 [views[index] setNextKeyView:views[(index + 1) % count]]; 02484 02485 _keyViewLoopIsDirty = NO; 02486 } 02487 02488 - (void)setAutorecalculatesKeyViewLoop:(BOOL)shouldRecalculate 02489 { 02490 if (_autorecalculatesKeyViewLoop === shouldRecalculate) 02491 return; 02492 02493 _autorecalculatesKeyViewLoop = shouldRecalculate; 02494 02495 if (_keyViewLoopIsDirty) 02496 [self recalculateKeyViewLoop]; 02497 else if (_autorecalculatesKeyViewLoop) 02498 [self _dirtyKeyViewLoop]; 02499 } 02500 02501 - (BOOL)autorecalculatesKeyViewLoop 02502 { 02503 return _autorecalculatesKeyViewLoop; 02504 } 02505 02506 - (void)selectNextKeyView:(id)sender 02507 { 02508 if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop]) 02509 [self recalculateKeyViewLoop]; 02510 02511 var nextValidKeyView = nil; 02512 02513 if ([_firstResponder isKindOfClass:[CPView class]]) 02514 nextValidKeyView = [_firstResponder nextValidKeyView]; 02515 02516 if (!nextValidKeyView) 02517 { 02518 var initialFirstResponder = [self initialFirstResponder]; 02519 02520 if ([initialFirstResponder acceptsFirstResponder]) 02521 nextValidKeyView = initialFirstResponder; 02522 else 02523 nextValidKeyView = [initialFirstResponder nextValidKeyView]; 02524 } 02525 02526 [self makeFirstResponder:nextValidKeyView]; 02527 } 02528 02529 - (void)selectPreviousKeyView:(id)sender 02530 { 02531 if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop]) 02532 [self recalculateKeyViewLoop]; 02533 02534 var previousValidKeyView = nil; 02535 02536 if ([_firstResponder isKindOfClass:[CPView class]]) 02537 previousValidKeyView = [_firstResponder previousValidKeyView]; 02538 02539 if (!previousValidKeyView) 02540 { 02541 var initialFirstResponder = [self initialFirstResponder]; 02542 02543 if ([initialFirstResponder acceptsFirstResponder]) 02544 previousValidKeyView = initialFirstResponder; 02545 else 02546 previousValidKeyView = [initialFirstResponder previousValidKeyView]; 02547 } 02548 02549 [self makeFirstResponder:previousValidKeyView]; 02550 } 02551 02552 - (void)selectKeyViewFollowingView:(CPView)aView 02553 { 02554 if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop]) 02555 [self recalculateKeyViewLoop]; 02556 02557 var nextValidKeyView = [aView nextValidKeyView]; 02558 02559 if ([nextValidKeyView isKindOfClass:[CPView class]]) 02560 [self makeFirstResponder:nextValidKeyView]; 02561 } 02562 02563 - (void)selectKeyViewPrecedingView:(CPView)aView 02564 { 02565 if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop]) 02566 [self recalculateKeyViewLoop]; 02567 02568 var previousValidKeyView = [aView previousValidKeyView]; 02569 02570 if ([previousValidKeyView isKindOfClass:[CPView class]]) 02571 [self makeFirstResponder:previousValidKeyView]; 02572 } 02573 02579 - (void)setDefaultButtonCell:(CPButton)aButton 02580 { 02581 [self setDefaultButton:aButton]; 02582 } 02583 02588 - (CPButton)defaultButtonCell 02589 { 02590 return [self defaultButton]; 02591 } 02592 02599 - (void)setDefaultButton:(CPButton)aButton 02600 { 02601 if (_defaultButton === aButton) 02602 return; 02603 02604 if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter) 02605 [_defaultButton setKeyEquivalent:nil]; 02606 02607 _defaultButton = aButton; 02608 02609 if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter) 02610 [_defaultButton setKeyEquivalent:CPCarriageReturnCharacter]; 02611 } 02612 02616 - (CPButton)defaultButton 02617 { 02618 return _defaultButton; 02619 } 02620 02624 - (void)enableKeyEquivalentForDefaultButton 02625 { 02626 _defaultButtonEnabled = YES; 02627 } 02628 02633 - (void)enableKeyEquivalentForDefaultButtonCell 02634 { 02635 [self enableKeyEquivalentForDefaultButton]; 02636 } 02637 02641 - (void)disableKeyEquivalentForDefaultButton 02642 { 02643 _defaultButtonEnabled = NO; 02644 } 02645 02650 - (void)disableKeyEquivalentForDefaultButtonCell 02651 { 02652 [self disableKeyEquivalentForDefaultButton]; 02653 } 02654 02655 @end 02656 02657 var allViews = function(aWindow) 02658 { 02659 var views = [CPArray arrayWithObject:[aWindow contentView]]; 02660 02661 [views addObjectsFromArray:[[aWindow contentView] subviews]]; 02662 02663 var index = 0; 02664 for (; index < views.length; ++index) 02665 views = views.concat([views[index] subviews]); 02666 02667 return views; 02668 } 02669 02670 var keyViewComparator = function(lhs, rhs, context) 02671 { 02672 var lhsBounds = [lhs convertRect:[lhs bounds] toView:nil], 02673 rhsBounds = [rhs convertRect:[rhs bounds] toView:nil], 02674 lhsY = _CGRectGetMinY(lhsBounds), 02675 rhsY = _CGRectGetMinY(rhsBounds), 02676 lhsX = _CGRectGetMinX(lhsBounds), 02677 rhsX = _CGRectGetMinX(rhsBounds), 02678 intersectsVertically = MIN(_CGRectGetMaxY(lhsBounds), _CGRectGetMaxY(rhsBounds)) - MAX(lhsY, rhsY); 02679 02680 // If two views are "on the same line" (intersect vertically), then rely on the x comparison. 02681 if (intersectsVertically > 0) 02682 { 02683 if (lhsX < rhsX) 02684 return CPOrderedAscending; 02685 02686 if (lhsX === rhsX) 02687 return CPOrderedSame; 02688 02689 return CPOrderedDescending; 02690 } 02691 02692 if (lhsY < rhsY) 02693 return CPOrderedAscending; 02694 02695 if (lhsY === rhsY) 02696 return CPOrderedSame; 02697 02698 return CPOrderedDescending; 02699 } 02700 02701 @implementation CPWindow (MenuBar) 02702 02703 - (void)_synchronizeMenuBarTitleWithWindowTitle 02704 { 02705 // Windows with Documents automatically update the native window title and the menu bar title. 02706 if (![_windowController document] || ![self isMainWindow]) 02707 return; 02708 02709 [CPMenu setMenuBarTitle:_title]; 02710 } 02711 02712 @end 02713 02714 @implementation CPWindow (BridgeSupport) 02715 02716 /* 02717 @ignore 02718 */ 02719 - (void)resizeWithOldPlatformWindowSize:(CGSize)aSize 02720 { 02721 if ([self isFullPlatformWindow]) 02722 return [self setFrame:[_platformWindow visibleFrame]]; 02723 02724 if (_autoresizingMask == CPWindowNotSizable) 02725 return; 02726 02727 var frame = [_platformWindow contentBounds], 02728 newFrame = CGRectMakeCopy(_frame), 02729 dX = (CGRectGetWidth(frame) - aSize.width) / 02730 (((_autoresizingMask & CPWindowMinXMargin) ? 1 : 0) + (_autoresizingMask & CPWindowWidthSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxXMargin ? 1 : 0)), 02731 dY = (CGRectGetHeight(frame) - aSize.height) / 02732 ((_autoresizingMask & CPWindowMinYMargin ? 1 : 0) + (_autoresizingMask & CPWindowHeightSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxYMargin ? 1 : 0)); 02733 02734 if (_autoresizingMask & CPWindowMinXMargin) 02735 newFrame.origin.x += dX; 02736 if (_autoresizingMask & CPWindowWidthSizable) 02737 newFrame.size.width += dX; 02738 02739 if (_autoresizingMask & CPWindowMinYMargin) 02740 newFrame.origin.y += dY; 02741 if (_autoresizingMask & CPWindowHeightSizable) 02742 newFrame.size.height += dY; 02743 02744 [self setFrame:newFrame]; 02745 } 02746 02747 /* 02748 @ignore 02749 */ 02750 - (void)setAutoresizingMask:(unsigned)anAutoresizingMask 02751 { 02752 _autoresizingMask = anAutoresizingMask; 02753 } 02754 02755 /* 02756 @ignore 02757 */ 02758 - (unsigned)autoresizingMask 02759 { 02760 return _autoresizingMask; 02761 } 02762 02766 - (CGPoint)convertBaseToGlobal:(CGPoint)aPoint 02767 { 02768 return [CPPlatform isBrowser] ? [self convertBaseToPlatformWindow:aPoint] : [self convertBaseToScreen:aPoint]; 02769 } 02770 02774 - (CGPoint)convertGlobalToBase:(CGPoint)aPoint 02775 { 02776 return [CPPlatform isBrowser] ? [self convertPlatformWindowToBase:aPoint] : [self convertScreenToBase:aPoint]; 02777 } 02778 02782 - (CGPoint)convertBaseToPlatformWindow:(CGPoint)aPoint 02783 { 02784 if ([self _sharesChromeWithPlatformWindow]) 02785 return aPoint; 02786 02787 var origin = [self frame].origin; 02788 02789 return _CGPointMake(aPoint.x + origin.x, aPoint.y + origin.y); 02790 } 02791 02795 - (CGPoint)convertPlatformWindowToBase:(CGPoint)aPoint 02796 { 02797 if ([self _sharesChromeWithPlatformWindow]) 02798 return aPoint; 02799 02800 var origin = [self frame].origin; 02801 02802 return _CGPointMake(aPoint.x - origin.x, aPoint.y - origin.y); 02803 } 02804 02805 - (CGPoint)convertScreenToBase:(CGPoint)aPoint 02806 { 02807 return [self convertPlatformWindowToBase:[_platformWindow convertScreenToBase:aPoint]]; 02808 } 02809 02810 - (CGPoint)convertBaseToScreen:(CGPoint)aPoint 02811 { 02812 return [_platformWindow convertBaseToScreen:[self convertBaseToPlatformWindow:aPoint]]; 02813 } 02814 02815 - (void)_setSharesChromeWithPlatformWindow:(BOOL)shouldShareFrameWithPlatformWindow 02816 { 02817 // We canna' do it captain! We just don't have the power! 02818 if (shouldShareFrameWithPlatformWindow && [CPPlatform isBrowser]) 02819 return; 02820 02821 _sharesChromeWithPlatformWindow = shouldShareFrameWithPlatformWindow; 02822 02823 [self _updateShadow]; 02824 } 02825 02826 - (BOOL)_sharesChromeWithPlatformWindow 02827 { 02828 return _sharesChromeWithPlatformWindow; 02829 } 02830 02831 // Undo and Redo Support 02835 - (CPUndoManager)undoManager 02836 { 02837 // If we've ever created an undo manager, return it. 02838 if (_undoManager) 02839 return _undoManager; 02840 02841 // If not, check to see if the document has one. 02842 var documentUndoManager = [[_windowController document] undoManager]; 02843 02844 if (documentUndoManager) 02845 return documentUndoManager; 02846 02847 // If not, check to see if the delegate has one. 02848 if (_delegateRespondsToWindowWillReturnUndoManagerSelector) 02849 return [_delegate windowWillReturnUndoManager:self]; 02850 02851 // If not, create one. 02852 if (!_undoManager) 02853 _undoManager = [[CPUndoManager alloc] init]; 02854 02855 return _undoManager; 02856 } 02857 02862 - (void)undo:(id)aSender 02863 { 02864 [[self undoManager] undo]; 02865 } 02866 02871 - (void)redo:(id)aSender 02872 { 02873 [[self undoManager] redo]; 02874 } 02875 02876 - (BOOL)containsPoint:(CGPoint)aPoint 02877 { 02878 return CGRectContainsPoint(_frame, aPoint); 02879 } 02880 02881 @end 02882 02883 @implementation CPWindow (Deprecated) 02888 - (void)setFullBridge:(BOOL)shouldBeFullBridge 02889 { 02890 [self setFullPlatformWindow:shouldBeFullBridge]; 02891 } 02892 02897 - (BOOL)isFullBridge 02898 { 02899 return [self isFullPlatformWindow]; 02900 } 02901 02902 /* 02903 @ignore 02904 */ 02905 - (CGPoint)convertBaseToBridge:(CGPoint)aPoint 02906 { 02907 return [self convertBaseToPlatformWindow:aPoint]; 02908 } 02909 02910 /* 02911 @ignore 02912 */ 02913 - (CGPoint)convertBridgeToBase:(CGPoint)aPoint 02914 { 02915 return [self convertPlatformWindowToBase:aPoint]; 02916 } 02917 02918 @end 02919 02920 var interpolate = function(fromValue, toValue, progress) 02921 { 02922 return fromValue + (toValue - fromValue) * progress; 02923 } 02924 02925 /* @ignore */ 02926 @implementation _CPWindowFrameAnimation : CPAnimation 02927 { 02928 CPWindow _window; 02929 02930 CGRect _startFrame; 02931 CGRect _targetFrame; 02932 } 02933 02934 - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame 02935 { 02936 self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear]; 02937 02938 if (self) 02939 { 02940 _window = aWindow; 02941 02942 _targetFrame = CGRectMakeCopy(aTargetFrame); 02943 _startFrame = CGRectMakeCopy([_window frame]); 02944 } 02945 02946 return self; 02947 } 02948 02949 - (void)startAnimation 02950 { 02951 [super startAnimation]; 02952 02953 _window._isAnimating = YES; 02954 } 02955 02956 - (void)setCurrentProgress:(float)aProgress 02957 { 02958 [super setCurrentProgress:aProgress]; 02959 02960 var value = [self currentValue]; 02961 02962 if (value == 1.0) 02963 _window._isAnimating = NO; 02964 02965 var newFrame = CGRectMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value), 02966 interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value), 02967 interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value), 02968 interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value)); 02969 02970 [_window setFrame:newFrame display:YES animate:NO]; 02971 } 02972 02973 @end 02974 02975 function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasShadow, aLevel) 02976 { 02977 return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel }; 02978 } 02979 02980 CPStandardWindowShadowStyle = 0; 02981 CPMenuWindowShadowStyle = 1; 02982 CPPanelWindowShadowStyle = 2; 02983 CPCustomWindowShadowStyle = 3; 02984 02985