API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPWindow.j
Go to the documentation of this file.
1 /*
2  * CPWindow.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 /*
27  Borderless window mask option.
28  @global
29  @class CPWindow
30 */
32 /*
33  Titled window mask option.
34  @global
35  @class CPWindow
36 */
38 /*
39  Closeable window mask option.
40  @global
41  @class CPWindow
42 */
44 /*
45  Miniaturizabe window mask option.
46  @global
47  @class CPWindow
48 */
50 /*
51  Resizable window mask option.
52  @global
53  @class CPWindow
54 */
56 /*
57  Textured window mask option.
58  @global
59  @class CPWindow
60 */
62 /*
63  @global
64  @class CPWindow
65 */
67 /*
68  @global
69  @class CPWindow
70 */
72 
80 
82 /*
83  Default level for windows
84  @group CPWindowLevel
85  @global
86 */
88 /*
89  Floating palette type window
90  @group CPWindowLevel
91  @global
92 */
94 /*
95  Submenu type window
96  @group CPWindowLevel
97  @global
98 */
100 /*
101  For a torn-off menu
102  @group CPWindowLevel
103  @global
104 */
106 /*
107  For the application's main menu
108  @group CPWindowLevel
109  @global
110 */
112 /*
113  Status window level
114  @group CPWindowLevel
115  @global
116 */
118 /*
119  Level for a modal panel
120  @group CPWindowLevel
121  @global
122 */
124 /*
125  Level for a pop up menu
126  @group CPWindowLevel
127  @global
128 */
130 /*
131  Level for a window being dragged
132  @group CPWindowLevel
133  @global
134 */
136 /*
137  Level for the screens saver
138  @group CPWindowLevel
139  @global
140 */
142 
143 /*
144  The receiver is removed from the screen list and hidden.
145  @global
146  @class CPWindowOrderingMode
147 */
149 /*
150  The receiver is placed directly in front of the window specified.
151  @global
152  @class CPWindowOrderingMode
153 */
155 /*
156  The receiver is placed directly behind the window specified.
157  @global
158  @class CPWindowOrderingMode
159 */
161 
162 CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
163 CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
164 CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
165 CPWindowDidBecomeKeyNotification = @"CPWindowDidBecomeKeyNotification";
166 CPWindowDidResignKeyNotification = @"CPWindowDidResignKeyNotification";
167 CPWindowDidResizeNotification = @"CPWindowDidResizeNotification";
168 CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
169 CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
170 CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
171 CPWindowDidMiniaturizeNotification = @"CPWindowDidMiniaturizeNotification";
172 CPWindowWillMiniaturizeNotification = @"CPWindowWillMiniaturizeNotification";
173 CPWindowDidDeminiaturizeNotification = @"CPWindowDidDeminiaturizeNotification";
174 
175 _CPWindowDidChangeFirstResponderNotification = @"_CPWindowDidChangeFirstResponderNotification";
176 
180 
185 
191 
192  _CPWindowShadowColor = nil;
193 
196 
198  CPWindowResizeStyleGlobalChangeNotification = @"CPWindowResizeStyleGlobalChangeNotification";
199 
200 /*
201  Keys for which action messages will be sent by default when unhandled, e.g. complete:.
202 */
213  ];
214 
271 @implementation CPWindow : CPResponder
272 {
273  CPPlatformWindow _platformWindow;
274 
275  int _windowNumber;
276  unsigned _styleMask;
277  CGRect _frame;
278  int _level;
279  BOOL _isVisible;
280  BOOL _isMiniaturized;
281  BOOL _isAnimating;
282  BOOL _hasShadow;
283  BOOL _isMovableByWindowBackground;
284  BOOL _isMovable;
285  unsigned _shadowStyle;
286  BOOL _showsResizeIndicator;
287 
288  int _positioningMask;
289  CGRect _positioningScreenRect;
290 
291  BOOL _isDocumentEdited;
292  BOOL _isDocumentSaving;
293 
294  CPImageView _shadowView;
295 
296  CPView _windowView;
297  CPView _contentView;
298  CPView _toolbarView;
299 
300  CPArray _mouseEnteredStack;
301  CPView _leftMouseDownView;
302  CPView _rightMouseDownView;
303 
304  CPToolbar _toolbar;
305  CPResponder _firstResponder;
306  CPResponder _initialFirstResponder;
307  BOOL _hasBecomeKeyWindow;
308  id _delegate;
309 
310  CPString _title;
311 
312  BOOL _acceptsMouseMovedEvents;
313  BOOL _ignoresMouseEvents;
314 
315  CPWindowController _windowController;
316 
317  CGSize _minSize;
318  CGSize _maxSize;
319 
320  CPUndoManager _undoManager;
321  CPURL _representedURL;
322 
323  CPSet _registeredDraggedTypes;
324  CPArray _registeredDraggedTypesArray;
325  CPCountedSet _inclusiveRegisteredDraggedTypes;
326 
327  CPButton _defaultButton;
328  BOOL _defaultButtonEnabled;
329 
330  BOOL _autorecalculatesKeyViewLoop;
331  BOOL _keyViewLoopIsDirty;
332 
333  BOOL _sharesChromeWithPlatformWindow;
334 
335  // Bridge Support
336 #if PLATFORM(DOM)
337  DOMElement _DOMElement;
338 #endif
339 
340  unsigned _autoresizingMask;
341 
342  BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
343 
344  BOOL _isFullPlatformWindow;
345  _CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
346 
347  CPDictionary _sheetContext;
348  CPWindow _parentView;
349  BOOL _isSheet;
350  _CPWindowFrameAnimation _frameAnimation;
351 }
352 
353 /*
354  Private initializer for Objective-J
355  @ignore
356 */
357 + (void)initialize
358 {
359  if (self !== [CPWindow class])
360  return;
361 
362  var bundle = [CPBundle bundleForClass:[CPWindow class]];
363 
364  CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:_CGSizeMake(16.0, 16.0)]
365 }
366 
367 - (id)init
368 {
369  return [self initWithContentRect:_CGRectMakeZero() styleMask:CPTitledWindowMask];
370 }
371 
387 - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
388 {
389  self = [super init];
390 
391  if (self)
392  {
393  var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
394 
395  _frame = [windowViewClass frameRectForContentRect:aContentRect];
396 
397  [self _setSharesChromeWithPlatformWindow:![CPPlatform isBrowser]];
398 
399  if ([CPPlatform isBrowser])
401  else
402  {
403  // give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
404  if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
405  {
406  var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
407  _frame.size.height = MIN(768.0, visibleFrame.size.height);
408  _frame.size.width = MIN(1024.0, visibleFrame.size.width);
409  _frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
410  _frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
411  }
413  [self platformWindow]._only = self;
414  }
415 
416  _isFullPlatformWindow = NO;
417  _registeredDraggedTypes = [CPSet set];
418  _registeredDraggedTypesArray = [];
419  _acceptsMouseMovedEvents = YES;
420  _isMovable = YES;
421 
422  _isSheet = NO;
423  _sheetContext = nil;
424  _parentView = nil;
425 
426  // Set up our window number.
427  _windowNumber = [CPApp._windows count];
428  CPApp._windows[_windowNumber] = self;
429 
430  _styleMask = aStyleMask;
431 
432  [self setLevel:CPNormalWindowLevel];
433 
434  _minSize = _CGSizeMake(0.0, 0.0);
435  _maxSize = _CGSizeMake(1000000.0, 1000000.0);
436 
437  // Create our border view which is the actual root of our view hierarchy.
438  _windowView = [[windowViewClass alloc] initWithFrame:_CGRectMake(0.0, 0.0, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) styleMask:aStyleMask];
439 
440  [_windowView _setWindow:self];
441  [_windowView setNextResponder:self];
442 
443  [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
444 
445  // Create a generic content view.
446  [self setContentView:[[CPView alloc] initWithFrame:_CGRectMakeZero()]];
447 
448  _firstResponder = self;
449 
450 #if PLATFORM(DOM)
451  _DOMElement = document.createElement("div");
452 
453  _DOMElement.style.position = "absolute";
454  _DOMElement.style.visibility = "visible";
455  _DOMElement.style.zIndex = 0;
456 
457  if (![self _sharesChromeWithPlatformWindow])
458  {
459  CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame));
460  }
461 
462  CPDOMDisplayServerSetStyleSize(_DOMElement, 1, 1);
463  CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement);
464 #endif
465 
466  [self setNextResponder:CPApp];
467 
468  [self setHasShadow:aStyleMask !== CPBorderlessWindowMask];
469 
470  if (aStyleMask & CPBorderlessBridgeWindowMask)
471  [self setFullPlatformWindow:YES];
472 
473  _autorecalculatesKeyViewLoop = NO;
474  _defaultButtonEnabled = YES;
475  _keyViewLoopIsDirty = NO;
476  _hasBecomeKeyWindow = NO;
477 
478  [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
479 
482  name:CPWindowResizeStyleGlobalChangeNotification
483  object:nil];
484  }
485 
486  return self;
487 }
488 
489 - (CPPlatformWindow)platformWindow
490 {
491  return _platformWindow;
492 }
493 
499 - (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow
500 {
501  var wasVisible = [self isVisible];
502 
503  // we have to close it first, otherwise we get a DOM exception.
504  if (wasVisible)
505  [self close];
506 
507  _platformWindow = aPlatformWindow;
508  [_platformWindow _setTitle:_title window:self];
509 
510  if (wasVisible)
511  [self orderFront:self];
512 }
513 
514 
518 + (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask
519 {
520  if (aStyleMask & CPHUDBackgroundWindowMask)
521  return _CPHUDWindowView;
522 
523  else if (aStyleMask === CPBorderlessWindowMask)
524  return _CPBorderlessWindowView;
525 
526  else if (aStyleMask & CPDocModalWindowMask)
527  return _CPDocModalWindowView;
528 
529  return _CPStandardWindowView;
530 }
531 
532 + (Class)_windowViewClassForFullPlatformWindowStyleMask:(unsigned)aStyleMask
533 {
534  return _CPBorderlessBridgeWindowView;
535 }
536 
537 - (void)awakeFromCib
538 {
539  // At this time we know the final screen (or browser) size
540  // and can apply the positioning mask, if any, from the nib.
541  if (_positioningScreenRect)
542  {
543  var actualScreenRect = [CPPlatform isBrowser] ? [_platformWindow contentBounds] : [[self screen] visibleFrame],
544  frame = [self frame],
545  origin = frame.origin;
546 
547  if (actualScreenRect)
548  {
549  if ((_positioningMask & CPWindowPositionFlexibleLeft) && (_positioningMask & CPWindowPositionFlexibleRight))
550  {
551  // Proportional Horizontal.
552  origin.x *= (actualScreenRect.size.width / _positioningScreenRect.size.width);
553  }
554  else if (_positioningMask & CPWindowPositionFlexibleLeft)
555  {
556  // Fixed from Right
557  origin.x += actualScreenRect.size.width - _positioningScreenRect.size.width;
558  }
559  else if (_positioningMask & CPWindowPositionFlexibleRight)
560  {
561  // Fixed from Left
562  }
563 
564  if ((_positioningMask & CPWindowPositionFlexibleTop) && (_positioningMask & CPWindowPositionFlexibleBottom))
565  {
566  // Proportional Vertical.
567  origin.y *= (actualScreenRect.size.height / _positioningScreenRect.size.height);
568  }
569  else if (_positioningMask & CPWindowPositionFlexibleTop)
570  {
571  // Fixed from Bottom
572  origin.y += actualScreenRect.size.height - _positioningScreenRect.size.height;
573  }
574  else if (_positioningMask & CPWindowPositionFlexibleBottom)
575  {
576  // Fixed from Top
577  }
578 
579  [self setFrameOrigin:origin];
580  }
581  }
582 
583  /*
584  Calculate the key view loop if necessary. Note that Cocoa does not call recalculateKeyViewLoop when awaking a nib. If a key view loop was set in the cib, we have to chain it to the content view.
585  */
586  if ([self _hasKeyViewLoop:[_contentView subviews]])
587  {
588  var views = [self _viewsSortedByPosition],
589  count = [views count];
590 
591  // The first view is the content view.
592  // Find the first subview that has a next key view.
593  for (var i = 1; i < count; ++i)
594  {
595  var view = views[i];
596 
597  if ([view nextKeyView])
598  {
599  [_contentView setNextKeyView:view];
600  break;
601  }
602  }
603  }
604  else
605  {
606  // Cooca does NOT call the public method recalculateKeyViewLoop for nibs,
607  // but it does calculate the loop.
608  [self _doRecalculateKeyViewLoop];
609  }
610 }
611 
612 - (void)_setWindowView:(CPView)aWindowView
613 {
614  if (_windowView === aWindowView)
615  return;
616 
617  var oldWindowView = _windowView;
618 
619  _windowView = aWindowView;
620 
621  if (oldWindowView)
622  {
623  [oldWindowView _setWindow:nil];
624  [oldWindowView noteToolbarChanged];
625 
626 #if PLATFORM(DOM)
627  CPDOMDisplayServerRemoveChild(_DOMElement, oldWindowView._DOMElement);
628 #endif
629  }
630 
631  if (_windowView)
632  {
633 #if PLATFORM(DOM)
634  CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement);
635 #endif
636 
637  var contentRect = [_contentView convertRect:[_contentView bounds] toView:nil];
638 
639  contentRect.origin = [self convertBaseToGlobal:contentRect.origin];
640 
641  [_windowView _setWindow:self];
642  [_windowView setNextResponder:self];
643  [_windowView addSubview:_contentView];
644  [_windowView setTitle:_title];
645  [_windowView noteToolbarChanged];
646  [_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
647 
648  [self setFrame:[self frameRectForContentRect:contentRect]];
649  }
650 }
651 
658 - (void)setFullPlatformWindow:(BOOL)shouldBeFullPlatformWindow
659 {
660  if (![_platformWindow supportsFullPlatformWindows])
661  return;
662 
663  shouldBeFullPlatformWindow = !!shouldBeFullPlatformWindow;
664 
665  if (_isFullPlatformWindow === shouldBeFullPlatformWindow)
666  return;
667 
668  _isFullPlatformWindow = shouldBeFullPlatformWindow;
669 
670  if (_isFullPlatformWindow)
671  {
672  _fullPlatformWindowSession = _CPWindowFullPlatformWindowSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]);
673 
674  var fullPlatformWindowViewClass = [[self class] _windowViewClassForFullPlatformWindowStyleMask:_styleMask],
675  windowView = [[fullPlatformWindowViewClass alloc] initWithFrame:_CGRectMakeZero() styleMask:_styleMask];
676 
677  [self _setWindowView:windowView];
678 
679  [self setLevel:CPBackgroundWindowLevel];
680  [self setHasShadow:NO];
681  [self setAutoresizingMask:CPWindowWidthSizable | CPWindowHeightSizable];
682  [self setFrame:[_platformWindow visibleFrame]];
683  }
684  else
685  {
686  var windowView = _fullPlatformWindowSession.windowView;
687 
688  [self _setWindowView:windowView];
689 
690  [self setLevel:_fullPlatformWindowSession.level];
691  [self setHasShadow:_fullPlatformWindowSession.hasShadow];
692  [self setAutoresizingMask:CPWindowNotSizable];
693 
694  [self setFrame:[windowView frameRectForContentRect:_fullPlatformWindowSession.contentRect]];
695  }
696 }
697 
701 - (BOOL)isFullPlatformWindow
702 {
703  return _isFullPlatformWindow;
704 }
705 
709 - (unsigned)styleMask
710 {
711  return _styleMask;
712 }
713 
732 + (CGRect)frameRectForContentRect:(CGRect)aContentRect styleMask:(unsigned)aStyleMask
733 {
734  return [[[self class] _windowViewClassForStyleMask:aStyleMask] frameRectForContentRect:aContentRect];
735 }
736 
741 - (CGRect)contentRectForFrameRect:(CGRect)aFrame
742 {
743  return [_windowView contentRectForFrameRect:aFrame];
744 }
745 
751 - (CGRect)frameRectForContentRect:(CGRect)aContentRect
752 {
753  return [_windowView frameRectForContentRect:aContentRect];
754 }
755 
759 - (CGRect)frame
760 {
761  return _CGRectMakeCopy(_frame);
762 }
763 
771 - (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
772 {
773  aFrame.size.width = MIN(MAX(aFrame.size.width, _minSize.width), _maxSize.width)
774  aFrame.size.height = MIN(MAX(aFrame.size.height, _minSize.height), _maxSize.height);
775  [self setFrame:aFrame display:shouldDisplay animate:shouldAnimate];
776 }
777 
785 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
786 {
787  aFrame = _CGRectMakeCopy(aFrame);
788 
789  var value = aFrame.origin.x,
790  delta = value - FLOOR(value);
791 
792  if (delta)
793  aFrame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value);
794 
795  value = aFrame.origin.y;
796  delta = value - FLOOR(value);
797 
798  if (delta)
799  aFrame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value);
800 
801  value = aFrame.size.width;
802  delta = value - FLOOR(value);
803 
804  if (delta)
805  aFrame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value);
806 
807  value = aFrame.size.height;
808  delta = value - FLOOR(value);
809 
810  if (delta)
811  aFrame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value);
812 
813  if (shouldAnimate)
814  {
815  [_frameAnimation stopAnimation];
816  _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
817 
818  [_frameAnimation startAnimation];
819  }
820  else
821  {
822  var origin = _frame.origin,
823  newOrigin = aFrame.origin;
824 
825  if (!_CGPointEqualToPoint(origin, newOrigin))
826  {
827  origin.x = newOrigin.x;
828  origin.y = newOrigin.y;
829 
830 #if PLATFORM(DOM)
831  if (![self _sharesChromeWithPlatformWindow])
832  {
833  CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, origin.x, origin.y);
834  }
835 #endif
836 
837  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMoveNotification object:self];
838  }
839 
840  var size = _frame.size,
841  newSize = aFrame.size;
842 
843  if (!_CGSizeEqualToSize(size, newSize))
844  {
845  size.width = newSize.width;
846  size.height = newSize.height;
847 
848  [_windowView setFrameSize:size];
849 
850  if (_hasShadow)
851  {
852  // if the shadow would be taller/wider than the window height,
853  // make it the same as the window height. this allows views to
854  // become 0, 0 with no shadow on them and makes the sheet
855  // animation look nicer
856  var shadowSize = _CGSizeMake(size.width, size.height);
857 
858  if (size.width >= (SHADOW_MARGIN_LEFT + SHADOW_MARGIN_RIGHT))
859  shadowSize.width += SHADOW_MARGIN_LEFT + SHADOW_MARGIN_RIGHT;
860 
861  if (size.height >= (SHADOW_MARGIN_BOTTOM + SHADOW_MARGIN_TOP + SHADOW_DISTANCE))
862  shadowSize.height += SHADOW_MARGIN_BOTTOM + SHADOW_MARGIN_TOP + SHADOW_DISTANCE;
863 
864  [_shadowView setFrameSize:shadowSize];
865  }
866 
867  if (!_isAnimating)
868  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
869  }
870 
871  if ([self _sharesChromeWithPlatformWindow])
872  [_platformWindow setContentRect:_frame];
873  }
874 }
875 
881 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
882 {
883  [self _setClippedFrame:aFrame display:shouldDisplay animate:NO];
884 }
885 
890 - (void)setFrame:(CGRect)aFrame
891 {
892  [self _setClippedFrame:aFrame display:YES animate:NO];
893 }
894 
899 - (void)setFrameOrigin:(CGPoint)anOrigin
900 {
901  [self _setClippedFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
902 
903  // reposition sheet
904  if ([self attachedSheet])
905  [self _setAttachedSheetFrameOrigin];
906 }
907 
912 - (void)setFrameSize:(CGSize)aSize
913 {
914  [self _setClippedFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
915 }
916 
921 - (void)orderFront:(id)aSender
922 {
923 #if PLATFORM(DOM)
924  // -dw- if a sheet is clicked, the parent window should come up too
925  if ([self isSheet])
926  [_parentView orderFront:self];
927 
928  [_platformWindow orderFront:self];
929  [_platformWindow order:CPWindowAbove window:self relativeTo:nil];
930 #endif
931 
932  if (!CPApp._keyWindow)
933  [self makeKeyWindow];
934 
935  if ([self isKeyWindow] && (_firstResponder === self || !_firstResponder))
936  [self makeFirstResponder:_initialFirstResponder];
937 
938  if (!CPApp._mainWindow)
939  [self makeMainWindow];
940 }
941 
942 /*
943  Makes the receiver the last window in the screen ordering.
944  @param aSender the object that requested this
945  @ignore
946 */
947 - (void)orderBack:(id)aSender
948 {
949  //[_platformWindow order:CPWindowBelow
950 }
951 
956 - (void)orderOut:(id)aSender
957 {
958  if ([self isSheet])
959  {
960  // -dw- as in Cocoa, orderOut: detaches the sheet and animates out
961  [self._parentView _detachSheetWindow];
962  return;
963  }
964 
965 #if PLATFORM(DOM)
966  if ([self _sharesChromeWithPlatformWindow])
967  [_platformWindow orderOut:self];
968 #endif
969 
970  if ([_delegate respondsToSelector:@selector(windowWillClose:)])
971  [_delegate windowWillClose:self];
972 
973 #if PLATFORM(DOM)
974  [_platformWindow order:CPWindowOut window:self relativeTo:nil];
975 #endif
976 
977  [self _updateMainAndKeyWindows];
978 }
979 
985 - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
986 {
987 #if PLATFORM(DOM)
988  [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
989 #endif
990 }
991 
996 - (void)setLevel:(int)aLevel
997 {
998  if (aLevel === _level)
999  return;
1000 
1001  [_platformWindow moveWindow:self fromLevel:_level toLevel:aLevel];
1002 
1003  _level = aLevel;
1004 
1005  if ([self _sharesChromeWithPlatformWindow])
1006  [_platformWindow setLevel:aLevel];
1007 }
1008 
1012 - (int)level
1013 {
1014  return _level;
1015 }
1016 
1020 - (BOOL)isVisible
1021 {
1022  return _isVisible;
1023 }
1024 
1030 + (void)setGlobalResizeStyle:(int)aStyle
1031 {
1032  if (CPWindowResizeStyle === aStyle)
1033  return;
1034 
1035  CPWindowResizeStyle = aStyle;
1036  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowResizeStyleGlobalChangeNotification object:nil];
1037 }
1038 
1039 - (void)_didReceiveResizeStyleChange:(CPNotification)aNotification
1040 {
1041  [_windowView setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
1042 }
1043 
1047 + (int)globalResizeStyle
1048 {
1049  return CPWindowResizeStyle;
1050 }
1051 
1055 - (BOOL)showsResizeIndicator
1056 {
1057  return _showsResizeIndicator;
1058 }
1059 
1064 - (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
1065 {
1066  shouldShowResizeIndicator = !!shouldShowResizeIndicator;
1067 
1068  if (_showsResizeIndicator === shouldShowResizeIndicator)
1069  return;
1070 
1071  _showsResizeIndicator = shouldShowResizeIndicator;
1072  [_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
1073 }
1074 
1078 - (CGSize)resizeIndicatorOffset
1079 {
1080  return [_windowView resizeIndicatorOffset];
1081 }
1082 
1087 - (void)setResizeIndicatorOffset:(CGSize)anOffset
1088 {
1089  [_windowView setResizeIndicatorOffset:anOffset];
1090 }
1091 
1097 - (void)setContentView:(CPView)aView
1098 {
1099  if (_contentView)
1100  [_contentView removeFromSuperview];
1101 
1102  var bounds = _CGRectMake(0.0, 0.0, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame));
1103 
1104  _contentView = aView;
1105  [_contentView setFrame:[self contentRectForFrameRect:bounds]];
1106 
1107  [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1108  [_windowView addSubview:_contentView];
1109 
1110  /*
1111  If the initial first responder has been set to something other than
1112  the window, set it to the window because it will no longer be valid.
1113  */
1114  if (_initialFirstResponder && _initialFirstResponder !== self)
1115  _initialFirstResponder = self;
1116 }
1117 
1121 - (CPView)contentView
1122 {
1123  return _contentView;
1124 }
1125 
1130 - (void)setAlphaValue:(float)aValue
1131 {
1132  [_windowView setAlphaValue:aValue];
1133 }
1134 
1138 - (float)alphaValue
1139 {
1140  return [_windowView alphaValue];
1141 }
1142 
1147 - (void)setBackgroundColor:(CPColor)aColor
1148 {
1149  [_windowView setBackgroundColor:aColor];
1150 }
1151 
1155 - (CPColor)backgroundColor
1156 {
1157  return [_windowView backgroundColor];
1158 }
1159 
1165 - (void)setMinSize:(CGSize)aSize
1166 {
1167  if (_CGSizeEqualToSize(_minSize, aSize))
1168  return;
1169 
1170  _minSize = _CGSizeMakeCopy(aSize);
1171 
1172  var size = _CGSizeMakeCopy([self frame].size),
1173  needsFrameChange = NO;
1174 
1175  if (size.width < _minSize.width)
1176  {
1177  size.width = _minSize.width;
1178  needsFrameChange = YES;
1179  }
1180 
1181  if (size.height < _minSize.height)
1182  {
1183  size.height = _minSize.height;
1184  needsFrameChange = YES;
1185  }
1186 
1187  if (needsFrameChange)
1188  [self setFrameSize:size];
1189 }
1190 
1194 - (CGSize)minSize
1195 {
1196  return _minSize;
1197 }
1198 
1205 - (void)setMaxSize:(CGSize)aSize
1206 {
1207  if (_CGSizeEqualToSize(_maxSize, aSize))
1208  return;
1209 
1210  _maxSize = _CGSizeMakeCopy(aSize);
1211 
1212  var size = _CGSizeMakeCopy([self frame].size),
1213  needsFrameChange = NO;
1214 
1215  if (size.width > _maxSize.width)
1216  {
1217  size.width = _maxSize.width;
1218  needsFrameChange = YES;
1219  }
1220 
1221  if (size.height > _maxSize.height)
1222  {
1223  size.height = _maxSize.height;
1224  needsFrameChange = YES;
1225  }
1226 
1227  if (needsFrameChange)
1228  [self setFrameSize:size];
1229 }
1230 
1234 - (CGSize)maxSize
1235 {
1236  return _maxSize;
1237 }
1238 
1242 - (BOOL)hasShadow
1243 {
1244  return _hasShadow;
1245 }
1246 
1247 - (void)_updateShadow
1248 {
1249  if ([self _sharesChromeWithPlatformWindow])
1250  {
1251  if (_shadowView)
1252  {
1253 #if PLATFORM(DOM)
1254  CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
1255 #endif
1256  _shadowView = nil;
1257  }
1258 
1259  [_platformWindow setHasShadow:_hasShadow];
1260 
1261  return;
1262  }
1263 
1264  if (_hasShadow && !_shadowView)
1265  {
1266  var bounds = [_windowView bounds];
1267 
1268  _shadowView = [[CPView alloc] initWithFrame:_CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE,
1269  SHADOW_MARGIN_LEFT + _CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + _CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)];
1270 
1271  if (!_CPWindowShadowColor)
1272  {
1273  var bundle = [CPBundle bundleForClass:[CPWindow class]];
1274 
1276  [
1277  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow0.png"] size:_CGSizeMake(20.0, 19.0)],
1278  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow1.png"] size:_CGSizeMake(1.0, 19.0)],
1279  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow2.png"] size:_CGSizeMake(19.0, 19.0)],
1280 
1281  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow3.png"] size:_CGSizeMake(20.0, 1.0)],
1282  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow4.png"] size:_CGSizeMake(1.0, 1.0)],
1283  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow5.png"] size:_CGSizeMake(19.0, 1.0)],
1284 
1285  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow6.png"] size:_CGSizeMake(20.0, 18.0)],
1286  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow7.png"] size:_CGSizeMake(1.0, 18.0)],
1287  [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowShadow8.png"] size:_CGSizeMake(19.0, 18.0)]
1288  ]]];
1289  }
1290 
1291  [_shadowView setBackgroundColor:_CPWindowShadowColor];
1292  [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1293 
1294 #if PLATFORM(DOM)
1295  CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
1296 #endif
1297  }
1298  else if (!_hasShadow && _shadowView)
1299  {
1300 #if PLATFORM(DOM)
1301  CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
1302 #endif
1303  _shadowView = nil;
1304  }
1305 }
1306 
1311 - (void)setHasShadow:(BOOL)shouldHaveShadow
1312 {
1313  if (_hasShadow === shouldHaveShadow)
1314  return;
1315 
1316  _hasShadow = shouldHaveShadow;
1317 
1318  [self _updateShadow];
1319 }
1320 
1332 - (void)setShadowStyle:(unsigned)aStyle
1333 {
1334  _shadowStyle = aStyle;
1335 
1336  [[self platformWindow] setShadowStyle:_shadowStyle];
1337 }
1338 
1343 - (void)setDelegate:(id)aDelegate
1344 {
1345  var defaultCenter = [CPNotificationCenter defaultCenter];
1346 
1347  [defaultCenter removeObserver:_delegate name:CPWindowDidResignKeyNotification object:self];
1348  [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeKeyNotification object:self];
1349  [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeMainNotification object:self];
1350  [defaultCenter removeObserver:_delegate name:CPWindowDidResignMainNotification object:self];
1351  [defaultCenter removeObserver:_delegate name:CPWindowDidMoveNotification object:self];
1352  [defaultCenter removeObserver:_delegate name:CPWindowDidResizeNotification object:self];
1353  [defaultCenter removeObserver:_delegate name:CPWindowWillBeginSheetNotification object:self];
1354  [defaultCenter removeObserver:_delegate name:CPWindowDidEndSheetNotification object:self];
1355 
1356  _delegate = aDelegate;
1357  _delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)];
1358 
1359  if ([_delegate respondsToSelector:@selector(windowDidResignKey:)])
1360  [defaultCenter
1361  addObserver:_delegate
1362  selector:@selector(windowDidResignKey:)
1363  name:CPWindowDidResignKeyNotification
1364  object:self];
1365 
1366  if ([_delegate respondsToSelector:@selector(windowDidBecomeKey:)])
1367  [defaultCenter
1368  addObserver:_delegate
1369  selector:@selector(windowDidBecomeKey:)
1370  name:CPWindowDidBecomeKeyNotification
1371  object:self];
1372 
1373  if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
1374  [defaultCenter
1375  addObserver:_delegate
1376  selector:@selector(windowDidBecomeMain:)
1377  name:CPWindowDidBecomeMainNotification
1378  object:self];
1379 
1380  if ([_delegate respondsToSelector:@selector(windowDidResignMain:)])
1381  [defaultCenter
1382  addObserver:_delegate
1383  selector:@selector(windowDidResignMain:)
1384  name:CPWindowDidResignMainNotification
1385  object:self];
1386 
1387  if ([_delegate respondsToSelector:@selector(windowDidMove:)])
1388  [defaultCenter
1389  addObserver:_delegate
1390  selector:@selector(windowDidMove:)
1391  name:CPWindowDidMoveNotification
1392  object:self];
1393 
1394  if ([_delegate respondsToSelector:@selector(windowDidResize:)])
1395  [defaultCenter
1396  addObserver:_delegate
1397  selector:@selector(windowDidResize:)
1398  name:CPWindowDidResizeNotification
1399  object:self];
1400 
1401  if ([_delegate respondsToSelector:@selector(windowWillBeginSheet:)])
1402  [defaultCenter
1403  addObserver:_delegate
1404  selector:@selector(windowWillBeginSheet:)
1405  name:CPWindowWillBeginSheetNotification
1406  object:self];
1407 
1408  if ([_delegate respondsToSelector:@selector(windowDidEndSheet:)])
1409  [defaultCenter
1410  addObserver:_delegate
1411  selector:@selector(windowDidEndSheet:)
1412  name:CPWindowDidEndSheetNotification
1413  object:self];
1414 }
1415 
1419 - (id)delegate
1420 {
1421  return _delegate;
1422 }
1423 
1428 - (void)setWindowController:(CPWindowController)aWindowController
1429 {
1430  _windowController = aWindowController;
1431 }
1432 
1436 - (CPWindowController)windowController
1437 {
1438  return _windowController;
1439 }
1440 
1441 - (void)doCommandBySelector:(SEL)aSelector
1442 {
1443  if ([_delegate respondsToSelector:aSelector])
1444  [_delegate performSelector:aSelector];
1445  else
1446  [super doCommandBySelector:aSelector];
1447 }
1448 
1449 - (BOOL)acceptsFirstResponder
1450 {
1451  return NO;
1452 }
1453 
1454 - (CPView)initialFirstResponder
1455 {
1456  return _initialFirstResponder;
1457 }
1458 
1459 - (void)setInitialFirstResponder:(CPView)aView
1460 {
1461  _initialFirstResponder = aView;
1462 }
1463 
1464 - (void)_setupFirstResponder
1465 {
1466  /*
1467  When the window is first made the key window, if the first responder is the window, use the initial first responder if there is one. If there is a first responder and it is not the window, ignore the initial first responder.
1468  */
1469  if (!_hasBecomeKeyWindow)
1470  {
1471  if (_firstResponder === self)
1472  {
1473  if (_initialFirstResponder)
1474  [self makeFirstResponder:_initialFirstResponder];
1475  else
1476  {
1477  // Make the first valid key view the first responder
1478  var view = [_contentView nextValidKeyView];
1479 
1480  if (view)
1481  [self makeFirstResponder:view];
1482  }
1483 
1484  return;
1485  }
1486  }
1487 
1488  if (_firstResponder)
1489  [self makeFirstResponder:_firstResponder];
1490 }
1491 
1499 - (BOOL)makeFirstResponder:(CPResponder)aResponder
1500 {
1501  if (_firstResponder === aResponder)
1502  return YES;
1503 
1504  if (![_firstResponder resignFirstResponder])
1505  return NO;
1506 
1507  if (!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
1508  {
1509  _firstResponder = self;
1510 
1511  return NO;
1512  }
1513 
1514  _firstResponder = aResponder;
1515 
1516  [[CPNotificationCenter defaultCenter] postNotificationName:_CPWindowDidChangeFirstResponderNotification object:self];
1517 
1518  return YES;
1519 }
1520 
1524 - (CPResponder)firstResponder
1525 {
1526  return _firstResponder;
1527 }
1528 
1529 - (BOOL)acceptsMouseMovedEvents
1530 {
1531  return _acceptsMouseMovedEvents;
1532 }
1533 
1534 - (void)setAcceptsMouseMovedEvents:(BOOL)shouldAcceptMouseMovedEvents
1535 {
1536  _acceptsMouseMovedEvents = shouldAcceptMouseMovedEvents;
1537 }
1538 
1539 - (BOOL)ignoresMouseEvents
1540 {
1541  return _ignoresMouseEvents;
1542 }
1543 
1544 - (void)setIgnoresMouseEvents:(BOOL)shouldIgnoreMouseEvents
1545 {
1546  _ignoresMouseEvents = shouldIgnoreMouseEvents;
1547 }
1548 
1549 - (void)_mouseExitedResizeRect
1550 {
1551  [[CPCursor arrowCursor] set];
1552 }
1553 
1554 // Managing Titles
1555 
1559 - (CPString)title
1560 {
1561  return _title;
1562 }
1563 
1567 - (void)setTitle:(CPString)aTitle
1568 {
1569  _title = aTitle;
1570 
1571  [_windowView setTitle:aTitle];
1572  [_platformWindow _setTitle:_title window:self];
1573 
1574  [self _synchronizeMenuBarTitleWithWindowTitle];
1575 }
1576 
1580 - (void)setTitleWithRepresentedFilename:(CPString)aFilePath
1581 {
1582  [self setRepresentedFilename:aFilePath];
1583  [self setTitle:[aFilePath lastPathComponent]];
1584 }
1585 
1589 - (void)setRepresentedFilename:(CPString)aFilePath
1590 {
1591  // FIXME: urls vs filepaths and all.
1592  [self setRepresentedURL:aFilePath];
1593 }
1594 
1598 - (CPString)representedFilename
1599 {
1600  return _representedURL;
1601 }
1602 
1606 - (void)setRepresentedURL:(CPURL)aURL
1607 {
1608  _representedURL = aURL;
1609 }
1610 
1614 - (CPURL)representedURL
1615 {
1616  return _representedURL;
1617 }
1618 
1619 - (CPScreen)screen
1620 {
1621  return [[CPScreen alloc] init];
1622 }
1623 
1624 // Moving
1625 
1630 - (void)setMovableByWindowBackground:(BOOL)shouldBeMovableByWindowBackground
1631 {
1632  _isMovableByWindowBackground = shouldBeMovableByWindowBackground;
1633 }
1634 
1638 - (BOOL)isMovableByWindowBackground
1639 {
1640  return _isMovableByWindowBackground;
1641 }
1642 
1647 - (void)setMovable:(BOOL)shouldBeMovable
1648 {
1649  _isMovable = shouldBeMovable;
1650 }
1651 
1655 - (void)isMovable
1656 {
1657  return _isMovable;
1658 }
1659 
1663 - (void)center
1664 {
1665  if (_isFullPlatformWindow)
1666  return;
1667 
1668  var size = [self frame].size,
1669  containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
1670 
1671  var origin = _CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
1672 
1673  if (origin.x < 0.0)
1674  origin.x = 0.0;
1675 
1676  if (origin.y < 0.0)
1677  origin.y = 0.0;
1678 
1679  [self setFrameOrigin:origin];
1680 }
1681 
1686 - (void)sendEvent:(CPEvent)anEvent
1687 {
1688  var type = [anEvent type],
1689  point = [anEvent locationInWindow];
1690 
1691  // If a sheet is attached events get filtered here.
1692  // It is not clear what events should be passed to the view, perhaps all?
1693  // CPLeftMouseDown is needed for window moving and resizing to work.
1694  // CPMouseMoved is needed for rollover effects on title bar buttons.
1695  var sheet = [self attachedSheet];
1696 
1697  if (sheet)
1698  {
1699  switch (type)
1700  {
1701  case CPLeftMouseDown:
1702  [_windowView mouseDown:anEvent];
1703 
1704  // -dw- if the window is clicked, the sheet should come to front, and become key,
1705  // and the window should be immediately behind
1706  [sheet makeKeyAndOrderFront:self];
1707  break;
1708  case CPMouseMoved:
1709  [_windowView mouseMoved:anEvent];
1710  break;
1711  }
1712 
1713  return;
1714  }
1715 
1716  switch (type)
1717  {
1718  case CPFlagsChanged:
1719  return [[self firstResponder] flagsChanged:anEvent];
1720 
1721  case CPKeyUp:
1722  return [[self firstResponder] keyUp:anEvent];
1723 
1724  case CPKeyDown:
1725  if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
1726  {
1727  if ([anEvent modifierFlags] & CPShiftKeyMask)
1728  [self selectPreviousKeyView:self];
1729  else
1730  [self selectNextKeyView:self];
1731 #if PLATFORM(DOM)
1732  // Make sure the browser doesn't try to do its own tab handling.
1733  // This is important or the browser might blur the shared text field or token field input field,
1734  // even that we just moved it to a new first responder.
1735  [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
1736 #endif
1737  return;
1738  }
1739  else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
1740  {
1741  var didTabBack = [self selectPreviousKeyView:self];
1742 
1743  if (didTabBack)
1744  {
1745 #if PLATFORM(DOM)
1746  // Make sure the browser doesn't try to do its own tab handling.
1747  // This is important or the browser might blur the shared text field or token field input field,
1748  // even that we just moved it to a new first responder.
1749  [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
1750 #endif
1751  }
1752 
1753  return didTabBack;
1754  }
1755 
1756  [[self firstResponder] keyDown:anEvent];
1757 
1758  // Trigger the default button if needed
1759  // FIXME: Is this only applicable in a sheet? See isse: #722.
1760  if (![self disableKeyEquivalentForDefaultButton])
1761  {
1762  var defaultButton = [self defaultButton],
1763  keyEquivalent = [defaultButton keyEquivalent],
1764  modifierMask = [defaultButton keyEquivalentModifierMask];
1765 
1766  if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask])
1767  [[self defaultButton] performClick:self];
1768  }
1769 
1770  return;
1771 
1772  case CPScrollWheel:
1773  return [[_windowView hitTest:point] scrollWheel:anEvent];
1774 
1775  case CPLeftMouseUp:
1776  case CPRightMouseUp:
1777  var hitTestedView = _leftMouseDownView,
1778  selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:);
1779 
1780  if (!hitTestedView)
1781  hitTestedView = [_windowView hitTest:point];
1782 
1783  [hitTestedView performSelector:selector withObject:anEvent];
1784 
1785  _leftMouseDownView = nil;
1786 
1787  return;
1788 
1789  case CPLeftMouseDown:
1790  case CPRightMouseDown:
1791  _leftMouseDownView = [_windowView hitTest:point];
1792 
1793  if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder])
1794  [self makeFirstResponder:_leftMouseDownView];
1795 
1796  [CPApp activateIgnoringOtherApps:YES];
1797 
1798  var theWindow = [anEvent window],
1799  selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:);
1800 
1801  if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey])
1802  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1803  else
1804  {
1805  // FIXME: delayed ordering?
1806  [self makeKeyAndOrderFront:self];
1807 
1808  if ([_leftMouseDownView acceptsFirstMouse:anEvent])
1809  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1810  }
1811  break;
1812 
1813  case CPLeftMouseDragged:
1814  case CPRightMouseDragged:
1815  if (!_leftMouseDownView)
1816  return [[_windowView hitTest:point] mouseDragged:anEvent];
1817 
1818  var selector;
1819 
1820  if (type == CPRightMouseDragged)
1821  {
1822  selector = @selector(rightMouseDragged:)
1823  if (![_leftMouseDownView respondsToSelector:selector])
1824  selector = nil;
1825  }
1826 
1827  if (!selector)
1828  selector = @selector(mouseDragged:)
1829 
1830  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1831 
1832  case CPMouseMoved:
1833  [_windowView setCursorForLocation:point resizing:NO];
1834 
1835  if (!_acceptsMouseMovedEvents)
1836  return;
1837 
1838  if (!_mouseEnteredStack)
1839  _mouseEnteredStack = [];
1840 
1841  var hitTestView = [_windowView hitTest:point];
1842 
1843  if ([_mouseEnteredStack count] && [_mouseEnteredStack lastObject] === hitTestView)
1844  return [hitTestView mouseMoved:anEvent];
1845 
1846  var view = hitTestView,
1847  mouseEnteredStack = [];
1848 
1849  while (view)
1850  {
1851  mouseEnteredStack.unshift(view);
1852 
1853  view = [view superview];
1854  }
1855 
1856  var deviation = MIN(_mouseEnteredStack.length, mouseEnteredStack.length);
1857 
1858  while (deviation--)
1859  if (_mouseEnteredStack[deviation] === mouseEnteredStack[deviation])
1860  break;
1861 
1862  var index = deviation + 1,
1863  count = _mouseEnteredStack.length;
1864 
1865  if (index < count)
1866  {
1867  var event = [CPEvent mouseEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
1868 
1869  for (; index < count; ++index)
1870  [_mouseEnteredStack[index] mouseExited:event];
1871  }
1872 
1873  index = deviation + 1;
1874  count = mouseEnteredStack.length;
1875 
1876  if (index < count)
1877  {
1878  var event = [CPEvent mouseEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
1879 
1880  for (; index < count; ++index)
1881  [mouseEnteredStack[index] mouseEntered:event];
1882  }
1883 
1884  _mouseEnteredStack = mouseEnteredStack;
1885 
1886  [hitTestView mouseMoved:anEvent];
1887  }
1888 }
1889 
1893 - (int)windowNumber
1894 {
1895  return _windowNumber;
1896 }
1897 
1903 - (void)becomeKeyWindow
1904 {
1905  CPApp._keyWindow = self;
1906 
1907  if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)])
1908  [_firstResponder becomeKeyWindow];
1909 
1910  if (!_hasBecomeKeyWindow)
1911  {
1912  // The first time a window is loaded, if it does not have a key view loop
1913  // established, calculate it now.
1914  if (![self _hasKeyViewLoop:[_contentView subviews]])
1915  [self recalculateKeyViewLoop];
1916  }
1917 
1918  [self _setupFirstResponder];
1919  _hasBecomeKeyWindow = YES;
1920 
1921  [_windowView noteKeyWindowStateChanged];
1922 
1924  postNotificationName:CPWindowDidBecomeKeyNotification
1925  object:self];
1926 }
1927 
1932 - (BOOL)canBecomeKeyWindow
1933 {
1934  /*
1935  In Cocoa only titled windows return YES here by default. But the main browser
1936  window in Cappuccino doesn't have a title bar even that it's both titled and
1937  resizable, so we return YES when isFullPlatformWindow too.
1938 
1939  Note that Cocoa will return NO for a non-titled, resizable window. The Cocoa documention
1940  says it will return YES if there is a "resize bar", but in practice
1941  that is not the same as the resizable mask.
1942  */
1943  return (_styleMask & CPTitledWindowMask) || [self isFullPlatformWindow] || _isSheet;
1944 }
1945 
1949 - (BOOL)isKeyWindow
1950 {
1951  return [CPApp keyWindow] == self;
1952 }
1953 
1958 - (void)makeKeyAndOrderFront:(id)aSender
1959 {
1960  [self orderFront:self];
1961 
1962  [self makeKeyWindow];
1963  [self makeMainWindow];
1964 }
1965 
1969 - (void)makeKeyWindow
1970 {
1971  if ([CPApp keyWindow] === self || ![self canBecomeKeyWindow])
1972  return;
1973 
1974  [[CPApp keyWindow] resignKeyWindow];
1975  [self becomeKeyWindow];
1976 }
1977 
1981 - (void)resignKeyWindow
1982 {
1983  if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
1984  [_firstResponder resignKeyWindow];
1985 
1986  if (CPApp._keyWindow === self)
1987  CPApp._keyWindow = nil;
1988 
1989  [_windowView noteKeyWindowStateChanged];
1990 
1992  postNotificationName:CPWindowDidResignKeyNotification
1993  object:self];
1994 }
1995 
2006 - (void)dragImage:(CPImage)anImage at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
2007 {
2008  [[CPDragServer sharedDragServer] dragImage:anImage fromWindow:self at:[self convertBaseToGlobal:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
2009 }
2010 
2011 - (void)_noteRegisteredDraggedTypes:(CPSet)pasteboardTypes
2012 {
2013  if (!pasteboardTypes)
2014  return;
2015 
2016  if (!_inclusiveRegisteredDraggedTypes)
2017  _inclusiveRegisteredDraggedTypes = [CPCountedSet set];
2018 
2019  [_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes];
2020 }
2021 
2022 - (void)_noteUnregisteredDraggedTypes:(CPSet)pasteboardTypes
2023 {
2024  if (!pasteboardTypes)
2025  return;
2026 
2027  [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
2028 
2029  if ([_inclusiveRegisteredDraggedTypes count] === 0)
2030  _inclusiveRegisteredDraggedTypes = nil;
2031 }
2032 
2043 - (void)dragView:(CPView)aView at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
2044 {
2045  [[CPDragServer sharedDragServer] dragView:aView fromWindow:self at:[self convertBaseToGlobal:viewLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
2046 }
2047 
2052 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes
2053 {
2054  if (!pasteboardTypes)
2055  return;
2056 
2057  [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
2058  [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
2059  [self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
2060 
2061  _registeredDraggedTypesArray = nil;
2062 }
2063 
2068 - (CPArray)registeredDraggedTypes
2069 {
2070  if (!_registeredDraggedTypesArray)
2071  _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
2072 
2073  return _registeredDraggedTypesArray;
2074 }
2075 
2079 - (void)unregisterDraggedTypes
2080 {
2081  [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
2082 
2083  _registeredDraggedTypes = [CPSet set];
2084  _registeredDraggedTypesArray = [];
2085 }
2086 
2087 // Accessing Editing Status
2088 
2093 - (void)setDocumentEdited:(BOOL)isDocumentEdited
2094 {
2095  if (_isDocumentEdited == isDocumentEdited)
2096  return;
2097 
2098  _isDocumentEdited = isDocumentEdited;
2099 
2100  [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0];
2101 
2102  [_windowView setDocumentEdited:isDocumentEdited];
2103 }
2104 
2108 - (BOOL)isDocumentEdited
2109 {
2110  return _isDocumentEdited;
2111 }
2112 
2113 - (void)setDocumentSaving:(BOOL)isDocumentSaving
2114 {
2115  if (_isDocumentSaving == isDocumentSaving)
2116  return;
2117 
2118  _isDocumentSaving = isDocumentSaving;
2119 
2120  [self _synchronizeSaveMenuWithDocumentSaving];
2121 
2122  [_windowView windowDidChangeDocumentSaving];
2123 }
2124 
2125 - (BOOL)isDocumentSaving
2126 {
2127  return _isDocumentSaving;
2128 }
2129 
2130 /* @ignore */
2131 - (void)_synchronizeSaveMenuWithDocumentSaving
2132 {
2133  if (![self isMainWindow])
2134  return;
2135 
2136  var mainMenu = [CPApp mainMenu],
2137  index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."];
2138 
2139  if (index == CPNotFound)
2140  return;
2141 
2142  var item = [mainMenu itemAtIndex:index];
2143 
2144  if (_isDocumentSaving)
2145  {
2146  CPWindowSaveImage = [item image];
2147 
2148  [item setTitle:@"Saving..."];
2149  [item setImage:CPWindowSavingImage];
2150  [item setEnabled:NO];
2151  }
2152  else
2153  {
2154  [item setTitle:@"Save"];
2155  [item setImage:CPWindowSaveImage];
2156  [item setEnabled:YES];
2157  }
2158 }
2159 
2160 // Minimizing Windows
2161 
2166 - (void)performMiniaturize:(id)aSender
2167 {
2168  //FIXME show stuff
2169  [self miniaturize:aSender];
2170 }
2171 
2176 - (void)miniaturize:(id)sender
2177 {
2178  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillMiniaturizeNotification object:self];
2179 
2180  [[self platformWindow] miniaturize:sender];
2181 
2182  [self _updateMainAndKeyWindows];
2183 
2184  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self];
2185 
2186  _isMiniaturized = YES;
2187 }
2188 
2192 - (void)deminiaturize:(id)sender
2193 {
2194  [[self platformWindow] deminiaturize:sender];
2195 
2196  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidDeminiaturizeNotification object:self];
2197 
2198  _isMiniaturized = NO;
2199 }
2200 
2204 - (void)isMiniaturized
2205 {
2206  return _isMiniaturized;
2207 }
2208 
2209 // Closing Windows
2210 
2215 - (void)performClose:(id)aSender
2216 {
2217  if (!(_styleMask & CPClosableWindowMask))
2218  return;
2219 
2220  if ([self isFullBridge])
2221  {
2222  var event = [CPApp currentEvent];
2223 
2224  if ([event type] === CPKeyDown && [event characters] === "w" && ([event modifierFlags] & CPPlatformActionKeyMask))
2225  {
2226  [[self platformWindow] _propagateCurrentDOMEvent:YES];
2227  return;
2228  }
2229  }
2230 
2231  // Only send ONE windowShouldClose: message.
2232  if ([_delegate respondsToSelector:@selector(windowShouldClose:)])
2233  {
2234  if (![_delegate windowShouldClose:self])
2235  return;
2236  }
2237 
2238  // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true).
2239  else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self])
2240  return;
2241 
2242  var documents = [_windowController documents];
2243 
2244  if ([documents count])
2245  {
2246  var index = [documents indexOfObject:[_windowController document]];
2247 
2248  [documents[index] shouldCloseWindowController:_windowController
2249  delegate:self
2250  shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
2251  contextInfo:{documents:[documents copy], visited:0, index:index}];
2252  }
2253  else
2254  [self close];
2255 }
2256 
2257 - (void)_windowControllerContainingDocument:(CPDocument)document shouldClose:(BOOL)shouldClose contextInfo:(Object)context
2258 {
2259  if (shouldClose)
2260  {
2261  var windowController = [self windowController],
2262  documents = context.documents,
2263  count = [documents count],
2264  visited = ++context.visited,
2265  index = ++context.index % count;
2266 
2267  [document removeWindowController:windowController];
2268 
2269  if (visited < count)
2270  {
2271  [windowController setDocument:documents[index]];
2272 
2273  [documents[index] shouldCloseWindowController:_windowController
2274  delegate:self
2275  shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
2276  contextInfo:context];
2277  }
2278  else
2279  [self close];
2280  }
2281 }
2282 
2287 - (void)close
2288 {
2289  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillCloseNotification object:self];
2290 
2291  [self orderOut:nil];
2292 }
2293 
2294 // Managing Main Status
2298 - (BOOL)isMainWindow
2299 {
2300  return [CPApp mainWindow] === self;
2301 }
2302 
2306 - (BOOL)canBecomeMainWindow
2307 {
2308  // Note that the Cocoa documentation says that this method returns YES if
2309  // the window is visible and has a title bar or a "resize mechanism". It turns
2310  // out a "resize mechanism" is not the same as having the resize mask set.
2311  // In practice a window must have a title bar to become main, but we make
2312  // an exception for a full platform window.
2313  return ([self isVisible] && ((_styleMask & CPTitledWindowMask) || _isFullPlatformWindow));
2314 }
2315 
2319 - (void)makeMainWindow
2320 {
2321  if ([CPApp mainWindow] === self || ![self canBecomeMainWindow])
2322  return;
2323 
2324  [[CPApp mainWindow] resignMainWindow];
2325  [self becomeMainWindow];
2326 }
2327 
2331 - (void)becomeMainWindow
2332 {
2333  CPApp._mainWindow = self;
2334 
2335  [self _synchronizeMenuBarTitleWithWindowTitle];
2336  [self _synchronizeSaveMenuWithDocumentSaving];
2337 
2338  [_windowView noteMainWindowStateChanged];
2339 
2341  postNotificationName:CPWindowDidBecomeMainNotification
2342  object:self];
2343 }
2344 
2348 - (void)resignMainWindow
2349 {
2351  postNotificationName:CPWindowDidResignMainNotification
2352  object:self];
2353 
2354  if (CPApp._mainWindow === self)
2355  CPApp._mainWindow = nil;
2356 
2357  [_windowView noteMainWindowStateChanged];
2358 }
2359 
2360 - (void)_updateMainAndKeyWindows
2361 {
2362  var allWindows = [CPApp orderedWindows],
2363  windowCount = [allWindows count];
2364 
2365  if ([self isKeyWindow])
2366  {
2367  var keyWindow = [CPApp keyWindow];
2368  [self resignKeyWindow];
2369 
2370  if (keyWindow && keyWindow !== self && [keyWindow canBecomeKeyWindow])
2371  [keyWindow makeKeyWindow];
2372  else
2373  {
2374  var mainMenu = [CPApp mainMenu],
2375  menuBarClass = objj_getClass("_CPMenuBarWindow"),
2376  menuWindow;
2377 
2378  for (var i = 0; i < windowCount; i++)
2379  {
2380  var currentWindow = allWindows[i];
2381 
2382  if ([currentWindow isKindOfClass:menuBarClass])
2383  menuWindow = currentWindow;
2384 
2385  if (currentWindow === self || currentWindow === menuWindow)
2386  continue;
2387 
2388  if ([currentWindow isVisible] && [currentWindow canBecomeKeyWindow])
2389  {
2390  [currentWindow makeKeyWindow];
2391  break;
2392  }
2393  }
2394 
2395  if (![CPApp keyWindow])
2396  [menuWindow makeKeyWindow];
2397  }
2398  }
2399 
2400  if ([self isMainWindow])
2401  {
2402  var mainWindow = [CPApp mainWindow];
2403  [self resignMainWindow];
2404 
2405  if (mainWindow && mainWindow !== self && [mainWindow canBecomeMainWindow])
2406  [mainWindow makeMainWindow];
2407  else
2408  {
2409  var mainMenu = [CPApp mainMenu],
2410  menuBarClass = objj_getClass("_CPMenuBarWindow"),
2411  menuWindow;
2412 
2413  for (var i = 0; i < windowCount; i++)
2414  {
2415  var currentWindow = allWindows[i];
2416 
2417  if ([currentWindow isKindOfClass:menuBarClass])
2418  menuWindow = currentWindow;
2419 
2420  if (currentWindow === self || currentWindow === menuWindow)
2421  continue;
2422 
2423  if ([currentWindow isVisible] && [currentWindow canBecomeMainWindow])
2424  {
2425  [currentWindow makeMainWindow];
2426  break;
2427  }
2428  }
2429  }
2430  }
2431 }
2432 
2433 // Managing Toolbars
2437 - (CPToolbar)toolbar
2438 {
2439  return _toolbar;
2440 }
2441 
2446 - (void)setToolbar:(CPToolbar)aToolbar
2447 {
2448  if (_toolbar === aToolbar)
2449  return;
2450 
2451  // If this has an owner, dump it!
2452  [[aToolbar _window] setToolbar:nil];
2453 
2454  // This is no longer out toolbar.
2455  [_toolbar _setWindow:nil];
2456 
2457  _toolbar = aToolbar;
2458 
2459  // THIS is our toolbar.
2460  [_toolbar _setWindow:self];
2461 
2462  [self _noteToolbarChanged];
2463 }
2464 
2465 - (void)toggleToolbarShown:(id)aSender
2466 {
2467  var toolbar = [self toolbar];
2468 
2469  [toolbar setVisible:![toolbar isVisible]];
2470 }
2471 
2472 - (void)_noteToolbarChanged
2473 {
2474  var frame = _CGRectMakeCopy([self frame]),
2475  newFrame;
2476 
2477  [_windowView noteToolbarChanged];
2478 
2479  if (_isFullPlatformWindow)
2480  newFrame = [_platformWindow visibleFrame];
2481  else
2482  {
2483  newFrame = _CGRectMakeCopy([self frame]);
2484 
2485  newFrame.origin = frame.origin;
2486  }
2487 
2488  [self setFrame:newFrame];
2489  /*
2490  [_windowView setAnimatingToolbar:YES];
2491  [self setFrame:frame];
2492  [self setFrame:newFrame display:YES animate:YES];
2493  [_windowView setAnimatingToolbar:NO];
2494  */
2495 }
2496 
2497 - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
2498 {
2499  [_frameAnimation stopAnimation];
2500  _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
2501  [_frameAnimation setDelegate:delegate];
2502  [_frameAnimation setAnimationCurve:curve];
2503  [_frameAnimation setDuration:duration];
2504  [_frameAnimation startAnimation];
2505 }
2506 
2507 - (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
2508 {
2509  return CPWindowResizeTime;
2510 }
2511 
2512 /* @ignore */
2513 - (void)_setAttachedSheetFrameOrigin
2514 {
2515  // Position the sheet above the contentRect.
2516  var attachedSheet = [self attachedSheet],
2517  contentRect = [_contentView frame],
2518  sheetFrame = _CGRectMakeCopy([attachedSheet frame]);
2519 
2520  sheetFrame.origin.y = _CGRectGetMinY(_frame) + _CGRectGetMinY(contentRect);
2521  sheetFrame.origin.x = _CGRectGetMinX(_frame) + FLOOR((_CGRectGetWidth(_frame) - _CGRectGetWidth(sheetFrame)) / 2.0);
2522 
2523  [attachedSheet setFrame:sheetFrame display:YES animate:NO];
2524 }
2525 
2526 /* @ignore
2527  Starting point for sheet session, called from CPApplication beginSheet:
2528 */
2529 - (void)_attachSheet:(CPWindow)aSheet modalDelegate:(id)aModalDelegate
2530  didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
2531 {
2532  if (_sheetContext)
2533  {
2534  [CPException raise:CPInternalInconsistencyException
2535  reason:@"The target window of beginSheet: already has a sheet, did you forget orderOut: ?"];
2536  return;
2537  }
2538 
2539  var sheetFrame = [aSheet frame];
2540 
2541  _sheetContext = {"sheet": aSheet, "modalDelegate": aModalDelegate, "endSelector": aDidEndSelector,
2542  "contextInfo": aContextInfo, "frame": _CGRectMakeCopy(sheetFrame), "returnCode": -1,
2543  "opened": NO};
2544 
2545  [self _attachSheetWindow];
2546 }
2547 
2548 /* @ignore
2549  Called to animate the sheet in. The timer seems to solve a bug where sheets would
2550  be partially animated under certain conditions.
2551 */
2552 - (void)_attachSheetWindow
2553 {
2554  _sheetContext["isAttached"] = YES;
2555 
2556  // it would be ideal to block here and spin an event loop, until attach is complete
2558  target:self
2559  selector:@selector(_sheetShouldAnimateIn:)
2560  userInfo:nil
2561  repeats:NO];
2562 }
2563 
2564 /* @ignore
2565  Called to end the sheet. Note that orderOut: is needed to animate the sheet out, as in Cocoa.
2566  The sheet isn't completely gone until _cleanupSheetWindow gets called.
2567 */
2568 - (void)_endSheet
2569 {
2570  var delegate = _sheetContext["modalDelegate"],
2571  endSelector = _sheetContext["endSelector"];
2572 
2573  // If the sheet has been ordered out, defer didEndSelector until after sheet animates out.
2574  // This must be done since we cannot block and wait for the animation to complete.
2575  if (delegate && endSelector)
2576  {
2577  if (_sheetContext["isAttached"])
2578  objj_msgSend(delegate, endSelector, _sheetContext["sheet"], _sheetContext["returnCode"],
2579  _sheetContext["contextInfo"]);
2580  else
2581  _sheetContext["deferDidEndSelector"] = YES;
2582  }
2583 }
2584 
2585 /* @ignore
2586  Called to animate the sheet out. If called while animating in, schedules an animate
2587  out at completion
2588 */
2589 - (void)_detachSheetWindow
2590 {
2591  _sheetContext["isAttached"] = NO;
2592 
2593  // it would be ideal to block here and spin the event loop, until attach is complete
2595  target:self
2596  selector:@selector(_sheetShouldAnimateOut:)
2597  userInfo:nil
2598  repeats:NO];
2599 }
2600 
2601 /* @ignore
2602  Called to cleanup sheet, when we are definitely done with it
2603 */
2604 - (void)_cleanupSheetWindow
2605 {
2606  var sheet = _sheetContext["sheet"],
2607  lastFrame = _sheetContext["frame"],
2608  deferDidEnd = _sheetContext["deferDidEndSelector"];
2609 
2610  [sheet setFrame:lastFrame];
2611  [self _restoreMasksForView:[sheet contentView]];
2612 
2613  // if the parent window is modal, the sheet started its own modal session
2614  if (sheet._isModal)
2615  [CPApp stopModal];
2616 
2617  // restore the state of window before it was sheetified
2618  [sheet._windowView _enableSheet:NO];
2619 
2620  // close it
2621  sheet._isSheet = NO;
2622  [sheet orderOut:self];
2623 
2624  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self];
2625 
2626  if (deferDidEnd)
2627  {
2628  var delegate = _sheetContext["modalDelegate"],
2629  selector = _sheetContext["endSelector"],
2630  returnCode = _sheetContext["returnCode"],
2631  contextInfo = _sheetContext["contextInfo"];
2632 
2633  // context must be destroyed, since didEnd might want to attach another sheet
2634  _sheetContext = nil;
2635  sheet._parentView = nil;
2636 
2637  objj_msgSend(delegate, selector, sheet, returnCode, contextInfo);
2638  }
2639  else
2640  {
2641  _sheetContext = nil;
2642  sheet._parentView = nil;
2643  }
2644 }
2645 
2646 /* @ignore */
2647 - (void)animationDidEnd:(id)anim
2648 {
2649  var sheet = _sheetContext["sheet"];
2650 
2651  if (anim._window != sheet)
2652  return;
2653 
2655  target:self
2656  selector:@selector(_sheetAnimationDidEnd:)
2657  userInfo:nil
2658  repeats:NO];
2659 }
2660 
2661 /* @ignore */
2662 - (void)_sheetShouldAnimateIn:(CPTimer)timer
2663 {
2664  // can't open sheet while opening or closing animation is going on
2665  if (_sheetContext["isOpening"] ||
2666  _sheetContext["isClosing"])
2667  return;
2668 
2669  var sheet = _sheetContext["sheet"],
2670  sheetFrame = [sheet frame],
2671  frame = [self frame];
2672 
2673  [self _setUpMasksForView:[sheet contentView]];
2674 
2675  sheet._isSheet = YES;
2676  sheet._parentView = self;
2677 
2678  var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2),
2679  originy = frame.origin.y + [_contentView frame].origin.y,
2680  startFrame = _CGRectMake(originx, originy, sheetFrame.size.width, 0),
2681  endFrame = _CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height);
2682 
2683  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self];
2684 
2685  // if sheet is attached to a modal window, the sheet runs
2686  // as if itself and the parent window are modal
2687  sheet._isModal = NO;
2688 
2689  if ([CPApp modalWindow] === self)
2690  {
2691  [CPApp runModalForWindow:sheet];
2692  sheet._isModal = YES;
2693  }
2694 
2695  [sheet orderFront:self];
2696  [sheet setFrame:startFrame display:YES animate:NO];
2697 
2698  _sheetContext["opened"] = YES;
2699  _sheetContext["shouldClose"] = NO;
2700  _sheetContext["isOpening"] = YES;
2701 
2702  [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
2703 
2704  // NOTE: cocoa doesn't make window key until animation is done, but a
2705  // keypress while animating eventually gets to the window. Therefore,
2706  // there must be a runloop specifically designed for sheets?
2707  [sheet makeKeyWindow];
2708 }
2709 
2710 /* @ignore */
2711 - (void)_sheetShouldAnimateOut:(CPTimer)timer
2712 {
2713  var sheet = _sheetContext["sheet"],
2714  startFrame = [sheet frame],
2715  endFrame = _CGRectMakeCopy(startFrame);
2716 
2717  if (_sheetContext["isOpening"])
2718  {
2719  // allow sheet to be closed while opening, it will close when animate in completes
2720  _sheetContext["shouldClose"] = YES;
2721  return;
2722  }
2723 
2724  if (_sheetContext["isClosing"])
2725  return;
2726 
2727  _sheetContext["opened"] = NO;
2728  _sheetContext["frame"] = startFrame;
2729  _sheetContext["isClosing"] = YES;
2730 
2731  // the parent window can be orderedOut to disable the sheet animate out, as in Cocoa
2732  if ([self isVisible])
2733  {
2734  endFrame.size.height = 0;
2735  [self _setUpMasksForView:[sheet contentView]];
2736  [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
2737  }
2738  else
2739  {
2740  [self _sheetAnimationDidEnd:nil];
2741  }
2742 }
2743 
2744 /* @ignore */
2745 - (void)_sheetAnimationDidEnd:(CPTimer)timer
2746 {
2747  var sheet = _sheetContext["sheet"];
2748 
2749  _sheetContext["isOpening"] = NO;
2750  _sheetContext["isClosing"] = NO;
2751 
2752  if (_sheetContext["opened"] === YES)
2753  {
2754  // sheet is open and completely visible
2755  [self _restoreMasksForView:[sheet contentView]];
2756 
2757  // we wanted to close the sheet while it animated in, do that now
2758  if (_sheetContext["shouldClose"] === YES)
2759  [self _detachSheetWindow];
2760  }
2761  else
2762  {
2763  // sheet is closed and not visible
2764  [self _cleanupSheetWindow];
2765  }
2766 }
2767 
2768 - (void)_setUpMasksForView:(CPView)aView
2769 {
2770  var views = [aView subviews];
2771 
2772  [views addObject:aView];
2773 
2774  for (var i = 0, count = [views count]; i < count; i++)
2775  {
2776  var view = [views objectAtIndex:i],
2777  mask = [view autoresizingMask],
2778  maskToAdd = (mask & CPViewMinYMargin) ? 128 : CPViewMinYMargin;
2779 
2780  [view setAutoresizingMask:(mask | maskToAdd)];
2781  }
2782 }
2783 
2784 - (void)_restoreMasksForView:(CPView)aView
2785 {
2786  var views = [aView subviews];
2787 
2788  [views addObject:aView];
2789 
2790  for (var i = 0, count = [views count]; i < count; i++)
2791  {
2792  var view = [views objectAtIndex:i],
2793  mask = [view autoresizingMask],
2794  maskToRemove = (mask & 128) ? 128 : CPViewMinYMargin;
2795 
2796  [view setAutoresizingMask:(mask & (~ maskToRemove))];
2797  }
2798 }
2799 
2803 - (CPWindow)attachedSheet
2804 {
2805  if (_sheetContext === nil)
2806  return nil;
2807 
2808  return _sheetContext["sheet"];
2809 }
2810 
2814 - (BOOL)isSheet
2815 {
2816  return _isSheet;
2817 }
2818 
2819 //
2820 /*
2821  Used privately.
2822  @ignore
2823 */
2824 - (BOOL)becomesKeyOnlyIfNeeded
2825 {
2826  return NO;
2827 }
2828 
2833 - (BOOL)worksWhenModal
2834 {
2835  return NO;
2836 }
2837 
2838 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
2839 {
2840  // FIXME: should we be starting at the root, in other words _windowView?
2841  // The evidence seems to point to no...
2842  return [_contentView performKeyEquivalent:anEvent];
2843 }
2844 
2845 - (void)keyDown:(CPEvent)anEvent
2846 {
2847  // It's not clear why we do performKeyEquivalent again here...
2848  // Perhaps to allow something to happen between sendEvent: and keyDown:?
2849  if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
2850  return;
2851 
2852  // Apple's documentation is inconsistent with their behavior here. According to the docs
2853  // an event going of the responder chain is passed to the input system as a last resort.
2854  // However, the only methods I could get Cocoa to call automatically are
2855  // moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
2856  // Unhandled events just travel further up the responder chain _past_ the window.
2857  if (![self _processKeyboardUIKey:anEvent])
2858  [super keyDown:anEvent];
2859 }
2860 
2861 /*
2862  @ignore
2863  Interprets the key event for action messages and sends the action message down the responder chain
2864  Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
2865  We deviate from this by sending (the default) scrollPageUp:, scrollPageDown:, scrollToBeginningOfDocument: and scrollToEndOfDocument: for pageUp, pageDown, home and end keys.
2866  @param anEvent the event to handle.
2867  @return YES if the key event was handled, NO if no responder handled the key event
2868 */
2869 - (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
2870 {
2871  var character = [anEvent charactersIgnoringModifiers];
2872 
2873  if (![CPWindowActionMessageKeys containsObject:character])
2874  return NO;
2875 
2876  var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
2877 
2878  if ([selectors count] <= 0)
2879  return NO;
2880 
2881  if (character !== CPEscapeFunctionKey)
2882  {
2883  var selector = [selectors objectAtIndex:0];
2884  return [[self firstResponder] tryToPerform:selector with:self];
2885  }
2886  else
2887  {
2888  /*
2889  Cocoa sends complete: for the escape key (instead of the default cancelOperation:). This is also the only action that is not sent directly to the first responder, but through doCommandBySelector. The difference is that doCommandBySelector: will also send the action to the window and application delegates.
2890  */
2891  [[self firstResponder] doCommandBySelector:@selector(complete:)];
2892  }
2893 
2894  return NO;
2895 }
2896 
2897 - (void)_dirtyKeyViewLoop
2898 {
2899  if (_autorecalculatesKeyViewLoop)
2900  _keyViewLoopIsDirty = YES;
2901 }
2902 
2903 /*
2904  Recursively traverse an array of views (depth last) until we find one that has a next or previous key view set. Return nil if none can be found.
2905 
2906  We don't use _viewsSortedByPosition here because it is wasteful to enumerate the entire view hierarchy when we will probably find a key view at the top level.
2907 */
2908 - (BOOL)_hasKeyViewLoop:(CPArray)theViews
2909 {
2910  var i,
2911  count = [theViews count];
2912 
2913  for (i = 0; i < count; ++i)
2914  {
2915  var view = theViews[i];
2916 
2917  if ([view nextKeyView] || [view previousKeyView])
2918  return YES;
2919  }
2920 
2921  for (i = 0; i < count; ++i)
2922  {
2923  var subviews = [theViews[i] subviews];
2924 
2925  if ([subviews count] && [self _hasKeyViewLoop:subviews])
2926  return YES;
2927  }
2928 
2929  return NO;
2930 }
2931 
2939 - (void)recalculateKeyViewLoop
2940 {
2941  [self _doRecalculateKeyViewLoop];
2942 }
2943 
2944 - (CPArray)_viewsSortedByPosition
2945 {
2946  var views = [CPArray arrayWithObject:_contentView];
2947 
2948  views = views.concat([self _subviewsSortedByPosition:[_contentView subviews]]);
2949 
2950  return views;
2951 }
2952 
2953 - (CPArray)_subviewsSortedByPosition:(CPArray)theSubviews
2954 {
2955  /*
2956  We first sort the subviews according to geometric order.
2957  Then we go through each subview, and if it has subviews,
2958  they are sorted and inserted after the superview. This
2959  is done recursively.
2960  */
2961  theSubviews = [theSubviews copy];
2962  [theSubviews sortUsingFunction:keyViewComparator context:nil];
2963 
2964  var sortedViews = [];
2965 
2966  for (var i = 0, count = [theSubviews count]; i < count; ++i)
2967  {
2968  var view = theSubviews[i],
2969  subviews = [view subviews];
2970 
2971  sortedViews.push(view);
2972 
2973  if ([subviews count])
2974  sortedViews = sortedViews.concat([self _subviewsSortedByPosition:subviews]);
2975  }
2976 
2977  return sortedViews;
2978 }
2979 
2980 - (void)_doRecalculateKeyViewLoop
2981 {
2982  var views = [self _viewsSortedByPosition];
2983 
2984  for (var index = 0, count = [views count]; index < count; ++index)
2985  [views[index] setNextKeyView:views[(index + 1) % count]];
2986 
2987  _keyViewLoopIsDirty = NO;
2988 }
2989 
2990 - (void)setAutorecalculatesKeyViewLoop:(BOOL)shouldRecalculate
2991 {
2992  if (_autorecalculatesKeyViewLoop === shouldRecalculate)
2993  return;
2994 
2995  _autorecalculatesKeyViewLoop = shouldRecalculate;
2996 }
2997 
2998 - (BOOL)autorecalculatesKeyViewLoop
2999 {
3000  return _autorecalculatesKeyViewLoop;
3001 }
3002 
3003 - (void)selectNextKeyView:(id)sender
3004 {
3005  if (_keyViewLoopIsDirty)
3006  [self _doRecalculateKeyViewLoop];
3007 
3008  var nextValidKeyView = nil;
3009 
3010  if ([_firstResponder isKindOfClass:[CPView class]])
3011  nextValidKeyView = [_firstResponder nextValidKeyView];
3012 
3013  if (!nextValidKeyView)
3014  {
3015  if ([_initialFirstResponder acceptsFirstResponder])
3016  nextValidKeyView = _initialFirstResponder;
3017  else
3018  nextValidKeyView = [_initialFirstResponder nextValidKeyView];
3019  }
3020 
3021  if (nextValidKeyView)
3022  [self makeFirstResponder:nextValidKeyView];
3023 }
3024 
3025 - (void)selectPreviousKeyView:(id)sender
3026 {
3027  if (_keyViewLoopIsDirty)
3028  [self _doRecalculateKeyViewLoop];
3029 
3030  var previousValidKeyView = nil;
3031 
3032  if ([_firstResponder isKindOfClass:[CPView class]])
3033  previousValidKeyView = [_firstResponder previousValidKeyView];
3034 
3035  if (!previousValidKeyView)
3036  {
3037  if ([_initialFirstResponder acceptsFirstResponder])
3038  previousValidKeyView = _initialFirstResponder;
3039  else
3040  previousValidKeyView = [_initialFirstResponder previousValidKeyView];
3041  }
3042 
3043  if (previousValidKeyView)
3044  [self makeFirstResponder:previousValidKeyView];
3045 }
3046 
3047 - (void)selectKeyViewFollowingView:(CPView)aView
3048 {
3049  if (_keyViewLoopIsDirty)
3050  [self _doRecalculateKeyViewLoop];
3051 
3052  var nextValidKeyView = [aView nextValidKeyView];
3053 
3054  if ([nextValidKeyView isKindOfClass:[CPView class]])
3055  [self makeFirstResponder:nextValidKeyView];
3056 }
3057 
3058 - (void)selectKeyViewPrecedingView:(CPView)aView
3059 {
3060  if (_keyViewLoopIsDirty)
3061  [self _doRecalculateKeyViewLoop];
3062 
3063  var previousValidKeyView = [aView previousValidKeyView];
3064 
3065  if ([previousValidKeyView isKindOfClass:[CPView class]])
3066  [self makeFirstResponder:previousValidKeyView];
3067 }
3068 
3074 - (void)setDefaultButtonCell:(CPButton)aButton
3075 {
3076  [self setDefaultButton:aButton];
3077 }
3078 
3083 - (CPButton)defaultButtonCell
3084 {
3085  return [self defaultButton];
3086 }
3087 
3094 - (void)setDefaultButton:(CPButton)aButton
3095 {
3096  if (_defaultButton === aButton)
3097  return;
3098 
3099  if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
3100  [_defaultButton setKeyEquivalent:nil];
3101 
3102  _defaultButton = aButton;
3103 
3104  if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
3105  [_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
3106 }
3107 
3111 - (CPButton)defaultButton
3112 {
3113  return _defaultButton;
3114 }
3115 
3119 - (void)enableKeyEquivalentForDefaultButton
3120 {
3121  _defaultButtonEnabled = YES;
3122 }
3123 
3128 - (void)enableKeyEquivalentForDefaultButtonCell
3129 {
3131 }
3132 
3136 - (void)disableKeyEquivalentForDefaultButton
3137 {
3138  _defaultButtonEnabled = NO;
3139 }
3140 
3145 - (void)disableKeyEquivalentForDefaultButtonCell
3146 {
3148 }
3149 
3150 @end
3151 
3152 var keyViewComparator = function(lhs, rhs, context)
3153 {
3154  var lhsBounds = [lhs convertRect:[lhs bounds] toView:nil],
3155  rhsBounds = [rhs convertRect:[rhs bounds] toView:nil],
3156  lhsY = _CGRectGetMinY(lhsBounds),
3157  rhsY = _CGRectGetMinY(rhsBounds),
3158  lhsX = _CGRectGetMinX(lhsBounds),
3159  rhsX = _CGRectGetMinX(rhsBounds),
3160  intersectsVertically = MIN(_CGRectGetMaxY(lhsBounds), _CGRectGetMaxY(rhsBounds)) - MAX(lhsY, rhsY);
3161 
3162  // If two views are "on the same line" (intersect vertically), then rely on the x comparison.
3163  if (intersectsVertically > 0)
3164  {
3165  if (lhsX < rhsX)
3166  return CPOrderedAscending;
3167 
3168  if (lhsX === rhsX)
3169  return CPOrderedSame;
3170 
3171  return CPOrderedDescending;
3172  }
3173 
3174  if (lhsY < rhsY)
3175  return CPOrderedAscending;
3176 
3177  if (lhsY === rhsY)
3178  return CPOrderedSame;
3179 
3180  return CPOrderedDescending;
3181 };
3182 
3183 @implementation CPWindow (MenuBar)
3184 
3185 - (void)_synchronizeMenuBarTitleWithWindowTitle
3186 {
3187  // Windows with Documents automatically update the native window title and the menu bar title.
3188  if (![_windowController document] || ![self isMainWindow])
3189  return;
3190 
3191  [CPMenu setMenuBarTitle:_title];
3192 }
3193 
3194 @end
3195 
3197 
3198 /*
3199  @ignore
3200 */
3201 - (void)resizeWithOldPlatformWindowSize:(CGSize)aSize
3202 {
3203  if ([self isFullPlatformWindow])
3204  return [self setFrame:[_platformWindow visibleFrame]];
3205 
3206  if (_autoresizingMask == CPWindowNotSizable)
3207  return;
3208 
3209  var frame = [_platformWindow contentBounds],
3210  newFrame = _CGRectMakeCopy(_frame),
3211  dX = (_CGRectGetWidth(frame) - aSize.width) /
3212  (((_autoresizingMask & CPWindowMinXMargin) ? 1 : 0) + (_autoresizingMask & CPWindowWidthSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxXMargin ? 1 : 0)),
3213  dY = (_CGRectGetHeight(frame) - aSize.height) /
3214  ((_autoresizingMask & CPWindowMinYMargin ? 1 : 0) + (_autoresizingMask & CPWindowHeightSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxYMargin ? 1 : 0));
3215 
3216  if (_autoresizingMask & CPWindowMinXMargin)
3217  newFrame.origin.x += dX;
3218  if (_autoresizingMask & CPWindowWidthSizable)
3219  newFrame.size.width += dX;
3220 
3221  if (_autoresizingMask & CPWindowMinYMargin)
3222  newFrame.origin.y += dY;
3223  if (_autoresizingMask & CPWindowHeightSizable)
3224  newFrame.size.height += dY;
3225 
3226  [self setFrame:newFrame];
3227 }
3228 
3229 /*
3230  @ignore
3231 */
3232 - (void)setAutoresizingMask:(unsigned)anAutoresizingMask
3233 {
3234  _autoresizingMask = anAutoresizingMask;
3235 }
3236 
3237 /*
3238  @ignore
3239 */
3240 - (unsigned)autoresizingMask
3241 {
3242  return _autoresizingMask;
3243 }
3244 
3248 - (CGPoint)convertBaseToGlobal:(CGPoint)aPoint
3249 {
3250  return [CPPlatform isBrowser] ? [self convertBaseToPlatformWindow:aPoint] : [self convertBaseToScreen:aPoint];
3251 }
3252 
3256 - (CGPoint)convertGlobalToBase:(CGPoint)aPoint
3257 {
3258  return [CPPlatform isBrowser] ? [self convertPlatformWindowToBase:aPoint] : [self convertScreenToBase:aPoint];
3259 }
3260 
3264 - (CGPoint)convertBaseToPlatformWindow:(CGPoint)aPoint
3265 {
3266  if ([self _sharesChromeWithPlatformWindow])
3267  return _CGPointMakeCopy(aPoint);
3268 
3269  var origin = [self frame].origin;
3270 
3271  return _CGPointMake(aPoint.x + origin.x, aPoint.y + origin.y);
3272 }
3273 
3277 - (CGPoint)convertPlatformWindowToBase:(CGPoint)aPoint
3278 {
3279  if ([self _sharesChromeWithPlatformWindow])
3280  return _CGPointMakeCopy(aPoint);
3281 
3282  var origin = [self frame].origin;
3283 
3284  return _CGPointMake(aPoint.x - origin.x, aPoint.y - origin.y);
3285 }
3286 
3287 - (CGPoint)convertScreenToBase:(CGPoint)aPoint
3288 {
3289  return [self convertPlatformWindowToBase:[_platformWindow convertScreenToBase:aPoint]];
3290 }
3291 
3292 - (CGPoint)convertBaseToScreen:(CGPoint)aPoint
3293 {
3294  return [_platformWindow convertBaseToScreen:[self convertBaseToPlatformWindow:aPoint]];
3295 }
3296 
3297 - (void)_setSharesChromeWithPlatformWindow:(BOOL)shouldShareFrameWithPlatformWindow
3298 {
3299  // We canna' do it captain! We just don't have the power!
3300  if (shouldShareFrameWithPlatformWindow && [CPPlatform isBrowser])
3301  return;
3302 
3303  _sharesChromeWithPlatformWindow = shouldShareFrameWithPlatformWindow;
3304 
3305  [self _updateShadow];
3306 }
3307 
3308 - (BOOL)_sharesChromeWithPlatformWindow
3309 {
3310  return _sharesChromeWithPlatformWindow;
3311 }
3312 
3313 // Undo and Redo Support
3317 - (CPUndoManager)undoManager
3318 {
3319  // If we've ever created an undo manager, return it.
3320  if (_undoManager)
3321  return _undoManager;
3322 
3323  // If not, check to see if the document has one.
3324  var documentUndoManager = [[_windowController document] undoManager];
3325 
3326  if (documentUndoManager)
3327  return documentUndoManager;
3328 
3329  // If not, check to see if the delegate has one.
3330  if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
3331  return [_delegate windowWillReturnUndoManager:self];
3332 
3333  // If not, create one.
3334  if (!_undoManager)
3335  _undoManager = [[CPUndoManager alloc] init];
3336 
3337  return _undoManager;
3338 }
3339 
3344 - (void)undo:(id)aSender
3345 {
3346  [[self undoManager] undo];
3347 }
3348 
3353 - (void)redo:(id)aSender
3354 {
3355  [[self undoManager] redo];
3356 }
3357 
3358 - (BOOL)containsPoint:(CGPoint)aPoint
3359 {
3360  return _CGRectContainsPoint(_frame, aPoint);
3361 }
3362 
3363 - (BOOL)_isValidMousePoint:(CGPoint)aPoint
3364 {
3365  // If we are using the new resizing mode, mouse events are valid
3366  // outside the window's frame for non-full platform windows.
3367  var mouseFrame = (!_isFullPlatformWindow && (_styleMask & CPResizableWindowMask) && (CPWindowResizeStyle === CPWindowResizeStyleModern)) ? _CGRectInset(_frame, -CPWindowResizeSlop, -CPWindowResizeSlop) : _frame;
3368 
3369  return _CGRectContainsPoint(mouseFrame, aPoint);
3370 }
3371 
3372 @end
3373 
3374 @implementation CPWindow (Deprecated)
3379 - (void)setFullBridge:(BOOL)shouldBeFullBridge
3380 {
3381  [self setFullPlatformWindow:shouldBeFullBridge];
3382 }
3383 
3388 - (BOOL)isFullBridge
3389 {
3390  return [self isFullPlatformWindow];
3391 }
3392 
3393 /*
3394  @ignore
3395 */
3396 - (CGPoint)convertBaseToBridge:(CGPoint)aPoint
3397 {
3398  return [self convertBaseToPlatformWindow:aPoint];
3399 }
3400 
3401 /*
3402  @ignore
3403 */
3404 - (CGPoint)convertBridgeToBase:(CGPoint)aPoint
3405 {
3406  return [self convertPlatformWindowToBase:aPoint];
3407 }
3408 
3409 @end
3410 
3411 var interpolate = function(fromValue, toValue, progress)
3412 {
3413  return fromValue + (toValue - fromValue) * progress;
3414 };
3415 
3416 /* @ignore */
3417 @implementation _CPWindowFrameAnimation : CPAnimation
3418 {
3419  CPWindow _window;
3420 
3421  CGRect _startFrame;
3422  CGRect _targetFrame;
3423 }
3424 
3425 - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
3426 {
3427  self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
3428 
3429  if (self)
3430  {
3431  _window = aWindow;
3432 
3433  _targetFrame = _CGRectMakeCopy(aTargetFrame);
3434  _startFrame = _CGRectMakeCopy([_window frame]);
3435  }
3436 
3437  return self;
3438 }
3439 
3440 - (void)startAnimation
3441 {
3442  [super startAnimation];
3443 
3444  _window._isAnimating = YES;
3445 }
3446 
3447 - (void)setCurrentProgress:(float)aProgress
3448 {
3449  [super setCurrentProgress:aProgress];
3450 
3451  var value = [self currentValue];
3452 
3453  if (value == 1.0)
3454  _window._isAnimating = NO;
3455 
3456  var newFrame = _CGRectMake(
3457  interpolate(_CGRectGetMinX(_startFrame), _CGRectGetMinX(_targetFrame), value),
3458  interpolate(_CGRectGetMinY(_startFrame), _CGRectGetMinY(_targetFrame), value),
3459  interpolate(_CGRectGetWidth(_startFrame), _CGRectGetWidth(_targetFrame), value),
3460  interpolate(_CGRectGetHeight(_startFrame), _CGRectGetHeight(_targetFrame), value));
3461 
3462  [_window setFrame:newFrame display:YES animate:NO];
3463 }
3464 
3465 @end
3466 
3467 function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasShadow, aLevel)
3468 {
3469  return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel };
3470 }
3471 
3476 
3477