API  0.9.8
 All Classes Files Functions Variables Typedefs 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 #if PLATFORM(BROWSER)
25 #endif
26 
27 
28 @global CPApp
29 
30 @typedef _CPWindowFullPlatformWindowSession
31 
32 
34 
35 @optional
36 - (BOOL)windowShouldClose:(CPWindow)aWindow;
37 - (CPUndoManager)windowWillReturnUndoManager:(CPWindow)window;
38 - (void)windowDidBecomeKey:(CPNotification)aNotification;
39 - (void)windowDidBecomeMain:(CPNotification)aNotification;
40 - (void)windowDidEndSheet:(CPNotification)aNotification;
41 - (void)windowDidMove:(CPNotification)aNotification;
42 - (void)windowDidResignKey:(CPNotification)aNotification;
43 - (void)windowDidResignMain:(CPNotification)aNotification;
44 - (void)windowDidResize:(CPNotification)aNotification;
45 - (void)windowWillBeginSheet:(CPNotification)aNotification;
46 - (void)windowWillClose:(CPWindow)aWindow;
47 
48 @end
49 
51  CPWindowDelegate_windowWillReturnUndoManager_ = 1 << 2,
53 
55 
57  CPWindowResizeStyleGlobalChangeNotification = @"CPWindowResizeStyleGlobalChangeNotification",
58 
61 
62 /*
63  Keys for which action messages will be sent by default when unhandled, e.g. complete:.
64 */
66  CPLeftArrowFunctionKey,
67  CPRightArrowFunctionKey,
68  CPUpArrowFunctionKey,
69  CPDownArrowFunctionKey,
70  CPPageUpFunctionKey,
71  CPPageDownFunctionKey,
72  CPHomeFunctionKey,
73  CPEndFunctionKey,
74  CPEscapeFunctionKey
75  ];
76 
132 @implementation CPWindow : CPResponder
133 {
134  CPPlatformWindow _platformWindow;
135 
136  int _windowNumber;
137  unsigned _styleMask;
138  CGRect _frame;
139  int _level;
140  BOOL _isVisible;
141  BOOL _hasBeenOrderedIn;
142  BOOL _isMiniaturized;
143  BOOL _isAnimating;
144  BOOL _hasShadow;
145  BOOL _isMovableByWindowBackground;
146  BOOL _isMovable;
147  BOOL _constrainsToUsableScreen;
148  unsigned _shadowStyle;
149  BOOL _showsResizeIndicator;
150 
151  int _positioningMask;
152  CGRect _positioningScreenRect;
153 
154  BOOL _isDocumentEdited;
155  BOOL _isDocumentSaving;
156 
157  CPImageView _shadowView;
158 
159  CPView _windowView;
160  CPView _contentView;
161  CPView _toolbarView;
162 
163  CPArray _mouseEnteredStack;
164  CPView _leftMouseDownView;
165  CPView _rightMouseDownView;
166 
167  CPToolbar _toolbar;
168  CPResponder _firstResponder;
169  CPResponder _initialFirstResponder;
170  BOOL _hasBecomeKeyWindow;
171  id <CPWindowDelegate> _delegate;
172  unsigned _implementedDelegateMethods;
173 
174  CPString _title;
175 
176  BOOL _acceptsMouseMovedEvents;
177  BOOL _ignoresMouseEvents;
178 
179  CPWindowController _windowController;
180 
181  CGSize _minSize;
182  CGSize _maxSize;
183 
184  CPUndoManager _undoManager;
185  CPURL _representedURL;
186 
187  CPSet _registeredDraggedTypes;
188  CPArray _registeredDraggedTypesArray;
189  CPCountedSet _inclusiveRegisteredDraggedTypes;
190 
191  CPButton _defaultButton;
192  BOOL _defaultButtonEnabled;
193 
194  BOOL _autorecalculatesKeyViewLoop;
195  BOOL _keyViewLoopIsDirty;
196 
197  BOOL _sharesChromeWithPlatformWindow;
198 
199  // Bridge Support
200 #if PLATFORM(DOM)
201  DOMElement _DOMElement;
202 #endif
203 
204  unsigned _autoresizingMask;
205 
206  BOOL _isFullPlatformWindow;
207  _CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
208 
209  CPWindow _parentWindow;
210  CPArray _childWindows;
211  CPWindowOrderingMode _childOrdering;
212 
213  CPDictionary _sheetContext;
214  CPWindow _parentView;
215  BOOL _isSheet;
216  _CPWindowFrameAnimation _frameAnimation;
217 }
218 
219 + (Class)_binderClassForBinding:(CPString)aBinding
220 {
221  if ([aBinding hasPrefix:CPDisplayPatternTitleBinding])
222  return [CPTitleWithPatternBinding class];
223 
224  return [super _binderClassForBinding:aBinding];
225 }
226 
227 - (id)init
228 {
229  return [self initWithContentRect:CGRectMakeZero() styleMask:CPTitledWindowMask];
230 }
231 
247 - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned)aStyleMask
248 {
249  self = [super init];
250 
251  if (self)
252  {
253  var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
254 
255  _frame = [windowViewClass frameRectForContentRect:aContentRect];
256  _constrainsToUsableScreen = YES;
257 
258  [self _setSharesChromeWithPlatformWindow:![CPPlatform isBrowser]];
259 
260  if ([CPPlatform isBrowser])
262  else
263  {
264  // give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
265  if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
266  {
267  var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
268  _frame.size.height = MIN(768.0, visibleFrame.size.height);
269  _frame.size.width = MIN(1024.0, visibleFrame.size.width);
270  _frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
271  _frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
272  }
273 
275  [self platformWindow]._only = self;
276  }
277 
278  _isFullPlatformWindow = NO;
279  _registeredDraggedTypes = [CPSet set];
280  _registeredDraggedTypesArray = [];
281  _acceptsMouseMovedEvents = YES;
282  _isMovable = YES;
283  _hasBeenOrderedIn = NO;
284 
285  _parentWindow = nil;
286  _childWindows = [];
287  _childOrdering = CPWindowOut;
288 
289  _isSheet = NO;
290  _sheetContext = nil;
291  _parentView = nil;
292 
293  // Set up our window number.
294  _windowNumber = [CPApp._windows count];
295  CPApp._windows[_windowNumber] = self;
296 
297  _styleMask = aStyleMask;
298 
299  [self setLevel:CPNormalWindowLevel];
300 
301  // Create our border view which is the actual root of our view hierarchy.
302  _windowView = [[windowViewClass alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)) styleMask:aStyleMask];
303 
304  [_windowView _setWindow:self];
305  [_windowView setNextResponder:self];
306 
307  // Size calculation needs _windowView
308  _minSize = [self _calculateMinSizeForProposedSize:CGSizeMake(0.0, 0.0)];
309  _maxSize = CGSizeMake(1000000.0, 1000000.0);
310 
311  [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
312 
313  // Create a generic content view.
314  [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
315 
316  _firstResponder = self;
317 
318 #if PLATFORM(DOM)
319  _DOMElement = document.createElement("div");
320 
321  _DOMElement.style.position = "absolute";
322  _DOMElement.style.visibility = "visible";
323  _DOMElement.style.zIndex = 0;
324 
325  if (![self _sharesChromeWithPlatformWindow])
326  {
327  CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, CGRectGetMinX(_frame), CGRectGetMinY(_frame));
328  }
329 
330  CPDOMDisplayServerSetStyleSize(_DOMElement, 1, 1);
331  CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement);
332 #endif
333 
334  [self setNextResponder:CPApp];
335 
336  [self setHasShadow:aStyleMask !== CPBorderlessWindowMask];
337 
338  if (aStyleMask & CPBorderlessBridgeWindowMask)
339  [self setFullPlatformWindow:YES];
340 
341  _autorecalculatesKeyViewLoop = NO;
342  _defaultButtonEnabled = YES;
343  _keyViewLoopIsDirty = NO;
344  _hasBecomeKeyWindow = NO;
345 
346  [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
347 
350  name:CPWindowResizeStyleGlobalChangeNotification
351  object:nil];
352  }
353 
354  return self;
355 }
356 
357 - (CPPlatformWindow)platformWindow
358 {
359  return _platformWindow;
360 }
361 
367 - (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow
368 {
369  var wasVisible = [self isVisible];
370 
371  // we have to close it first, otherwise we get a DOM exception.
372  if (wasVisible)
373  [self close];
374 
375  _platformWindow = aPlatformWindow;
376  [_platformWindow _setTitle:_title window:self];
377 
378  if (wasVisible)
379  [self orderFront:self];
380 }
381 
382 
386 + (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask
387 {
388  if (aStyleMask & CPHUDBackgroundWindowMask)
389  return _CPHUDWindowView;
390 
391  else if (aStyleMask === CPBorderlessWindowMask)
392  return _CPBorderlessWindowView;
393 
394  else if (aStyleMask & CPDocModalWindowMask)
395  return _CPDocModalWindowView;
396 
397  else if (aStyleMask & _CPModalWindowMask)
398  return _CPModalWindowView;
399 
400  return _CPStandardWindowView;
401 }
402 
403 + (Class)_windowViewClassForFullPlatformWindowStyleMask:(unsigned)aStyleMask
404 {
405  return _CPBorderlessBridgeWindowView;
406 }
407 
408 - (void)awakeFromCib
409 {
410  // At this time we know the final screen (or browser) size
411  // and can apply the positioning mask, if any, from the nib.
412  if (_positioningScreenRect)
413  {
414  var actualScreenRect = [CPPlatform isBrowser] ? [_platformWindow contentBounds] : [[self screen] visibleFrame],
415  frame = [self frame],
416  origin = frame.origin;
417 
418  if (actualScreenRect)
419  {
420  if ((_positioningMask & CPWindowPositionFlexibleLeft) && (_positioningMask & CPWindowPositionFlexibleRight))
421  {
422  // Proportional Horizontal.
423  origin.x *= (actualScreenRect.size.width / _positioningScreenRect.size.width);
424  }
425  else if (_positioningMask & CPWindowPositionFlexibleLeft)
426  {
427  // Fixed from Right
428  origin.x += actualScreenRect.size.width - _positioningScreenRect.size.width;
429  }
430  else if (_positioningMask & CPWindowPositionFlexibleRight)
431  {
432  // Fixed from Left
433  }
434 
435  if ((_positioningMask & CPWindowPositionFlexibleTop) && (_positioningMask & CPWindowPositionFlexibleBottom))
436  {
437  // Proportional Vertical.
438  origin.y *= (actualScreenRect.size.height / _positioningScreenRect.size.height);
439  }
440  else if (_positioningMask & CPWindowPositionFlexibleTop)
441  {
442  // Fixed from Bottom
443  origin.y += actualScreenRect.size.height - _positioningScreenRect.size.height;
444  }
445  else if (_positioningMask & CPWindowPositionFlexibleBottom)
446  {
447  // Fixed from Top
448  }
449 
450  [self setFrameOrigin:origin];
451  }
452  }
453 
454  /*
455  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.
456  */
457  if ([self _hasKeyViewLoop:[_contentView subviews]])
458  {
459  var views = [self _viewsSortedByPosition],
460  count = [views count];
461 
462  // The first view is the content view.
463  // Find the first subview that has a next key view.
464  for (var i = 1; i < count; ++i)
465  {
466  var view = views[i];
467 
468  if ([view nextKeyView])
469  {
470  [_contentView setNextKeyView:view];
471  break;
472  }
473  }
474  }
475  else
476  {
477  // Cooca does NOT call the public method recalculateKeyViewLoop for nibs,
478  // but it does calculate the loop.
479  [self _doRecalculateKeyViewLoop];
480  }
481 }
482 
483 - (void)_setWindowView:(CPView)aWindowView
484 {
485  if (_windowView === aWindowView)
486  return;
487 
488  var oldWindowView = _windowView;
489 
490  _windowView = aWindowView;
491 
492  if (oldWindowView)
493  {
494  [oldWindowView _setWindow:nil];
495  [oldWindowView noteToolbarChanged];
496 
497 #if PLATFORM(DOM)
498  CPDOMDisplayServerRemoveChild(_DOMElement, oldWindowView._DOMElement);
499 #endif
500  }
501 
502  if (_windowView)
503  {
504 #if PLATFORM(DOM)
505  CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement);
506 #endif
507 
508  var contentRect = [_contentView convertRect:[_contentView bounds] toView:nil];
509 
510  contentRect.origin = [self convertBaseToGlobal:contentRect.origin];
511 
512  [_windowView _setWindow:self];
513  [_windowView setNextResponder:self];
514  [_windowView addSubview:_contentView];
515  [_windowView setTitle:_title];
516  [_windowView noteToolbarChanged];
517  [_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
518 
519  [self setFrame:[self frameRectForContentRect:contentRect]];
520  }
521 }
522 
529 - (void)setFullPlatformWindow:(BOOL)shouldBeFullPlatformWindow
530 {
531  if (![_platformWindow supportsFullPlatformWindows])
532  return;
533 
534  shouldBeFullPlatformWindow = !!shouldBeFullPlatformWindow;
535 
536  if (_isFullPlatformWindow === shouldBeFullPlatformWindow)
537  return;
538 
539  _isFullPlatformWindow = shouldBeFullPlatformWindow;
540 
541  if (_isFullPlatformWindow)
542  {
543  _fullPlatformWindowSession = _CPWindowFullPlatformWindowSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]);
544 
545  var fullPlatformWindowViewClass = [[self class] _windowViewClassForFullPlatformWindowStyleMask:_styleMask],
546  windowView = [[fullPlatformWindowViewClass alloc] initWithFrame:CGRectMakeZero() styleMask:_styleMask];
547 
548  if (_platformWindow != [CPPlatformWindow primaryPlatformWindow] && [_platformWindow _hasInitializeInstanceWithWindow])
549  [_platformWindow setContentRect:[self frame]];
550 
551  [self _setWindowView:windowView];
552 
553  [self setLevel:CPBackgroundWindowLevel];
554  [self setHasShadow:NO];
555  [self setAutoresizingMask:CPWindowWidthSizable | CPWindowHeightSizable];
556  [self setFrame:[_platformWindow visibleFrame]];
557  }
558  else
559  {
560  var windowView = _fullPlatformWindowSession.windowView;
561 
562  [self _setWindowView:windowView];
563 
564  [self setLevel:_fullPlatformWindowSession.level];
565  [self setHasShadow:_fullPlatformWindowSession.hasShadow];
566  [self setAutoresizingMask:CPWindowNotSizable];
567 
568  [self setFrame:[windowView frameRectForContentRect:_fullPlatformWindowSession.contentRect]];
569  }
570 }
571 
575 - (BOOL)isFullPlatformWindow
576 {
577  return _isFullPlatformWindow;
578 }
579 
583 - (unsigned)styleMask
584 {
585  return _styleMask;
586 }
587 
606 + (CGRect)frameRectForContentRect:(CGRect)aContentRect styleMask:(unsigned)aStyleMask
607 {
608  return [[[self class] _windowViewClassForStyleMask:aStyleMask] frameRectForContentRect:aContentRect];
609 }
610 
615 - (CGRect)contentRectForFrameRect:(CGRect)aFrame
616 {
617  return [_windowView contentRectForFrameRect:aFrame];
618 }
619 
625 - (CGRect)frameRectForContentRect:(CGRect)aContentRect
626 {
627  return [_windowView frameRectForContentRect:aContentRect];
628 }
629 
633 - (CGRect)frame
634 {
635  return CGRectMakeCopy(_frame);
636 }
637 
645 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
646 {
647  [self _setFrame:aFrame display:shouldDisplay animate:shouldAnimate constrainWidth:NO constrainHeight:YES];
648 }
649 
650 - (void)_setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate constrainWidth:(BOOL)shouldConstrainWidth constrainHeight:(BOOL)shouldConstrainHeight
651 {
652  var frame = CGRectMakeCopy(aFrame),
653  value = frame.origin.x,
654  delta = value - FLOOR(value);
655 
656  if (delta)
657  frame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value);
658 
659  value = frame.origin.y;
660  delta = value - FLOOR(value);
661 
662  if (delta)
663  frame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value);
664 
665  value = frame.size.width;
666  delta = value - FLOOR(value);
667 
668  if (delta)
669  frame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value);
670 
671  value = frame.size.height;
672  delta = value - FLOOR(value);
673 
674  if (delta)
675  frame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value);
676 
677  frame = [self _constrainFrame:frame toUsableScreenWidth:shouldConstrainWidth andHeight:shouldConstrainHeight];
678 
679  if (shouldAnimate)
680  {
681  [_frameAnimation stopAnimation];
682  _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:frame];
683 
684  [_frameAnimation startAnimation];
685  }
686  else
687  {
688  var origin = _frame.origin,
689  newOrigin = frame.origin,
690  originMoved = !CGPointEqualToPoint(origin, newOrigin);
691 
692  if (originMoved)
693  {
694  delta = CGPointMake(newOrigin.x - origin.x, newOrigin.y - origin.y);
695  origin.x = newOrigin.x;
696  origin.y = newOrigin.y;
697 
698 #if PLATFORM(DOM)
699  if (![self _sharesChromeWithPlatformWindow])
700  {
701  CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, origin.x, origin.y);
702  }
703 #endif
704 
705  // reposition sheet
706  if ([self attachedSheet])
707  [self _setAttachedSheetFrameOrigin];
708 
709  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMoveNotification object:self];
710  }
711 
712  var size = _frame.size,
713  newSize = frame.size;
714 
715  if (!CGSizeEqualToSize(size, newSize))
716  {
717  size.width = newSize.width;
718  size.height = newSize.height;
719 
720  [_windowView setFrameSize:size];
721 
722  if (_hasShadow)
723  [_shadowView setNeedsLayout];
724 
725  if (!_isAnimating)
726  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
727  }
728 
729  if ([self _sharesChromeWithPlatformWindow])
730  [_platformWindow setContentRect:_frame];
731 
732  if (originMoved)
733  [self _moveChildWindows:delta];
734  }
735 
736  if ([_platformWindow _canUpdateContentRect] && _isFullPlatformWindow && _platformWindow != [CPPlatformWindow primaryPlatformWindow])
737  [_platformWindow setContentRect:aFrame];
738 }
739 
740 /*
741  Constrain a frame so that the window remains at least partially visible on screen,
742  moving or resizing the frame as necessary.
743 */
744 - (CGRect)_constrainFrame:(CGRect)aFrame toUsableScreenWidth:(BOOL)constrainWidth andHeight:(BOOL)constrainHeight
745 {
746  var frame = CGRectMakeCopy(aFrame);
747 
748  if (!_constrainsToUsableScreen || !_isVisible)
749  return frame;
750 
751  var usableRect = [_platformWindow usableContentFrame];
752 
753  if (constrainWidth)
754  {
755  // First move the frame right to ensure the left side is within the usable rect.
756  frame.origin.x = MAX(frame.origin.x, usableRect.origin.x);
757 
758  // Now move the frame left so that the right side is within the usable rect.
759  var maxX = MIN(CGRectGetMaxX(frame), CGRectGetMaxX(usableRect));
760  frame.origin.x = maxX - frame.size.width;
761 
762  // Finally, adjust the left + width to ensure the left side is within the usable rect.
763  var usableWidth = CGRectGetWidth(usableRect);
764 
765  if (CGRectGetWidth(frame) > usableWidth)
766  {
767  frame.origin.x = CGRectGetMinX(usableRect);
768  frame.size.width = MAX(usableWidth, _minSize.width);
769  }
770  }
771 
772  if (constrainHeight)
773  {
774  // First move the frame down to ensure the top is within the usable rect.
775  frame.origin.y = MAX(frame.origin.y, usableRect.origin.y);
776 
777  // Now move the frame up so that the bottom is within the usable rect.
778  var maxY = MIN(CGRectGetMaxY(frame), CGRectGetMaxY(usableRect));
779  frame.origin.y = maxY - frame.size.height;
780 
781  // Finally, adjust the top + height to ensure the top is within the usable rect.
782  var usableHeight = CGRectGetHeight(usableRect);
783 
784  if (CGRectGetHeight(frame) > usableHeight)
785  {
786  frame.origin.y = CGRectGetMinY(usableRect);
787  frame.size.height = MAX(usableHeight, _minSize.height);
788  }
789  }
790 
791  return frame;
792 }
793 
794 /*
795  Constrain the origin of a frame such that:
796 
797  - The window view's minimum resize width is kept onscreen at the left/right of the window.
798  - The top of the window is kept below the top of the usable content.
799  - The top of the contentView + CPWindowMinVisibleVerticalMargin is kept above the bottom of the usable content.
800 */
801 - (CGRect)_constrainOriginOfFrame:(CGRect)aFrame
802 {
803  var frame = CGRectMakeCopy(aFrame);
804 
805  if (!_constrainsToUsableScreen || !_isVisible)
806  return frame;
807 
808  var usableRect = [_platformWindow usableContentFrame],
809  minimumSize = [_windowView _minimumResizeSize];
810 
811  // First constrain x so that at least CPWindowMinVisibleHorizontalMargin is visible on the right
812  frame.origin.x = MAX(frame.origin.x, CGRectGetMinX(usableRect) + minimumSize.width - CGRectGetWidth(frame));
813 
814  // Now constrain x so that at least CPWindowMinVisibleHorizontalMargin is visible on the left
815  frame.origin.x = MIN(frame.origin.x, CGRectGetMaxX(usableRect) - minimumSize.width);
816 
817  // Now constrain y so that it is below the top of the usable content
818  frame.origin.y = MAX(frame.origin.y, CGRectGetMinY(usableRect));
819 
820  // Finally constrain y so that at least CPWindowMinVisibleHorizontalMargin is visible at the bottom
821  frame.origin.y = MIN(frame.origin.y, CGRectGetMaxY(usableRect) - CGRectGetMinY([_contentView frame]) - CPWindowMinVisibleVerticalMargin);
822 
823  return frame;
824 }
825 
826 - (void)_moveChildWindows:(CGPoint)delta
827 {
828  [_childWindows enumerateObjectsUsingBlock:function(childWindow)
829  {
830  var origin = [childWindow frame].origin;
831 
832  [childWindow setFrameOrigin:CGPointMake(origin.x + delta.x, origin.y + delta.y)];
833  }
834  ];
835 }
836 
842 - (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
843 {
844  [self setFrame:aFrame display:shouldDisplay animate:NO];
845 }
846 
851 - (void)setFrame:(CGRect)aFrame
852 {
853  [self setFrame:aFrame display:YES animate:NO];
854 }
855 
860 - (void)setFrameOrigin:(CGPoint)anOrigin
861 {
862  var frame = [self _constrainOriginOfFrame:CGRectMake(anOrigin.x, anOrigin.y, _frame.size.width, _frame.size.height)];
863  [self _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
864 }
865 
870 - (void)setFrameSize:(CGSize)aSize
871 {
872  [self setFrame:CGRectMake(CGRectGetMinX(_frame), CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
873 }
874 
879 - (void)orderFront:(id)aSender
880 {
881  [self orderWindow:CPWindowAbove relativeTo:0];
882 }
883 
884 - (void)_orderFront
885 {
886 
887 #if PLATFORM(DOM)
888 
889  if (!_isVisible)
890  [_platformWindow _setShouldUpdateContentRect:NO];
891 
892  // -dw- if a sheet is clicked, the parent window should come up too
893  if (_isSheet)
894  [_parentView orderFront:self];
895 
896  // Save the boolean since it will be updated in the method order:window:relativeTo:
897  var wasVisible = _isVisible;
898 
899  [_platformWindow orderFront:self];
900  [_platformWindow order:CPWindowAbove window:self relativeTo:nil];
901 
902  // setFrame is set after ordering the window as this method can send some notifications
903  if (!wasVisible)
904  [self _setFrame:_frame display:YES animate:NO constrainWidth:YES constrainHeight:YES];
905 #endif
906 
907  if (!CPApp._keyWindow)
908  [self makeKeyWindow];
909 
910  if ([self isKeyWindow] && (_firstResponder === self || !_firstResponder))
911  [self makeFirstResponder:_initialFirstResponder];
912 
913  if (!CPApp._mainWindow)
914  [self makeMainWindow];
915 
916  [_platformWindow _setShouldUpdateContentRect:YES];
917 }
918 
919 /*
920  Called when a parent window orders in a child window directly.
921  without going through the ordering methods in CPWindow.
922 */
923 - (void)_parentDidOrderInChild
924 {
925 }
926 
927 /*
928  Called when the window is displayed in the DOM
929 */
930 - (void)_windowWillBeAddedToTheDOM
931 {
934  name:_CPPlatformWindowWillCloseNotification
935  object:_platformWindow];
936 
937  [[self contentView] _addObservers];
938 }
939 
940 /*
941  Called when the window is removed in the DOM
942 */
943 - (void)_windowWillBeRemovedFromTheDOM
944 {
945  [[CPNotificationCenter defaultCenter] removeObserver:self name:_CPPlatformWindowWillCloseNotification object:nil];
946 
947  [[self contentView] _removeObservers];
948 }
949 
950 
951 /*
952  Makes the receiver the last window in the screen ordering.
953  @param aSender the object that requested this
954  @ignore
955 */
956 - (void)orderBack:(id)aSender
957 {
958  [self orderWindow:CPWindowBelow relativeTo:0];
959 }
960 
961 - (void)_orderBack
962 {
963  // FIXME: Implement this
964 }
965 
970 - (void)orderOut:(id)aSender
971 {
972  [self orderWindow:CPWindowOut relativeTo:0];
973 }
974 
975 - (void)_orderOutRecursively:(BOOL)recursive
976 {
977  if (!_isVisible)
978  return;
979 
980  if ([self isSheet])
981  {
982  // -dw- as in Cocoa, orderOut: detaches the sheet and animates out
983  [self._parentView _detachSheetWindow];
984  return;
985  }
986 
987  if (recursive)
988  [_childWindows makeObjectsPerformSelector:@selector(_orderOutRecursively:) withObject:recursive];
989 
990 #if PLATFORM(DOM)
991  if ([self _sharesChromeWithPlatformWindow])
992  [_platformWindow orderOut:self];
993 
994  if (_isFullPlatformWindow && _platformWindow != [CPPlatformWindow primaryPlatformWindow])
995  [_platformWindow orderOut:self];
996 
997  [_platformWindow order:CPWindowOut window:self relativeTo:nil];
998 #endif
999 
1000  [self makeFirstResponder:nil];
1001  [self _updateMainAndKeyWindows];
1002 }
1003 
1009 - (void)orderWindow:(CPWindowOrderingMode)orderingMode relativeTo:(int)otherWindowNumber
1010 {
1011  if (orderingMode === CPWindowOut)
1012  {
1013  // Directly ordering out will detach a child window
1014  [_parentWindow removeChildWindow:self];
1015 
1016  // In Cocoa, a window orders out its child windows only if it has no parent
1017  [self _orderOutRecursively:!_parentWindow];
1018  }
1019  else if (orderingMode === CPWindowAbove && otherWindowNumber === 0)
1020  [self _orderFront];
1021  else if (orderingMode === CPWindowBelow && otherWindowNumber === 0)
1022  [self _orderBack];
1023 #if PLATFORM(DOM)
1024  else
1025  [_platformWindow order:orderingMode window:self relativeTo:CPApp._windows[otherWindowNumber]];
1026 #endif
1027 }
1028 
1033 - (void)setLevel:(int)aLevel
1034 {
1035  if (aLevel === _level)
1036  return;
1037 
1038  [_platformWindow moveWindow:self fromLevel:_level toLevel:aLevel];
1039 
1040  _level = aLevel;
1041  [_childWindows makeObjectsPerformSelector:@selector(setLevel:) withObject:_level];
1042 
1043  if ([self _sharesChromeWithPlatformWindow])
1044  [_platformWindow setLevel:aLevel];
1045 }
1046 
1050 - (int)level
1051 {
1052  return _level;
1053 }
1054 
1058 - (BOOL)isVisible
1059 {
1060  return _isVisible;
1061 }
1062 
1068 + (void)setGlobalResizeStyle:(int)aStyle
1069 {
1070  if (CPWindowResizeStyle === aStyle)
1071  return;
1072 
1073  CPWindowResizeStyle = aStyle;
1074  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowResizeStyleGlobalChangeNotification object:nil];
1075 }
1076 
1081 + (void)setConstrainWindowsToUsableScreen:(BOOL)shouldConstrain
1082 {
1083  CPWindowConstrainToScreen = shouldConstrain;
1084 }
1085 
1089 + (BOOL)constrainWindowsToUsableScreen
1090 {
1092 }
1093 
1094 - (void)_didReceiveResizeStyleChange:(CPNotification)aNotification
1095 {
1096  [_windowView setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
1097 }
1098 
1102 + (int)globalResizeStyle
1103 {
1104  return CPWindowResizeStyle;
1105 }
1106 
1110 - (BOOL)showsResizeIndicator
1111 {
1112  return _showsResizeIndicator;
1113 }
1114 
1119 - (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
1120 {
1121  shouldShowResizeIndicator = !!shouldShowResizeIndicator;
1122 
1123  if (_showsResizeIndicator === shouldShowResizeIndicator)
1124  return;
1125 
1126  _showsResizeIndicator = shouldShowResizeIndicator;
1127  [_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
1128 }
1129 
1133 - (CGSize)resizeIndicatorOffset
1134 {
1135  return [_windowView resizeIndicatorOffset];
1136 }
1137 
1142 - (void)setResizeIndicatorOffset:(CGSize)anOffset
1143 {
1144  [_windowView setResizeIndicatorOffset:anOffset];
1145 }
1146 
1152 - (void)setContentView:(CPView)aView
1153 {
1154  if (_contentView && _contentView !== aView)
1155  [_contentView removeFromSuperview];
1156 
1157  var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
1158 
1159  _contentView = aView;
1160  [_contentView setFrame:[self contentRectForFrameRect:bounds]];
1161 
1162  [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1163  [_windowView addSubview:_contentView];
1164 
1165  /*
1166  If the initial first responder has been set to something other than
1167  the window, set it to the window because it will no longer be valid.
1168  */
1169  if (_initialFirstResponder && _initialFirstResponder !== self)
1170  _initialFirstResponder = self;
1171 }
1172 
1176 - (CPView)contentView
1177 {
1178  return _contentView;
1179 }
1180 
1185 - (void)setAlphaValue:(float)aValue
1186 {
1187  [_windowView setAlphaValue:aValue];
1188 }
1189 
1193 - (float)alphaValue
1194 {
1195  return [_windowView alphaValue];
1196 }
1197 
1202 - (void)setBackgroundColor:(CPColor)aColor
1203 {
1204  [_windowView setBackgroundColor:aColor];
1205 }
1206 
1211 {
1212  return [_windowView backgroundColor];
1213 }
1214 
1222 - (void)setMinSize:(CGSize)aSize
1223 {
1224  if (CGSizeEqualToSize(_minSize, aSize))
1225  return;
1226 
1227  _minSize = [self _calculateMinSizeForProposedSize:aSize];
1228 
1229  var size = CGSizeMakeCopy([self frame].size),
1230  needsFrameChange = NO;
1231 
1232  if (size.width < _minSize.width)
1233  {
1234  size.width = _minSize.width;
1235  needsFrameChange = YES;
1236  }
1237 
1238  if (size.height < _minSize.height)
1239  {
1240  size.height = _minSize.height;
1241  needsFrameChange = YES;
1242  }
1243 
1244  if (needsFrameChange)
1245  [self setFrameSize:size];
1246 }
1247 
1251 - (CGSize)minSize
1252 {
1253  return _minSize;
1254 }
1255 
1257 - (CGSize)_calculateMinSizeForProposedSize:(CGSize)proposedSize
1258 {
1259  var contentFrame = [self contentRectForFrameRect:_frame],
1260  minHeight = CGRectGetHeight(_frame) - CGRectGetHeight(contentFrame);
1261 
1262  return CGSizeMake(MAX(proposedSize.width, 0), MAX(proposedSize.height, minHeight));
1263 }
1264 
1271 - (void)setMaxSize:(CGSize)aSize
1272 {
1273  if (CGSizeEqualToSize(_maxSize, aSize))
1274  return;
1275 
1276  _maxSize = CGSizeMakeCopy(aSize);
1277 
1278  var size = CGSizeMakeCopy([self frame].size),
1279  needsFrameChange = NO;
1280 
1281  if (size.width > _maxSize.width)
1282  {
1283  size.width = _maxSize.width;
1284  needsFrameChange = YES;
1285  }
1286 
1287  if (size.height > _maxSize.height)
1288  {
1289  size.height = _maxSize.height;
1290  needsFrameChange = YES;
1291  }
1292 
1293  if (needsFrameChange)
1294  [self setFrameSize:size];
1295 }
1296 
1300 - (CGSize)maxSize
1301 {
1302  return _maxSize;
1303 }
1304 
1308 - (BOOL)hasShadow
1309 {
1310  return _hasShadow;
1311 }
1312 
1313 - (void)_updateShadow
1314 {
1315  if ([self _sharesChromeWithPlatformWindow])
1316  {
1317  if (_shadowView)
1318  {
1319 #if PLATFORM(DOM)
1320  CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
1321 #endif
1322  _shadowView = nil;
1323  }
1324 
1325  [_platformWindow setHasShadow:_hasShadow];
1326 
1327  return;
1328  }
1329 
1330  if (_hasShadow && !_shadowView)
1331  {
1332  _shadowView = [[_CPShadowWindowView alloc] initWithFrame:CGRectMakeZero()];
1333 
1334  [_shadowView setWindowView:_windowView];
1335  [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1336  [_shadowView setNeedsLayout];
1337 
1338 #if PLATFORM(DOM)
1339  CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
1340 #endif
1341  }
1342  else if (!_hasShadow && _shadowView)
1343  {
1344 #if PLATFORM(DOM)
1345  CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
1346 #endif
1347  _shadowView = nil;
1348  }
1349 }
1350 
1355 - (void)setHasShadow:(BOOL)shouldHaveShadow
1356 {
1357  if (_hasShadow === shouldHaveShadow)
1358  return;
1359 
1360  _hasShadow = shouldHaveShadow;
1361 
1362  [self _updateShadow];
1363 }
1364 
1376 - (void)setShadowStyle:(unsigned)aStyle
1377 {
1378  _shadowStyle = aStyle;
1379 
1380  [[self platformWindow] setShadowStyle:_shadowStyle];
1381 }
1382 
1387 - (void)setDelegate:(id <CPWindowDelegate>)aDelegate
1388 {
1389  if (_delegate === aDelegate)
1390  return;
1391 
1392  var defaultCenter = [CPNotificationCenter defaultCenter];
1393 
1394  [defaultCenter removeObserver:_delegate name:CPWindowDidResignKeyNotification object:self];
1395  [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeKeyNotification object:self];
1396  [defaultCenter removeObserver:_delegate name:CPWindowDidBecomeMainNotification object:self];
1397  [defaultCenter removeObserver:_delegate name:CPWindowDidResignMainNotification object:self];
1398  [defaultCenter removeObserver:_delegate name:CPWindowDidMoveNotification object:self];
1399  [defaultCenter removeObserver:_delegate name:CPWindowDidResizeNotification object:self];
1400  [defaultCenter removeObserver:_delegate name:CPWindowWillBeginSheetNotification object:self];
1401  [defaultCenter removeObserver:_delegate name:CPWindowDidEndSheetNotification object:self];
1402 
1403  _delegate = aDelegate;
1404  _implementedDelegateMethods = 0;
1405 
1406  if ([_delegate respondsToSelector:@selector(windowShouldClose:)])
1407  _implementedDelegateMethods |= CPWindowDelegate_windowShouldClose_;
1408 
1409  if ([_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)])
1410  _implementedDelegateMethods |= CPWindowDelegate_windowWillReturnUndoManager_;
1411 
1412  if ([_delegate respondsToSelector:@selector(windowWillClose:)])
1413  _implementedDelegateMethods |= CPWindowDelegate_windowWillClose_;
1414 
1415  if ([_delegate respondsToSelector:@selector(windowDidResignKey:)])
1416  [defaultCenter
1417  addObserver:_delegate
1418  selector:@selector(windowDidResignKey:)
1419  name:CPWindowDidResignKeyNotification
1420  object:self];
1421 
1422  if ([_delegate respondsToSelector:@selector(windowDidBecomeKey:)])
1423  [defaultCenter
1424  addObserver:_delegate
1425  selector:@selector(windowDidBecomeKey:)
1426  name:CPWindowDidBecomeKeyNotification
1427  object:self];
1428 
1429  if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
1430  [defaultCenter
1431  addObserver:_delegate
1432  selector:@selector(windowDidBecomeMain:)
1433  name:CPWindowDidBecomeMainNotification
1434  object:self];
1435 
1436  if ([_delegate respondsToSelector:@selector(windowDidResignMain:)])
1437  [defaultCenter
1438  addObserver:_delegate
1439  selector:@selector(windowDidResignMain:)
1440  name:CPWindowDidResignMainNotification
1441  object:self];
1442 
1443  if ([_delegate respondsToSelector:@selector(windowDidMove:)])
1444  [defaultCenter
1445  addObserver:_delegate
1446  selector:@selector(windowDidMove:)
1447  name:CPWindowDidMoveNotification
1448  object:self];
1449 
1450  if ([_delegate respondsToSelector:@selector(windowDidResize:)])
1451  [defaultCenter
1452  addObserver:_delegate
1453  selector:@selector(windowDidResize:)
1454  name:CPWindowDidResizeNotification
1455  object:self];
1456 
1457  if ([_delegate respondsToSelector:@selector(windowWillBeginSheet:)])
1458  [defaultCenter
1459  addObserver:_delegate
1460  selector:@selector(windowWillBeginSheet:)
1461  name:CPWindowWillBeginSheetNotification
1462  object:self];
1463 
1464  if ([_delegate respondsToSelector:@selector(windowDidEndSheet:)])
1465  [defaultCenter
1466  addObserver:_delegate
1467  selector:@selector(windowDidEndSheet:)
1468  name:CPWindowDidEndSheetNotification
1469  object:self];
1470 }
1471 
1476 {
1477  return _delegate;
1478 }
1479 
1484 - (void)setWindowController:(CPWindowController)aWindowController
1485 {
1486  _windowController = aWindowController;
1487 }
1488 
1492 - (CPWindowController)windowController
1493 {
1494  return _windowController;
1495 }
1496 
1497 - (void)doCommandBySelector:(SEL)aSelector
1498 {
1499  if ([_delegate respondsToSelector:aSelector])
1500  [_delegate performSelector:aSelector];
1501  else
1502  [super doCommandBySelector:aSelector];
1503 }
1504 
1505 - (BOOL)acceptsFirstResponder
1506 {
1507  return NO;
1508 }
1509 
1510 - (CPView)initialFirstResponder
1511 {
1512  return _initialFirstResponder;
1513 }
1514 
1515 - (void)setInitialFirstResponder:(CPView)aView
1516 {
1517  _initialFirstResponder = aView;
1518 }
1519 
1520 - (void)_setupFirstResponder
1521 {
1522  /*
1523  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.
1524  */
1525  if (!_hasBecomeKeyWindow)
1526  {
1527  if (_firstResponder === self)
1528  {
1529  if (_initialFirstResponder)
1530  [self makeFirstResponder:_initialFirstResponder];
1531  else
1532  {
1533  // Make the first valid key view the first responder
1534  var view = [_contentView nextValidKeyView];
1535 
1536  if (view)
1537  [self makeFirstResponder:view];
1538  }
1539 
1540  return;
1541  }
1542  }
1543 
1544  if (_firstResponder)
1545  [self makeFirstResponder:_firstResponder];
1546 }
1547 
1555 - (BOOL)makeFirstResponder:(CPResponder)aResponder
1556 {
1557  if (_firstResponder === aResponder)
1558  return YES;
1559 
1560  if (![_firstResponder resignFirstResponder])
1561  return NO;
1562 
1563  if (!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
1564  {
1565  _firstResponder = self;
1566 
1567  return NO;
1568  }
1569 
1570  _firstResponder = aResponder;
1571 
1572  [[CPNotificationCenter defaultCenter] postNotificationName:_CPWindowDidChangeFirstResponderNotification object:self];
1573 
1574  return YES;
1575 }
1576 
1580 - (CPResponder)firstResponder
1581 {
1582  return _firstResponder;
1583 }
1584 
1585 - (BOOL)acceptsMouseMovedEvents
1586 {
1587  return _acceptsMouseMovedEvents;
1588 }
1589 
1590 - (void)setAcceptsMouseMovedEvents:(BOOL)shouldAcceptMouseMovedEvents
1591 {
1592  _acceptsMouseMovedEvents = shouldAcceptMouseMovedEvents;
1593 }
1594 
1595 - (BOOL)ignoresMouseEvents
1596 {
1597  return _ignoresMouseEvents;
1598 }
1599 
1600 - (void)setIgnoresMouseEvents:(BOOL)shouldIgnoreMouseEvents
1601 {
1602  _ignoresMouseEvents = shouldIgnoreMouseEvents;
1603 }
1604 
1605 - (void)_mouseExitedResizeRect
1606 {
1607  [[CPCursor arrowCursor] set];
1608 }
1609 
1610 // Managing Titles
1611 
1615 - (CPString)title
1616 {
1617  return _title;
1618 }
1619 
1623 - (void)setTitle:(CPString)aTitle
1624 {
1625  _title = aTitle;
1626 
1627  [_windowView setTitle:aTitle];
1628  [_platformWindow _setTitle:_title window:self];
1629 }
1630 
1634 - (void)setTitleWithRepresentedFilename:(CPString)aFilePath
1635 {
1636  [self setRepresentedFilename:aFilePath];
1637  [self setTitle:[aFilePath lastPathComponent]];
1638 }
1639 
1643 - (void)setRepresentedFilename:(CPString)aFilePath
1644 {
1645  // FIXME: urls vs filepaths and all.
1646  [self setRepresentedURL:[CPURL URLWithString:aFilePath]];
1647 }
1648 
1652 - (CPString)representedFilename
1653 {
1654  return [_representedURL absoluteString];
1655 }
1656 
1660 - (void)setRepresentedURL:(CPURL)aURL
1661 {
1662  _representedURL = aURL;
1663 }
1664 
1668 - (CPURL)representedURL
1669 {
1670  return _representedURL;
1671 }
1672 
1673 - (CPScreen)screen
1674 {
1675  return [[CPScreen alloc] init];
1676 }
1677 
1678 // Moving
1679 
1684 - (void)setMovableByWindowBackground:(BOOL)shouldBeMovableByWindowBackground
1685 {
1686  _isMovableByWindowBackground = shouldBeMovableByWindowBackground;
1687 }
1688 
1692 - (BOOL)isMovableByWindowBackground
1693 {
1694  return _isMovableByWindowBackground;
1695 }
1696 
1701 - (void)setMovable:(BOOL)shouldBeMovable
1702 {
1703  _isMovable = shouldBeMovable;
1704 }
1705 
1709 - (void)isMovable
1710 {
1711  return _isMovable;
1712 }
1713 
1717 - (void)center
1718 {
1719  if (_isFullPlatformWindow)
1720  return;
1721 
1722  var size = [self frame].size,
1723  containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
1724 
1725  var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
1726 
1727  if (origin.x < 0.0)
1728  origin.x = 0.0;
1729 
1730  if (origin.y < 0.0)
1731  origin.y = 0.0;
1732 
1733  [self setFrameOrigin:origin];
1734 }
1735 
1740 - (void)sendEvent:(CPEvent)anEvent
1741 {
1742  var type = [anEvent type],
1743  sheet = [self attachedSheet];
1744 
1745  // If a sheet is attached events get filtered here.
1746  // It is not clear what events should be passed to the view, perhaps all?
1747  // CPLeftMouseDown is needed for window moving and resizing to work.
1748  // CPMouseMoved is needed for rollover effects on title bar buttons.
1749 
1750  if (sheet)
1751  {
1752  switch (type)
1753  {
1754  case CPLeftMouseDown:
1755 
1756  // This is needed when a doubleClick occurs when the sheet is closing or opening
1757  if (!_parentWindow)
1758  return;
1759 
1760  [_windowView mouseDown:anEvent];
1761 
1762  // -dw- if the window is clicked, the sheet should come to front, and become key,
1763  // and the window should be immediately behind
1764  [sheet makeKeyAndOrderFront:self];
1765 
1766  return;
1767 
1768  case CPMouseMoved:
1769  // Allow these through to the parent
1770  break;
1771 
1772  default:
1773  // Everything else is filtered
1774  return;
1775  }
1776  }
1777 
1778  var point = [anEvent locationInWindow];
1779 
1780  switch (type)
1781  {
1782  case CPFlagsChanged:
1783  return [[self firstResponder] flagsChanged:anEvent];
1784 
1785  case CPKeyUp:
1786  return [[self firstResponder] keyUp:anEvent];
1787 
1788  case CPKeyDown:
1789  if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
1790  {
1791  if ([anEvent modifierFlags] & CPShiftKeyMask)
1792  [self selectPreviousKeyView:self];
1793  else
1794  [self selectNextKeyView:self];
1795 #if PLATFORM(DOM)
1796  // Make sure the browser doesn't try to do its own tab handling.
1797  // This is important or the browser might blur the shared text field or token field input field,
1798  // even that we just moved it to a new first responder.
1799  [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
1800 #endif
1801  return;
1802  }
1803  else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
1804  {
1805  var didTabBack = [self selectPreviousKeyView:self];
1806 
1807  if (didTabBack)
1808  {
1809 #if PLATFORM(DOM)
1810  // Make sure the browser doesn't try to do its own tab handling.
1811  // This is important or the browser might blur the shared text field or token field input field,
1812  // even that we just moved it to a new first responder.
1813  [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
1814 #endif
1815 
1816  }
1817  return didTabBack;
1818  }
1819  else if ([anEvent charactersIgnoringModifiers] == CPEscapeFunctionKey && [self _processKeyboardUIKey:anEvent])
1820  {
1821  return;
1822  }
1823 
1824  [[self firstResponder] keyDown:anEvent];
1825 
1826  // Trigger the default button if needed
1827  // FIXME: Is this only applicable in a sheet? See isse: #722.
1828  if (![self disableKeyEquivalentForDefaultButton])
1829  {
1830  var defaultButton = [self defaultButton],
1831  keyEquivalent = [defaultButton keyEquivalent],
1832  modifierMask = [defaultButton keyEquivalentModifierMask];
1833 
1834  if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask])
1835  [[self defaultButton] performClick:self];
1836  }
1837 
1838  return;
1839 
1840  case CPScrollWheel:
1841  return [[_windowView hitTest:point] scrollWheel:anEvent];
1842 
1843  case CPLeftMouseUp:
1844  case CPRightMouseUp:
1845  var hitTestedView = _leftMouseDownView,
1846  selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:);
1847 
1848  if (!hitTestedView)
1849  hitTestedView = [_windowView hitTest:point];
1850 
1851  [hitTestedView performSelector:selector withObject:anEvent];
1852 
1853  _leftMouseDownView = nil;
1854 
1855  return;
1856 
1857  case CPLeftMouseDown:
1858  case CPRightMouseDown:
1859  // This will return _windowView if it is within a resize region
1860  _leftMouseDownView = [_windowView hitTest:point];
1861 
1862  if (_leftMouseDownView !== _firstResponder && [_leftMouseDownView acceptsFirstResponder])
1863  [self makeFirstResponder:_leftMouseDownView];
1864 
1865  var keyWindow = [CPApp keyWindow];
1866 
1867  // This is only when we move from a platform to another one
1868  if ([keyWindow platformWindow] != [self platformWindow])
1869  [self makeKeyAndOrderFront:self];
1870 
1871  [CPApp activateIgnoringOtherApps:YES];
1872 
1873  var theWindow = [anEvent window],
1874  selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:);
1875 
1876  if ([theWindow isKeyWindow] || ([theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey]))
1877  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1878  else
1879  {
1880  // FIXME: delayed ordering?
1881  [self makeKeyAndOrderFront:self];
1882 
1883  if ([_leftMouseDownView acceptsFirstMouse:anEvent])
1884  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1885  }
1886  break;
1887 
1888  case CPLeftMouseDragged:
1889  case CPRightMouseDragged:
1890  if (!_leftMouseDownView)
1891  return [[_windowView hitTest:point] mouseDragged:anEvent];
1892 
1893  var selector;
1894 
1895  if (type == CPRightMouseDragged)
1896  {
1897  selector = @selector(rightMouseDragged:)
1898  if (![_leftMouseDownView respondsToSelector:selector])
1899  selector = nil;
1900  }
1901 
1902  if (!selector)
1903  selector = @selector(mouseDragged:)
1904 
1905  return [_leftMouseDownView performSelector:selector withObject:anEvent];
1906 
1907  case CPMouseMoved:
1908  [_windowView setCursorForLocation:point resizing:NO];
1909 
1910  // Ignore mouse moves for parents of sheets
1911  if (!_acceptsMouseMovedEvents || sheet)
1912  return;
1913 
1914  if (!_mouseEnteredStack)
1915  _mouseEnteredStack = [];
1916 
1917  var hitTestView = [_windowView hitTest:point];
1918 
1919  if ([_mouseEnteredStack count] && [_mouseEnteredStack lastObject] === hitTestView)
1920  return [hitTestView mouseMoved:anEvent];
1921 
1922  var view = hitTestView,
1923  mouseEnteredStack = [];
1924 
1925  while (view)
1926  {
1927  mouseEnteredStack.unshift(view);
1928 
1929  view = [view superview];
1930  }
1931 
1932  var deviation = MIN(_mouseEnteredStack.length, mouseEnteredStack.length);
1933 
1934  while (deviation--)
1935  if (_mouseEnteredStack[deviation] === mouseEnteredStack[deviation])
1936  break;
1937 
1938  var index = deviation + 1,
1939  count = _mouseEnteredStack.length;
1940 
1941  if (index < count)
1942  {
1943  var event = [CPEvent mouseEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
1944 
1945  for (; index < count; ++index)
1946  [_mouseEnteredStack[index] mouseExited:event];
1947  }
1948 
1949  index = deviation + 1;
1950  count = mouseEnteredStack.length;
1951 
1952  if (index < count)
1953  {
1954  var event = [CPEvent mouseEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
1955 
1956  for (; index < count; ++index)
1957  [mouseEnteredStack[index] mouseEntered:event];
1958  }
1959 
1960  _mouseEnteredStack = mouseEnteredStack;
1961 
1962  [hitTestView mouseMoved:anEvent];
1963  }
1964 }
1965 
1969 - (int)windowNumber
1970 {
1971  return _windowNumber;
1972 }
1973 
1979 - (void)becomeKeyWindow
1980 {
1981  CPApp._keyWindow = self;
1982 
1983  if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)])
1984  [_firstResponder becomeKeyWindow];
1985 
1986  if (!_hasBecomeKeyWindow)
1987  {
1988  // The first time a window is loaded, if it does not have a key view loop
1989  // established, calculate it now.
1990  if (![self _hasKeyViewLoop:[_contentView subviews]])
1991  [self recalculateKeyViewLoop];
1992  }
1993 
1994  [self _setupFirstResponder];
1995  _hasBecomeKeyWindow = YES;
1996 
1997  [_windowView noteKeyWindowStateChanged];
1998  [_contentView _notifyWindowDidBecomeKey];
1999 
2001  postNotificationName:CPWindowDidBecomeKeyNotification
2002  object:self];
2003 }
2004 
2009 - (BOOL)canBecomeKeyWindow
2010 {
2011  /*
2012  In Cocoa only titled windows return YES here by default. But the main browser
2013  window in Cappuccino doesn't have a title bar even that it's both titled and
2014  resizable, so we return YES when isFullPlatformWindow too.
2015 
2016  Note that Cocoa will return NO for a non-titled, resizable window. The Cocoa documention
2017  says it will return YES if there is a "resize bar", but in practice
2018  that is not the same as the resizable mask.
2019  */
2020  return (_styleMask & CPTitledWindowMask) || [self isFullPlatformWindow] || _isSheet;
2021 }
2022 
2026 - (BOOL)isKeyWindow
2027 {
2028  return [CPApp keyWindow] == self;
2029 }
2030 
2035 - (void)makeKeyAndOrderFront:(id)aSender
2036 {
2037  [self orderFront:self];
2038 
2039  [self makeKeyWindow];
2040  [self makeMainWindow];
2041 }
2042 
2046 - (void)makeKeyWindow
2047 {
2048  if ([CPApp keyWindow] === self || ![self canBecomeKeyWindow])
2049  return;
2050 
2051  [[CPApp keyWindow] resignKeyWindow];
2052  [self becomeKeyWindow];
2053 }
2054 
2058 - (void)resignKeyWindow
2059 {
2060  if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
2061  [_firstResponder resignKeyWindow];
2062 
2063  if (CPApp._keyWindow === self)
2064  CPApp._keyWindow = nil;
2065 
2066  [_windowView noteKeyWindowStateChanged];
2067  [_contentView _notifyWindowDidResignKey];
2068 
2070  postNotificationName:CPWindowDidResignKeyNotification
2071  object:self];
2072 }
2073 
2084 - (void)dragImage:(CPImage)anImage at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
2085 {
2086  [[CPDragServer sharedDragServer] dragImage:anImage fromWindow:self at:[self convertBaseToGlobal:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
2087 }
2088 
2089 - (void)_noteRegisteredDraggedTypes:(CPSet)pasteboardTypes
2090 {
2091  if (!pasteboardTypes)
2092  return;
2093 
2094  if (!_inclusiveRegisteredDraggedTypes)
2095  _inclusiveRegisteredDraggedTypes = [CPCountedSet set];
2096 
2097  [_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes];
2098 }
2099 
2100 - (void)_noteUnregisteredDraggedTypes:(CPSet)pasteboardTypes
2101 {
2102  if (!pasteboardTypes)
2103  return;
2104 
2105  [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
2106 
2107  if ([_inclusiveRegisteredDraggedTypes count] === 0)
2108  _inclusiveRegisteredDraggedTypes = nil;
2109 }
2110 
2121 - (void)dragView:(CPView)aView at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
2122 {
2123  [[CPDragServer sharedDragServer] dragView:aView fromWindow:self at:[self convertBaseToGlobal:viewLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
2124 }
2125 
2130 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes
2131 {
2132  if (!pasteboardTypes)
2133  return;
2134 
2135  [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
2136  [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
2137  [self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
2138 
2139  _registeredDraggedTypesArray = nil;
2140 }
2141 
2146 - (CPArray)registeredDraggedTypes
2147 {
2148  if (!_registeredDraggedTypesArray)
2149  _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
2150 
2151  return _registeredDraggedTypesArray;
2152 }
2153 
2157 - (void)unregisterDraggedTypes
2158 {
2159  [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
2160 
2161  _registeredDraggedTypes = [CPSet set];
2162  _registeredDraggedTypesArray = [];
2163 }
2164 
2165 // Accessing Editing Status
2166 
2171 - (void)setDocumentEdited:(BOOL)isDocumentEdited
2172 {
2173  if (_isDocumentEdited == isDocumentEdited)
2174  return;
2175 
2176  _isDocumentEdited = isDocumentEdited;
2177 
2178  [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0];
2179 
2180  [_windowView setDocumentEdited:isDocumentEdited];
2181 }
2182 
2186 - (BOOL)isDocumentEdited
2187 {
2188  return _isDocumentEdited;
2189 }
2190 
2191 - (void)setDocumentSaving:(BOOL)isDocumentSaving
2192 {
2193  if (_isDocumentSaving == isDocumentSaving)
2194  return;
2195 
2196  _isDocumentSaving = isDocumentSaving;
2197 
2198  [self _synchronizeSaveMenuWithDocumentSaving];
2199 
2200  [_windowView windowDidChangeDocumentSaving];
2201 }
2202 
2203 - (BOOL)isDocumentSaving
2204 {
2205  return _isDocumentSaving;
2206 }
2207 
2208 /* @ignore */
2209 - (void)_synchronizeSaveMenuWithDocumentSaving
2210 {
2211  if (![self isMainWindow])
2212  return;
2213 
2214  var mainMenu = [CPApp mainMenu],
2215  index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."];
2216 
2217  if (index == CPNotFound)
2218  return;
2219 
2220  var item = [mainMenu itemAtIndex:index];
2221 
2222  if (_isDocumentSaving)
2223  {
2224  CPWindowSaveImage = [item image];
2225 
2226  [item setTitle:@"Saving..."];
2227  [item setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"spinning-regular-gif" forClass:CPProgressIndicator]];
2228  [item setEnabled:NO];
2229  }
2230  else
2231  {
2232  [item setTitle:@"Save"];
2233  [item setImage:CPWindowSaveImage];
2234  [item setEnabled:YES];
2235  }
2236 }
2237 
2238 // Minimizing Windows
2239 
2244 - (void)performMiniaturize:(id)aSender
2245 {
2246  //FIXME show stuff
2247  [self miniaturize:aSender];
2248 }
2249 
2254 - (void)miniaturize:(id)sender
2255 {
2256  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillMiniaturizeNotification object:self];
2257 
2258  [[self platformWindow] miniaturize:sender];
2259 
2260  [self _updateMainAndKeyWindows];
2261 
2262  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self];
2263 
2264  _isMiniaturized = YES;
2265 }
2266 
2270 - (void)deminiaturize:(id)sender
2271 {
2272  [[self platformWindow] deminiaturize:sender];
2273 
2274  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidDeminiaturizeNotification object:self];
2275 
2276  _isMiniaturized = NO;
2277 }
2278 
2282 - (void)isMiniaturized
2283 {
2284  return _isMiniaturized;
2285 }
2286 
2287 // Closing Windows
2288 
2293 - (void)performClose:(id)aSender
2294 {
2295  if (!(_styleMask & CPClosableWindowMask))
2296  return;
2297 
2298  if ([self isFullPlatformWindow])
2299  {
2300  var event = [CPApp currentEvent];
2301 
2302  if ([event type] === CPKeyDown && [event characters] === "w" && ([event modifierFlags] & CPPlatformActionKeyMask))
2303  {
2304  [[self platformWindow] _propagateCurrentDOMEvent:YES];
2305  return;
2306  }
2307  }
2308 
2309  // The Cocoa docs say that if both the delegate and the window implement
2310  // windowShouldClose:, only the delegate receives the message.
2311  if ([self _delegateRespondsToWindowShouldClose])
2312  {
2313  if (![self _sendDelegateWindowShouldClose])
2314  return;
2315  }
2316  else if ([self respondsToSelector:@selector(windowShouldClose:)])
2317  {
2318  if (![self windowShouldClose:self])
2319  return;
2320  }
2321 
2322  var documents = [_windowController documents];
2323 
2324  if ([documents count])
2325  {
2326  var index = [documents indexOfObject:[_windowController document]];
2327 
2328  [documents[index] shouldCloseWindowController:_windowController
2329  delegate:self
2330  shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
2331  contextInfo:{documents:[documents copy], visited:0, index:index}];
2332  }
2333  else
2334  [self close];
2335 }
2336 
2337 - (void)_windowControllerContainingDocument:(CPDocument)document shouldClose:(BOOL)shouldClose contextInfo:(Object)context
2338 {
2339  if (shouldClose)
2340  {
2341  var windowController = [self windowController],
2342  documents = context.documents,
2343  count = [documents count],
2344  visited = ++context.visited,
2345  index = ++context.index % count;
2346 
2347  [document removeWindowController:windowController];
2348 
2349  if (visited < count)
2350  {
2351  [windowController setDocument:documents[index]];
2352 
2353  [documents[index] shouldCloseWindowController:_windowController
2354  delegate:self
2355  shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
2356  contextInfo:context];
2357  }
2358  else
2359  [self close];
2360  }
2361 }
2362 
2367 - (void)close
2368 {
2369  [self _sendDelegateWindowWillClose];
2370 
2371  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillCloseNotification object:self];
2372 
2373  [_parentWindow removeChildWindow:self];
2374  [self _orderOutRecursively:NO];
2375  [self _detachFromChildrenClosing:!_parentWindow];
2376 }
2377 
2378 - (void)_detachFromChildrenClosing:(BOOL)shouldCloseChildren
2379 {
2380  // When a window is closed, it must detach itself from all children
2381  [_childWindows enumerateObjectsUsingBlock:function(child)
2382  {
2383  [child setParentWindow:nil];
2384  }
2385  ];
2386 
2387  if (shouldCloseChildren)
2388  {
2389  // Cocoa does NOT call close or orderOut when closing child windows,// they are summarily closed.[_childWindows enumerateObjectsUsingBlock:function(child)
2390  {
2391 
2392 
2393  [child _orderOutRecursively:NO];
2394  [child _detachFromChildrenClosing:![child parentWindow]];
2395  }
2396  ];
2397  }
2398 
2399  _childWindows = [];
2400 }
2401 
2402 // Managing Main Status
2406 - (BOOL)isMainWindow
2407 {
2408  return [CPApp mainWindow] === self;
2409 }
2410 
2414 - (BOOL)canBecomeMainWindow
2415 {
2416  // Note that the Cocoa documentation says that this method returns YES if
2417  // the window is visible and has a title bar or a "resize mechanism". It turns
2418  // out a "resize mechanism" is not the same as having the resize mask set.
2419  // In practice a window must have a title bar to become main, but we make
2420  // an exception for a full platform window.
2421  return ([self isVisible] && ((_styleMask & CPTitledWindowMask) || _isFullPlatformWindow));
2422 }
2423 
2427 - (void)makeMainWindow
2428 {
2429  // Sheets cannot be main. Their parent window becomes main.
2430  if (_isSheet)
2431  {
2432  [_parentView makeMainWindow];
2433  return;
2434  }
2435 
2436  if ([CPApp mainWindow] === self || ![self canBecomeMainWindow])
2437  return;
2438 
2439  [[CPApp mainWindow] resignMainWindow];
2440  [self becomeMainWindow];
2441 }
2442 
2446 - (void)becomeMainWindow
2447 {
2448  CPApp._mainWindow = self;
2449 
2450  [self _synchronizeSaveMenuWithDocumentSaving];
2451 
2452  [_windowView noteMainWindowStateChanged];
2453 
2455  postNotificationName:CPWindowDidBecomeMainNotification
2456  object:self];
2457 }
2458 
2462 - (void)resignMainWindow
2463 {
2465  postNotificationName:CPWindowDidResignMainNotification
2466  object:self];
2467 
2468  if (CPApp._mainWindow === self)
2469  CPApp._mainWindow = nil;
2470 
2471  [_windowView noteMainWindowStateChanged];
2472 }
2473 
2474 - (void)_updateMainAndKeyWindows
2475 {
2476  var allWindows = [CPApp orderedWindows],
2477  windowCount = [allWindows count];
2478 
2479  if ([self isKeyWindow])
2480  {
2481  var keyWindow = [CPApp keyWindow];
2482  [self resignKeyWindow];
2483 
2484  if (keyWindow && keyWindow !== self && [keyWindow canBecomeKeyWindow])
2485  [keyWindow makeKeyWindow];
2486  else
2487  {
2488  var mainMenu = [CPApp mainMenu],
2489  menuBarClass = objj_getClass("_CPMenuBarWindow"),
2490  menuWindow;
2491 
2492  for (var i = 0; i < windowCount; i++)
2493  {
2494  var currentWindow = allWindows[i];
2495 
2496  if ([currentWindow isKindOfClass:menuBarClass])
2497  menuWindow = currentWindow;
2498 
2499  if (currentWindow === self || currentWindow === menuWindow)
2500  continue;
2501 
2502  if ([currentWindow isVisible] && [currentWindow canBecomeKeyWindow] && [currentWindow platformWindow] == [keyWindow platformWindow])
2503  {
2504  [currentWindow makeKeyWindow];
2505  break;
2506  }
2507  }
2508 
2509  if (![CPApp keyWindow])
2510  [menuWindow makeKeyWindow];
2511  }
2512  }
2513 
2514  if ([self isMainWindow])
2515  {
2516  var mainWindow = [CPApp mainWindow];
2517  [self resignMainWindow];
2518 
2519  if (mainWindow && mainWindow !== self && [mainWindow canBecomeMainWindow])
2520  [mainWindow makeMainWindow];
2521  else
2522  {
2523  var mainMenu = [CPApp mainMenu],
2524  menuBarClass = objj_getClass("_CPMenuBarWindow"),
2525  menuWindow;
2526 
2527  for (var i = 0; i < windowCount; i++)
2528  {
2529  var currentWindow = allWindows[i];
2530 
2531  if ([currentWindow isKindOfClass:menuBarClass])
2532  menuWindow = currentWindow;
2533 
2534  if (currentWindow === self || currentWindow === menuWindow)
2535  continue;
2536 
2537  if ([currentWindow isVisible] && [currentWindow canBecomeMainWindow])
2538  {
2539  [currentWindow makeMainWindow];
2540  break;
2541  }
2542  }
2543  }
2544  }
2545 }
2546 
2547 // Managing Toolbars
2551 - (CPToolbar)toolbar
2552 {
2553  return _toolbar;
2554 }
2555 
2560 - (void)setToolbar:(CPToolbar)aToolbar
2561 {
2562  if (_toolbar === aToolbar)
2563  return;
2564 
2565  // If this has an owner, dump it!
2566  [[aToolbar _window] setToolbar:nil];
2567 
2568  // This is no longer our toolbar.
2569  [_toolbar _setWindow:nil];
2570 
2571  _toolbar = aToolbar;
2572 
2573  // THIS is our toolbar.
2574  [_toolbar _setWindow:self];
2575 
2576  [self _noteToolbarChanged];
2577 }
2578 
2579 - (void)toggleToolbarShown:(id)aSender
2580 {
2581  var toolbar = [self toolbar];
2582 
2583  [toolbar setVisible:![toolbar isVisible]];
2584 }
2585 
2586 - (void)_noteToolbarChanged
2587 {
2588  var frame = CGRectMakeCopy([self frame]),
2589  newFrame;
2590 
2591  [_windowView noteToolbarChanged];
2592 
2593  if (_isFullPlatformWindow)
2594  newFrame = [_platformWindow visibleFrame];
2595  else
2596  {
2597  newFrame = CGRectMakeCopy([self frame]);
2598 
2599  newFrame.origin = frame.origin;
2600  }
2601 
2602  [self setFrame:newFrame];
2603  /*
2604  [_windowView setAnimatingToolbar:YES];
2605  [self setFrame:frame];
2606  [self setFrame:newFrame display:YES animate:YES];
2607  [_windowView setAnimatingToolbar:NO];
2608  */
2609 }
2610 
2614 - (CPArray)childWindows
2615 {
2616  return _childWindows;
2617 }
2618 
2619 - (void)addChildWindow:(CPWindow)childWindow ordered:(CPWindowOrderingMode)orderingMode
2620 {
2621  // Don't add the child if it is already in our list
2622  if ([_childWindows indexOfObject:childWindow] >= 0)
2623  return;
2624 
2625  if (orderingMode === CPWindowAbove || orderingMode === CPWindowBelow)
2626  [_childWindows addObject:childWindow];
2627  else
2628  [CPException raise:CPInvalidArgumentException
2629  reason:_cmd + @" unrecognized ordering mode " + orderingMode];
2630 
2631  [childWindow setParentWindow:self];
2632  [childWindow _setChildOrdering:orderingMode];
2633  [childWindow setLevel:[self level]];
2634 
2635  if ([self isVisible] && ![childWindow isVisible])
2636  [childWindow orderWindow:orderingMode relativeTo:_windowNumber];
2637 }
2638 
2639 - (void)removeChildWindow:(CPWindow)childWindow
2640 {
2641  var index = [_childWindows indexOfObject:childWindow];
2642 
2643  if (index === CPNotFound)
2644  return;
2645 
2646  [_childWindows removeObjectAtIndex:index];
2647  [childWindow setParentWindow:nil];
2648 }
2649 
2650 - (CPWindow)parentWindow
2651 {
2652  return _parentWindow;
2653 }
2654 
2660 - (BOOL)_hasAncestorWindow:(CPWindow)anAncestor
2661 {
2662  if (!_parentWindow || !anAncestor)
2663  return NO;
2664 
2665  if (anAncestor === _parentWindow)
2666  return YES;
2667 
2668  return [_parentWindow _hasAncestorWindow:anAncestor];
2669 }
2670 
2671 - (CPWindow)setParentWindow:(CPWindow)parentWindow
2672 {
2673  _parentWindow = parentWindow;
2674 }
2675 
2676 - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
2677 {
2678  [_frameAnimation stopAnimation];
2679  _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
2680  [_frameAnimation setDelegate:delegate];
2681  [_frameAnimation setAnimationCurve:curve];
2682  [_frameAnimation setDuration:duration];
2683  [_frameAnimation startAnimation];
2684 }
2685 
2686 - (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
2687 {
2688  return CPWindowResizeTime;
2689 }
2690 
2691 - (void)_setAttachedSheetFrameOrigin
2692 {
2693  // Position the sheet above the contentRect.
2694  var attachedSheet = [self attachedSheet],
2695  contentRect = [_contentView frame],
2696  sheetFrame = CGRectMakeCopy([attachedSheet frame]);
2697 
2698  sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
2699  sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
2700 
2701  [attachedSheet setFrame:sheetFrame display:YES animate:NO];
2702 }
2703 
2704 - (void)_previousSheetIsClosedNotification:(CPNotification)aNotification
2705 {
2706  [[CPNotificationCenter defaultCenter] removeObserver:self name:CPWindowDidEndSheetNotification object:self];
2707 
2708  var sheet = _sheetContext[@"nextSheet"],
2709  modalDelegate =_sheetContext[@"nextModalDelegate"],
2710  endSelector = _sheetContext[@"nextEndSelector"],
2711  contextInfo = _sheetContext[@"nextContextInfo"];
2712 
2713  // Needed, because when the notification CPWindowDidEndSheetNotification is sent, the sheetContext is not up to date...
2714  setTimeout(function()
2715  {
2716  [sheet._windowView _enableSheet:YES inWindow:self];
2717  [self _attachSheet:sheet modalDelegate:modalDelegate didEndSelector:endSelector contextInfo:contextInfo];
2718  }, 0)
2719 }
2720 
2721 /*
2722  Starting point for sheet session, called from CPApplication beginSheet:
2723 */
2724 - (void)_attachSheet:(CPWindow)aSheet modalDelegate:(id)aModalDelegate
2725  didEndSelector:(SEL)didEndSelector contextInfo:(id)contextInfo
2726 {
2727  if (_sheetContext)
2728  {
2729  // Here we wait till the current sheet is closed
2730  if (_sheetContext[@"isClosing"])
2731  {
2732  // Here we save the next sheet to open
2733  _sheetContext[@"nextSheet"] = aSheet;
2734  _sheetContext[@"nextModalDelegate"] = aModalDelegate;
2735  _sheetContext[@"nextEndSelector"] = didEndSelector;
2736  _sheetContext[@"nextContextInfo"] = contextInfo;
2737 
2738  [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_previousSheetIsClosedNotification:) name:CPWindowDidEndSheetNotification object:self];
2739  return;
2740  }
2741  else
2742  {
2743  [CPException raise:CPInternalInconsistencyException
2744  reason:@"The target window of beginSheet: already has a sheet, did you forget orderOut: ?"];
2745  return;
2746  }
2747  }
2748 
2749  _sheetContext = {
2750  "sheet": aSheet,
2751  "modalDelegate": aModalDelegate,
2752  "endSelector": didEndSelector,
2753  "contextInfo": contextInfo,
2754  "returnCode": -1,
2755  "opened": NO,
2756  "isAttached": YES,
2757  "savedConstrains": aSheet._constrainsToUsableScreen
2758  };
2759 
2760  // Sheets are not constrained, they are controlled by their parent
2761  aSheet._constrainsToUsableScreen = NO;
2762 
2763  // A timer seems to be necessary for the animation to work correctly
2765  target:self
2766  selector:@selector(_sheetShouldAnimateIn:)
2767  userInfo:nil
2768  repeats:NO];
2769 }
2770 
2771 /*
2772  Called to end the sheet. Note that orderOut: is needed to animate the sheet out, as in Cocoa.
2773  The sheet isn't completely gone until _cleanupSheetWindow gets called.
2774 */
2775 - (void)_endSheet
2776 {
2777  var delegate = _sheetContext["modalDelegate"],
2778  endSelector = _sheetContext["endSelector"];
2779 
2780  // If the sheet has been ordered out, defer didEndSelector until after sheet animates out.
2781  // This must be done since we cannot block and wait for the animation to complete.
2782  if (delegate && endSelector)
2783  {
2784  if (_sheetContext["isAttached"])
2785  objj_msgSend(delegate, endSelector, _sheetContext["sheet"], _sheetContext["returnCode"],
2786  _sheetContext["contextInfo"]);
2787  else
2788  _sheetContext["deferDidEndSelector"] = YES;
2789  }
2790 }
2791 
2792 /*
2793  Called to animate the sheet out. If called while animating in, schedules an animate
2794  out at completion
2795 */
2796 - (void)_detachSheetWindow
2797 {
2798  if (_sheetContext["isClosing"])
2799  return;
2800 
2801  _sheetContext["isAttached"] = NO;
2802  _sheetContext["isClosing"] = YES;
2803  _sheetContext["opened"] = NO;
2804 
2805  // A timer seems to be necessary for the animation to work correctly.
2806  // It would be ideal to block here and spin the event loop, until attach is complete.
2808  target:self
2809  selector:@selector(_sheetShouldAnimateOut:)
2810  userInfo:nil
2811  repeats:NO];
2812 }
2813 
2814 /*
2815  Called to cleanup sheet, when we are definitely done with it
2816 */
2817 - (void)_cleanupSheetWindow
2818 {
2819  var sheet = _sheetContext["sheet"],
2820  deferDidEnd = _sheetContext["deferDidEndSelector"];
2821 
2822  // If the parent window is modal, the sheet started its own modal session
2823  if (sheet._isModal)
2824  [CPApp stopModal];
2825 
2826  [self _removeClipForSheet:sheet];
2827 
2828  // Restore the state of window before it was sheetified
2829  sheet._isSheet = NO;
2830  [sheet._windowView _enableSheet:NO inWindow:self];
2831  sheet._constrainsToUsableScreen = _sheetContext["savedConstrains"];
2832 
2833  // Close it
2834  [sheet orderOut:self];
2835 
2836  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self];
2837 
2838  if (deferDidEnd)
2839  {
2840  var delegate = _sheetContext["modalDelegate"],
2841  selector = _sheetContext["endSelector"],
2842  returnCode = _sheetContext["returnCode"],
2843  contextInfo = _sheetContext["contextInfo"];
2844 
2845  // Context must be destroyed, since didEnd might want to attach another sheet
2846  _sheetContext = nil;
2847  sheet._parentView = nil;
2848 
2849  objj_msgSend(delegate, selector, sheet, returnCode, contextInfo);
2850  }
2851  else
2852  {
2853  _sheetContext = nil;
2854  sheet._parentView = nil;
2855  }
2856 }
2857 
2858 /* @ignore */
2859 - (void)animationDidEnd:(id)anim
2860 {
2861  var sheet = _sheetContext["sheet"];
2862 
2863  if (anim._window != sheet)
2864  return;
2865 
2867  target:self
2868  selector:@selector(_sheetAnimationDidEnd:)
2869  userInfo:nil
2870  repeats:NO];
2871 }
2872 
2873 - (void)_sheetShouldAnimateIn:(CPTimer)timer
2874 {
2875  // Can't open sheet while opening or closing animation is going on
2876  if (_sheetContext["isOpening"] || _sheetContext["isClosing"])
2877  return;
2878 
2879  var sheet = _sheetContext["sheet"];
2880  sheet._isSheet = YES;
2881  sheet._parentView = self;
2882 
2883  [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self];
2884 
2885  // If sheet is attached to a modal window, the sheet runs
2886  // as if itself and the parent window are modal
2887  sheet._isModal = NO;
2888 
2889  if ([CPApp modalWindow] === self)
2890  {
2891  [CPApp runModalForWindow:sheet];
2892  sheet._isModal = YES;
2893  }
2894 
2895  // The sheet starts hidden just above the top of a clip rect
2896  // TODO : Make properly for the -1 in endY
2897  var sheetFrame = [sheet frame],
2898  sheetShadowFrame = sheet._hasShadow ? [sheet._shadowView frame] : sheetFrame,
2899  frame = [self frame],
2900  originX = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2),
2901  startFrame = CGRectMake(originX, -sheetShadowFrame.size.height, sheetFrame.size.width, sheetFrame.size.height),
2902  endY = -1 + [_windowView bodyOffset] - [[self contentView] frame].origin.y,
2903  endFrame = CGRectMake(originX, endY, sheetFrame.size.width, sheetFrame.size.height);
2904 
2905  if (_toolbar && [_windowView showsToolbar] && [self isFullPlatformWindow])
2906  {
2907  endY += [[_toolbar _toolbarView] frameSize].height;
2908  endFrame = CGRectMake(originX, endY, sheetFrame.size.width, sheetFrame.size.height);
2909  }
2910 
2911  // Move the sheet offscreen before ordering front so it doesn't appear briefly
2912  [sheet setFrameOrigin:CGPointMake(0, -13000)];
2913 
2914  // Because clipping does funny thing with the DOM, we have to orderFront before clipping
2915  [sheet orderFront:self];
2916  [self _clipSheet:sheet];
2917 
2918  [sheet setFrame:startFrame display:YES animate:NO];
2919 
2920  _sheetContext["opened"] = YES;
2921  _sheetContext["shouldClose"] = NO;
2922  _sheetContext["isOpening"] = YES;
2923 
2924  [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
2925 }
2926 
2927 - (void)_sheetShouldAnimateOut:(CPTimer)timer
2928 {
2929  if (_sheetContext["isOpening"])
2930  {
2931  // Allow sheet to be closed while opening, it will close when animate in completes
2932  _sheetContext["shouldClose"] = YES;
2933  return;
2934  }
2935 
2936  // The parent window can be orderedOut to disable the sheet animate out, as in Cocoa
2937  if ([self isVisible])
2938  {
2939  var sheet = _sheetContext["sheet"],
2940  sheetFrame = [sheet frame],
2941  fullHeight = sheet._hasShadow ? [sheet._shadowView frame].size.height : sheetFrame.size.height,
2942  endFrame = CGRectMakeCopy(sheetFrame),
2943  contentOrigin = [self convertBaseToGlobal:[[self contentView] frame].origin];
2944 
2945  // Don't constrain sheets, they are controlled by the parent
2946  sheet._constrainsToUsableScreen = NO;
2947 
2948  [sheet setFrameOrigin:CGPointMake(sheetFrame.origin.x, sheetFrame.origin.y - contentOrigin.y)];
2949  [self _clipSheet:sheet];
2950 
2951  endFrame.origin.y = -fullHeight;
2952  [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
2953  }
2954  else
2955  {
2956  [self _sheetAnimationDidEnd:nil];
2957  }
2958 }
2959 
2960 - (void)_sheetAnimationDidEnd:(CPTimer)timer
2961 {
2962  var sheet = _sheetContext["sheet"];
2963 
2964  _sheetContext["isOpening"] = NO;
2965  _sheetContext["isClosing"] = NO;
2966 
2967  if (_sheetContext["opened"] === YES)
2968  {
2969  var sheetFrame = [sheet frame],
2970  sheetOrigin = CGPointMakeCopy(sheetFrame.origin);
2971 
2972  [self _removeClipForSheet:sheet];
2973  [sheet setFrameOrigin:CGPointMake(sheetOrigin.x, [sheet frame].origin.y + sheetOrigin.y)];
2974 
2975  // we wanted to close the sheet while it animated in, do that now
2976  if (_sheetContext["shouldClose"] === YES)
2977  [self _detachSheetWindow];
2978  else
2979  [sheet makeKeyWindow];
2980  }
2981  else
2982  {
2983  // sheet is closed and not visible
2984  [self _cleanupSheetWindow];
2985  }
2986 }
2987 
2988 - (void)_clipSheet:(CPWindow)aSheet
2989 {
2990  var clipRect = [_platformWindow contentBounds];
2991  clipRect.origin.y = [self frame].origin.y + [[self contentView] frame].origin.y;
2992 
2993  [[_platformWindow layerAtLevel:_level create:NO] clipWindow:aSheet toRect:clipRect];
2994 }
2995 
2996 - (void)_removeClipForSheet:(CPWindow)aSheet
2997 {
2998  [[_platformWindow layerAtLevel:_level create:NO] removeClipForWindow:aSheet];
2999 }
3000 
3004 - (CPWindow)attachedSheet
3005 {
3006  if (_sheetContext === nil)
3007  return nil;
3008 
3009  return _sheetContext["sheet"];
3010 }
3011 
3015 - (BOOL)isSheet
3016 {
3017  return _isSheet;
3018 }
3019 
3020 //
3021 /*
3022  Used privately.
3023  @ignore
3024 */
3025 - (BOOL)becomesKeyOnlyIfNeeded
3026 {
3027  return NO;
3028 }
3029 
3034 - (BOOL)worksWhenModal
3035 {
3036  return NO;
3037 }
3038 
3039 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
3040 {
3041  // FIXME: should we be starting at the root, in other words _windowView?
3042  // The evidence seems to point to no...
3043  return [_contentView performKeyEquivalent:anEvent];
3044 }
3045 
3046 - (void)keyDown:(CPEvent)anEvent
3047 {
3048  // It's not clear why we do performKeyEquivalent again here...
3049  // Perhaps to allow something to happen between sendEvent: and keyDown:?
3050  if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
3051  return;
3052 
3053  // Apple's documentation is inconsistent with their behavior here. According to the docs
3054  // an event going of the responder chain is passed to the input system as a last resort.
3055  // However, the only methods I could get Cocoa to call automatically are
3056  // moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
3057  // Unhandled events just travel further up the responder chain _past_ the window.
3058  if (![self _processKeyboardUIKey:anEvent])
3059  [super keyDown:anEvent];
3060 }
3061 
3062 /*
3063  @ignore
3064  Interprets the key event for action messages and sends the action message down the responder chain
3065  Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
3066  We deviate from this by sending (the default) scrollPageUp:, scrollPageDown:, scrollToBeginningOfDocument: and scrollToEndOfDocument: for pageUp, pageDown, home and end keys.
3067  @param anEvent the event to handle.
3068  @return YES if the key event was handled, NO if no responder handled the key event
3069 */
3070 - (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
3071 {
3072  var character = [anEvent charactersIgnoringModifiers];
3073 
3074  if (![CPWindowActionMessageKeys containsObject:character])
3075  return NO;
3076 
3077  var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
3078 
3079  if ([selectors count] <= 0)
3080  return NO;
3081 
3082  var selector = [selectors objectAtIndex:0];
3083 
3084  return [[self firstResponder] tryToPerform:selector with:self];
3085 }
3086 
3087 - (void)_dirtyKeyViewLoop
3088 {
3089  if (_autorecalculatesKeyViewLoop)
3090  _keyViewLoopIsDirty = YES;
3091 }
3092 
3093 /*
3094  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.
3095 
3096  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.
3097 */
3098 - (BOOL)_hasKeyViewLoop:(CPArray)theViews
3099 {
3100  var i,
3101  count = [theViews count];
3102 
3103  for (i = 0; i < count; ++i)
3104  {
3105  var view = theViews[i];
3106 
3107  if ([view nextKeyView] || [view previousKeyView])
3108  return YES;
3109  }
3110 
3111  for (i = 0; i < count; ++i)
3112  {
3113  var subviews = [theViews[i] subviews];
3114 
3115  if ([subviews count] && [self _hasKeyViewLoop:subviews])
3116  return YES;
3117  }
3118 
3119  return NO;
3120 }
3121 
3129 - (void)recalculateKeyViewLoop
3130 {
3131  [self _doRecalculateKeyViewLoop];
3132 }
3133 
3134 - (CPArray)_viewsSortedByPosition
3135 {
3136  var views = [CPArray arrayWithObject:_contentView];
3137 
3138  views = views.concat([self _subviewsSortedByPosition:[_contentView subviews]]);
3139 
3140  return views;
3141 }
3142 
3143 - (CPArray)_subviewsSortedByPosition:(CPArray)theSubviews
3144 {
3145  /*
3146  We first sort the subviews according to geometric order.
3147  Then we go through each subview, and if it has subviews,
3148  they are sorted and inserted after the superview. This
3149  is done recursively.
3150  */
3151  theSubviews = [theSubviews copy];
3152  [theSubviews sortUsingFunction:keyViewComparator context:nil];
3153 
3154  var sortedViews = [];
3155 
3156  for (var i = 0, count = [theSubviews count]; i < count; ++i)
3157  {
3158  var view = theSubviews[i],
3159  subviews = [view subviews];
3160 
3161  sortedViews.push(view);
3162 
3163  if ([subviews count])
3164  sortedViews = sortedViews.concat([self _subviewsSortedByPosition:subviews]);
3165  }
3166 
3167  return sortedViews;
3168 }
3169 
3170 - (void)_doRecalculateKeyViewLoop
3171 {
3172  var views = [self _viewsSortedByPosition];
3173 
3174  for (var index = 0, count = [views count]; index < count; ++index)
3175  [views[index] setNextKeyView:views[(index + 1) % count]];
3176 
3177  _keyViewLoopIsDirty = NO;
3178 }
3179 
3180 - (void)setAutorecalculatesKeyViewLoop:(BOOL)shouldRecalculate
3181 {
3182  if (_autorecalculatesKeyViewLoop === shouldRecalculate)
3183  return;
3184 
3185  _autorecalculatesKeyViewLoop = shouldRecalculate;
3186 }
3187 
3188 - (BOOL)autorecalculatesKeyViewLoop
3189 {
3190  return _autorecalculatesKeyViewLoop;
3191 }
3192 
3193 - (void)selectNextKeyView:(id)sender
3194 {
3195  if (_keyViewLoopIsDirty)
3196  [self _doRecalculateKeyViewLoop];
3197 
3198  var nextValidKeyView = nil;
3199 
3200  if ([_firstResponder isKindOfClass:[CPView class]])
3201  nextValidKeyView = [_firstResponder nextValidKeyView];
3202 
3203  if (!nextValidKeyView)
3204  {
3205  if ([_initialFirstResponder acceptsFirstResponder])
3206  nextValidKeyView = _initialFirstResponder;
3207  else
3208  nextValidKeyView = [_initialFirstResponder nextValidKeyView];
3209  }
3210 
3211  if (nextValidKeyView)
3212  [self makeFirstResponder:nextValidKeyView];
3213 }
3214 
3215 - (void)selectPreviousKeyView:(id)sender
3216 {
3217  if (_keyViewLoopIsDirty)
3218  [self _doRecalculateKeyViewLoop];
3219 
3220  var previousValidKeyView = nil;
3221 
3222  if ([_firstResponder isKindOfClass:[CPView class]])
3223  previousValidKeyView = [_firstResponder previousValidKeyView];
3224 
3225  if (!previousValidKeyView)
3226  {
3227  if ([_initialFirstResponder acceptsFirstResponder])
3228  previousValidKeyView = _initialFirstResponder;
3229  else
3230  previousValidKeyView = [_initialFirstResponder previousValidKeyView];
3231  }
3232 
3233  if (previousValidKeyView)
3234  [self makeFirstResponder:previousValidKeyView];
3235 }
3236 
3237 - (void)selectKeyViewFollowingView:(CPView)aView
3238 {
3239  if (_keyViewLoopIsDirty)
3240  [self _doRecalculateKeyViewLoop];
3241 
3242  var nextValidKeyView = [aView nextValidKeyView];
3243 
3244  if ([nextValidKeyView isKindOfClass:[CPView class]])
3245  [self makeFirstResponder:nextValidKeyView];
3246 }
3247 
3248 - (void)selectKeyViewPrecedingView:(CPView)aView
3249 {
3250  if (_keyViewLoopIsDirty)
3251  [self _doRecalculateKeyViewLoop];
3252 
3253  var previousValidKeyView = [aView previousValidKeyView];
3254 
3255  if ([previousValidKeyView isKindOfClass:[CPView class]])
3256  [self makeFirstResponder:previousValidKeyView];
3257 }
3258 
3264 - (void)setDefaultButtonCell:(CPButton)aButton
3265 {
3266  [self setDefaultButton:aButton];
3267 }
3268 
3273 - (CPButton)defaultButtonCell
3274 {
3275  return [self defaultButton];
3276 }
3277 
3284 - (void)setDefaultButton:(CPButton)aButton
3285 {
3286  if (_defaultButton === aButton)
3287  return;
3288 
3289  if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
3290  [_defaultButton setKeyEquivalent:nil];
3291 
3292  _defaultButton = aButton;
3293 
3294  if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
3295  [_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
3296 }
3297 
3301 - (CPButton)defaultButton
3302 {
3303  return _defaultButton;
3304 }
3305 
3309 - (void)enableKeyEquivalentForDefaultButton
3310 {
3311  _defaultButtonEnabled = YES;
3312 }
3313 
3318 - (void)enableKeyEquivalentForDefaultButtonCell
3319 {
3321 }
3322 
3326 - (void)disableKeyEquivalentForDefaultButton
3327 {
3328  _defaultButtonEnabled = NO;
3329 }
3330 
3335 - (void)disableKeyEquivalentForDefaultButtonCell
3336 {
3338 }
3339 
3340 - (void)setValue:(id)aValue forKey:(CPString)aKey
3341 {
3342  if (aKey === CPDisplayPatternTitleBinding)
3343  [self setTitle:aValue || @""];
3344  else
3345  [super setValue:aValue forKey:aKey];
3346 }
3347 
3348 - (void)_didReceivePlatformWindowWillCloseNotification:(CPNotification)aNotification
3349 {
3350  if ([aNotification object] != _platformWindow)
3351  return;
3352 
3353  [self close];
3354 }
3355 
3356 @end
3357 
3358 var keyViewComparator = function(lhs, rhs, context)
3359 {
3360  var lhsBounds = [lhs convertRect:[lhs bounds] toView:nil],
3361  rhsBounds = [rhs convertRect:[rhs bounds] toView:nil],
3362  lhsY = CGRectGetMinY(lhsBounds),
3363  rhsY = CGRectGetMinY(rhsBounds),
3364  lhsX = CGRectGetMinX(lhsBounds),
3365  rhsX = CGRectGetMinX(rhsBounds),
3366  intersectsVertically = MIN(CGRectGetMaxY(lhsBounds), CGRectGetMaxY(rhsBounds)) - MAX(lhsY, rhsY);
3367 
3368  // If two views are "on the same line" (intersect vertically), then rely on the x comparison.
3369  if (intersectsVertically > 0)
3370  {
3371  if (lhsX < rhsX)
3372  return CPOrderedAscending;
3373 
3374  if (lhsX === rhsX)
3375  return CPOrderedSame;
3376 
3377  return CPOrderedDescending;
3378  }
3379 
3380  if (lhsY < rhsY)
3381  return CPOrderedAscending;
3382 
3383  if (lhsY === rhsY)
3384  return CPOrderedSame;
3385 
3386  return CPOrderedDescending;
3387 };
3388 
3389 
3391 
3396 - (BOOL)_delegateRespondsToWindowWillUndoManager
3397 {
3398  return _implementedDelegateMethods & CPWindowDelegate_windowWillReturnUndoManager_;
3399 }
3400 
3405 - (BOOL)_delegateRespondsToWindowShouldClose
3406 {
3407  return _implementedDelegateMethods & CPWindowDelegate_windowShouldClose_
3408 }
3409 
3414 - (BOOL)_sendDelegateWindowShouldClose
3415 {
3416  if (!(_implementedDelegateMethods & CPWindowDelegate_windowShouldClose_))
3417  return YES;
3418 
3419  return [_delegate windowShouldClose:self];
3420 }
3421 
3426 - (BOOL)_sendDelegateWindowWillReturnUndoManager
3427 {
3428  if (!(_implementedDelegateMethods & CPWindowDelegate_windowWillReturnUndoManager_))
3429  return nil;
3430 
3431  return [_delegate windowWillReturnUndoManager:self];
3432 }
3433 
3438 - (void)_sendDelegateWindowWillClose
3439 {
3440  if (!(_implementedDelegateMethods & CPWindowDelegate_windowWillClose_))
3441  return;
3442 
3443  [_delegate windowWillClose:self];
3444 }
3445 
3446 @end
3447 
3448 
3450 
3451 /*
3452  @ignore
3453 */
3454 - (void)resizeWithOldPlatformWindowSize:(CGSize)aSize
3455 {
3456  if ([self isFullPlatformWindow])
3457  return [self setFrame:[_platformWindow visibleFrame]];
3458 
3459  // If this window is constrainable and we are globally ignoring constraining, ignore the platform resize
3460  if ((_constrainsToUsableScreen && !CPWindowConstrainToScreen) || _autoresizingMask === CPWindowNotSizable)
3461  return;
3462 
3463  var frame = [_platformWindow contentBounds],
3464  newFrame = CGRectMakeCopy(_frame),
3465  dX = (CGRectGetWidth(frame) - aSize.width) /
3466  (((_autoresizingMask & CPWindowMinXMargin) ? 1 : 0) + (_autoresizingMask & CPWindowWidthSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxXMargin ? 1 : 0)),
3467  dY = (CGRectGetHeight(frame) - aSize.height) /
3468  ((_autoresizingMask & CPWindowMinYMargin ? 1 : 0) + (_autoresizingMask & CPWindowHeightSizable ? 1 : 0) + (_autoresizingMask & CPWindowMaxYMargin ? 1 : 0));
3469 
3470  if (_autoresizingMask & CPWindowMinXMargin)
3471  newFrame.origin.x += dX;
3472 
3473  if (_autoresizingMask & CPWindowWidthSizable)
3474  newFrame.size.width += dX;
3475 
3476  if (_autoresizingMask & CPWindowMinYMargin)
3477  newFrame.origin.y += dY;
3478 
3479  if (_autoresizingMask & CPWindowHeightSizable)
3480  newFrame.size.height += dY;
3481 
3482  [self _setFrame:newFrame display:YES animate:NO constrainWidth:YES constrainHeight:YES];
3483 }
3484 
3485 /*
3486  @ignore
3487 */
3488 - (void)setAutoresizingMask:(unsigned)anAutoresizingMask
3489 {
3490  _autoresizingMask = anAutoresizingMask;
3491 }
3492 
3493 /*
3494  @ignore
3495 */
3496 - (unsigned)autoresizingMask
3497 {
3498  return _autoresizingMask;
3499 }
3500 
3504 - (CGPoint)convertBaseToGlobal:(CGPoint)aPoint
3505 {
3506  return [CPPlatform isBrowser] ? [self convertBaseToPlatformWindow:aPoint] : [self convertBaseToScreen:aPoint];
3507 }
3508 
3512 - (CGPoint)convertGlobalToBase:(CGPoint)aPoint
3513 {
3514  return [CPPlatform isBrowser] ? [self convertPlatformWindowToBase:aPoint] : [self convertScreenToBase:aPoint];
3515 }
3516 
3520 - (CGPoint)convertBaseToPlatformWindow:(CGPoint)aPoint
3521 {
3522  if ([self _sharesChromeWithPlatformWindow])
3523  return CGPointMakeCopy(aPoint);
3524 
3525  var origin = [self frame].origin;
3526 
3527  return CGPointMake(aPoint.x + origin.x, aPoint.y + origin.y);
3528 }
3529 
3533 - (CGPoint)convertPlatformWindowToBase:(CGPoint)aPoint
3534 {
3535  if ([self _sharesChromeWithPlatformWindow])
3536  return CGPointMakeCopy(aPoint);
3537 
3538  var origin = [self frame].origin;
3539 
3540  return CGPointMake(aPoint.x - origin.x, aPoint.y - origin.y);
3541 }
3542 
3543 - (CGPoint)convertScreenToBase:(CGPoint)aPoint
3544 {
3545  return [self convertPlatformWindowToBase:[_platformWindow convertScreenToBase:aPoint]];
3546 }
3547 
3548 - (CGPoint)convertBaseToScreen:(CGPoint)aPoint
3549 {
3550  return [_platformWindow convertBaseToScreen:[self convertBaseToPlatformWindow:aPoint]];
3551 }
3552 
3553 - (void)_setSharesChromeWithPlatformWindow:(BOOL)shouldShareFrameWithPlatformWindow
3554 {
3555  // We canna' do it captain! We just don't have the power!
3556  if (shouldShareFrameWithPlatformWindow && [CPPlatform isBrowser])
3557  return;
3558 
3559  _sharesChromeWithPlatformWindow = shouldShareFrameWithPlatformWindow;
3560 
3561  [self _updateShadow];
3562 }
3563 
3564 - (BOOL)_sharesChromeWithPlatformWindow
3565 {
3566  return _sharesChromeWithPlatformWindow;
3567 }
3568 
3569 // Undo and Redo Support
3573 - (CPUndoManager)undoManager
3574 {
3575  // If we've ever created an undo manager, return it.
3576  if (_undoManager)
3577  return _undoManager;
3578 
3579  // If not, check to see if the document has one.
3580  var documentUndoManager = [[_windowController document] undoManager];
3581 
3582  if (documentUndoManager)
3583  return documentUndoManager;
3584 
3585  // If not, check to see if the delegate has one.
3586  if ([self _delegateRespondsToWindowWillUndoManager])
3587  return [self _sendDelegateWindowWillReturnUndoManager];
3588 
3589  // If not, create one.
3590  if (!_undoManager)
3591  _undoManager = [[CPUndoManager alloc] init];
3592 
3593  return _undoManager;
3594 }
3595 
3600 - (void)undo:(id)aSender
3601 {
3602  [[self undoManager] undo];
3603 }
3604 
3609 - (void)redo:(id)aSender
3610 {
3611  [[self undoManager] redo];
3612 }
3613 
3614 - (BOOL)containsPoint:(CGPoint)aPoint
3615 {
3616  return CGRectContainsPoint(_frame, aPoint);
3617 }
3618 
3619 /* aPoint should be global */
3620 - (BOOL)_isValidMousePoint:(CGPoint)aPoint
3621 {
3622  // If we are using the new resizing mode, mouse events are valid
3623  // outside the window's frame for non-full platform windows.
3624  var mouseFrame = (!_isFullPlatformWindow && (_styleMask & CPResizableWindowMask) && (CPWindowResizeStyle === CPWindowResizeStyleModern)) ? CGRectInset(_frame, -_CPWindowViewResizeSlop, -_CPWindowViewResizeSlop) : _frame;
3625 
3626  return CGRectContainsPoint(mouseFrame, aPoint);
3627 }
3628 
3629 @end
3630 
3631 @implementation CPWindow (Deprecated)
3636 - (void)setFullBridge:(BOOL)shouldBeFullBridge
3637 {
3638  _CPReportLenientDeprecation([self class], _cmd, @selector(setFullPlatformWindow:));
3639 
3640  [self setFullPlatformWindow:shouldBeFullBridge];
3641 }
3642 
3647 - (BOOL)isFullBridge
3648 {
3649  return [self isFullPlatformWindow];
3650 }
3651 
3652 /*
3653  @ignore
3654 */
3655 - (CGPoint)convertBaseToBridge:(CGPoint)aPoint
3656 {
3657  return [self convertBaseToPlatformWindow:aPoint];
3658 }
3659 
3660 /*
3661  @ignore
3662 */
3663 - (CGPoint)convertBridgeToBase:(CGPoint)aPoint
3664 {
3665  return [self convertPlatformWindowToBase:aPoint];
3666 }
3667 
3668 @end
3669 
3670 var interpolate = function(fromValue, toValue, progress)
3671 {
3672  return fromValue + (toValue - fromValue) * progress;
3673 };
3674 
3675 /* @ignore */
3676 @implementation _CPWindowFrameAnimation : CPAnimation
3677 {
3678  CPWindow _window;
3679 
3680  CGRect _startFrame;
3681  CGRect _targetFrame;
3682 }
3683 
3684 - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
3685 {
3686  self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
3687 
3688  if (self)
3689  {
3690  _window = aWindow;
3691 
3692  _targetFrame = CGRectMakeCopy(aTargetFrame);
3693  _startFrame = CGRectMakeCopy([_window frame]);
3694  }
3695 
3696  return self;
3697 }
3698 
3699 - (void)startAnimation
3700 {
3701  [super startAnimation];
3702 
3703  _window._isAnimating = YES;
3704 }
3705 
3706 - (void)setCurrentProgress:(float)aProgress
3707 {
3708  [super setCurrentProgress:aProgress];
3709 
3710  var value = [self currentValue];
3711 
3712  if (value == 1.0)
3713  _window._isAnimating = NO;
3714 
3715  var newFrame = CGRectMake(
3716  interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value),
3717  interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value),
3718  interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value),
3719  interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value));
3720 
3721  [_window setFrame:newFrame display:YES animate:NO];
3722 }
3723 
3724 @end
3725 
3726 
3728 
3729 /* @ignore */
3730 - (id)_dragHitTest:(CGPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
3731 {
3732  // If none of our views or ourselves has registered for drag events...
3733  if (!_inclusiveRegisteredDraggedTypes)
3734  return nil;
3735 
3736 // We don't need to do this because the only place this gets called
3737 // -_dragHitTest: in CPPlatformWindow does this already. Perhaps to
3738 // be safe?
3739 // if (![self containsPoint:aPoint])
3740 // return nil;
3741 
3742  var adjustedPoint = [self convertPlatformWindowToBase:aPoint],
3743  hitView = [_windowView hitTest:adjustedPoint];
3744 
3745  while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
3746  hitView = [hitView superview];
3747 
3748  if (hitView)
3749  return hitView;
3750 
3751  if ([aPasteboard availableTypeFromArray:[self registeredDraggedTypes]])
3752  return self;
3753 
3754  return nil;
3755 }
3756 
3757 @end
3758 
3759 function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasShadow, aLevel)
3760 {
3761  return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel };
3762 }
3763 
3765 
3769 - (void)_setChildOrdering:(CPWindowOrderingMode)aValue
3770 {
3771  _childOrdering = aValue;
3772 }
3773 
3774 @end