1/** <title>NSWindow</title> 2 3 <abstract>The window class</abstract> 4 5 Copyright (C) 1996-2015 Free Software Foundation, Inc. 6 7 Author: Scott Christley <scottc@net-community.com> 8 Venkat Ajjanagadde <venkat@ocbi.com> 9 Date: 1996 10 Author: Felipe A. Rodriguez <far@ix.netcom.com> 11 Date: June 1998 12 Author: Richard Frith-Macdonald <richard@brainstorm.co.uk> 13 Date: December 1998 14 15 This file is part of the GNUstep GUI Library. 16 17 This library is free software; you can redistribute it and/or 18 modify it under the terms of the GNU Lesser General Public 19 License as published by the Free Software Foundation; either 20 version 2 of the License, or (at your option) any later version. 21 22 This library is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public 28 License along with this library; see the file COPYING.LIB. 29 If not, see <http://www.gnu.org/licenses/> or write to the 30 Free Software Foundation, 51 Franklin Street, Fifth Floor, 31 Boston, MA 02110-1301, USA. 32*/ 33 34#import "config.h" 35#include <math.h> 36#include <float.h> 37 38#import <Foundation/NSArray.h> 39#import <Foundation/NSDebug.h> 40#import <Foundation/NSRunLoop.h> 41#import <Foundation/NSScanner.h> 42#import <Foundation/NSAutoreleasePool.h> 43#import <Foundation/NSString.h> 44#import <Foundation/NSCoder.h> 45#import <Foundation/NSArray.h> 46#import <Foundation/NSEnumerator.h> 47#import <Foundation/NSGeometry.h> 48#import <Foundation/NSNotification.h> 49#import <Foundation/NSValue.h> 50#import <Foundation/NSException.h> 51#import <Foundation/NSSet.h> 52#import <Foundation/NSLock.h> 53#import <Foundation/NSUserDefaults.h> 54#import <Foundation/NSUndoManager.h> 55 56#import "AppKit/NSAnimation.h" 57#import "AppKit/NSApplication.h" 58#import "AppKit/NSButton.h" 59#import "AppKit/NSButtonCell.h" 60#import "AppKit/NSCachedImageRep.h" 61#import "AppKit/NSColor.h" 62#import "AppKit/NSColorList.h" 63#import "AppKit/NSCursor.h" 64#import "AppKit/NSDocumentController.h" 65#import "AppKit/NSDocument.h" 66#import "AppKit/NSDragging.h" 67#import "AppKit/NSEvent.h" 68#import "AppKit/NSFont.h" 69#import "AppKit/NSGraphics.h" 70#import "AppKit/NSHelpManager.h" 71#import "AppKit/NSKeyValueBinding.h" 72#import "AppKit/NSImage.h" 73#import "AppKit/NSMenu.h" 74#import "AppKit/NSPasteboard.h" 75#import "AppKit/NSScreen.h" 76#import "AppKit/NSTextField.h" 77#import "AppKit/NSTextFieldCell.h" 78#import "AppKit/NSView.h" 79#import "AppKit/NSWindow.h" 80#import "AppKit/NSWindowController.h" 81#import "AppKit/PSOperators.h" 82 83#import "GNUstepGUI/GSTheme.h" 84#import "GNUstepGUI/GSTrackingRect.h" 85#import "GNUstepGUI/GSDisplayServer.h" 86#import "GNUstepGUI/GSWindowDecorationView.h" 87#import "GSBindingHelpers.h" 88#import "GSGuiPrivate.h" 89#import "GSToolTips.h" 90#import "GSIconManager.h" 91#import "NSToolbarFrameworkPrivate.h" 92#import "NSViewPrivate.h" 93 94#define GSI_ARRAY_TYPES 0 95#define GSI_ARRAY_TYPE NSWindow * 96#define GSI_ARRAY_NO_RELEASE 1 97#define GSI_ARRAY_NO_RETAIN 1 98 99#ifdef GSIArray 100#undef GSIArray 101#endif 102#include <GNUstepBase/GSIArray.h> 103 104static GSToolTips *toolTipVisible = nil; 105static id<GSWindowDecorator> windowDecorator = nil; 106 107 108BOOL GSViewAcceptsDrag(NSView *v, id<NSDraggingInfo> dragInfo); 109 110@interface NSObject (DragInfoBackend) 111- (void) dragImage: (NSImage*)anImage 112 at: (NSPoint)screenLocation 113 offset: (NSSize)initialOffset 114 event: (NSEvent*)event 115 pasteboard: (NSPasteboard*)pboard 116 source: (id)sourceObject 117 slideBack: (BOOL)slideFlag; 118- (void) postDragEvent: (NSEvent*)event; 119@end 120 121@interface NSView (MoveToWindow) 122// Normally this method is only used internally. 123- (void) _viewWillMoveToWindow: (NSWindow*)newWindow; 124@end 125 126@interface NSScreen (PrivateMethods) 127- (id) _initWithScreenNumber: (int)screen; 128@end 129 130@interface NSApplication(Inactive) 131- (BOOL) _isWindowInactive: (NSWindow *)window; 132- (void) _setWindow: (NSWindow *)window inactive: (BOOL)inactive; 133@end 134 135@interface GSWindowAnimationDelegate : NSObject 136{ 137} 138@end 139 140@implementation GSWindowAnimationDelegate 141- (void) animationDidEnd: (NSAnimation *)animation 142{ 143 AUTORELEASE(animation); 144} 145 146- (void) animationDidStop: (NSAnimation *)animation 147{ 148 AUTORELEASE(animation); 149} 150 151@end 152 153static GSWindowAnimationDelegate *animationDelegate; 154 155/* 156 * Category for internal methods (for use only within the NSWindow class itself 157 * or with other AppKit classes. 158 */ 159@interface NSWindow (GNUstepPrivate) 160 161+ (void) _addAutodisplayedWindow: (NSWindow *)w; 162+ (void) _removeAutodisplayedWindow: (NSWindow *)w; 163+ (void) _setToolTipVisible: (GSToolTips*)t; 164+ (GSToolTips*) _toolTipVisible; 165 166- (void) _lossOfKeyOrMainWindow; 167- (NSView *) _windowView; 168- (NSScreen *) _screenForFrame: (NSRect)frame; 169@end 170 171@implementation NSWindow (GNUstepPrivate) 172 173+ (void) _setToolTipVisible: (GSToolTips*)t 174{ 175 toolTipVisible = t; 176} 177 178+ (GSToolTips*) _toolTipVisible 179{ 180 return toolTipVisible; 181} 182 183/* Window autodisplay machinery. */ 184- (void) _handleAutodisplay 185{ 186 if (_f.is_autodisplay && _f.views_need_display) 187 { 188 [self disableFlushWindow]; 189 [self displayIfNeeded]; 190 [self enableFlushWindow]; 191 [self flushWindowIfNeeded]; 192 } 193} 194 195static NSArray *modes = nil; 196 197/* Array of windows we might need to handle autodisplay for (in practice 198a list of windows that are, wrt. -gui, on-screen). */ 199static GSIArray_t autodisplayedWindows; 200 201/* 202This method handles all normal displaying. It is set to be run on each 203runloop iteration when the first window is created 204 205The reason why this performer is always added, as opposed to adding it 206when display is needed and not re-adding it here, is that 207-setNeedsDisplay* might be called from a method invoked by 208-performSelector:target:argument:order:modes:, and if it is, the display 209needs to happen in the same runloop iteration, before blocking for 210events. If the performer were added in a call to another performer, it 211wouldn't be called until the next runloop iteration, ie. after the runloop 212has blocked and waited for events. 213*/ 214+(void) _handleAutodisplay: (id)bogus 215{ 216 int i; 217 for (i = 0; i < GSIArrayCount(&autodisplayedWindows); i++) 218 [GSIArrayItemAtIndex(&autodisplayedWindows, i).ext _handleAutodisplay]; 219 220 [[NSRunLoop currentRunLoop] 221 performSelector: @selector(_handleAutodisplay:) 222 target: self 223 argument: nil 224 order: 600000 225 modes: modes]; 226} 227 228+(void) _addAutodisplayedWindow: (NSWindow *)w 229{ 230 int i; 231 /* If it's the first time we're called, set up the performer and modes 232 array. */ 233 if (!modes) 234 { 235 modes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, 236 NSModalPanelRunLoopMode, 237 NSEventTrackingRunLoopMode, nil]; 238 [[NSRunLoop currentRunLoop] 239 performSelector: @selector(_handleAutodisplay:) 240 target: self 241 argument: nil 242 order: 600000 243 modes: modes]; 244 GSIArrayInitWithZoneAndCapacity(&autodisplayedWindows, 245 NSDefaultMallocZone(), 1); 246 } 247 248 /* O(n), but it's much more important that _handleAutodisplay: can iterate 249 quickly over the array. (_handleAutodisplay: is called once for every 250 event, this method is only called when windows are ordered in or out.) */ 251 for (i = 0; i < GSIArrayCount(&autodisplayedWindows); i++) 252 if (GSIArrayItemAtIndex(&autodisplayedWindows, i).ext == w) 253 return; 254 GSIArrayAddItem(&autodisplayedWindows, (GSIArrayItem)w); 255} 256 257+(void) _removeAutodisplayedWindow: (NSWindow *)w 258{ 259 int i; 260 for (i = 0; i < GSIArrayCount(&autodisplayedWindows); i++) 261 if (GSIArrayItemAtIndex(&autodisplayedWindows, i).ext == w) 262 { 263 GSIArrayRemoveItemAtIndex(&autodisplayedWindows, i); 264 return; 265 } 266 /* This happens eg. if a window is ordered out twice. In such cases, 267 the window has already been removed from the list, so we don't need 268 to do anything here. */ 269} 270 271 272/* We get here if we were ordered out or miniaturized. In this case if 273 we were the key or main window, go through the list of all windows 274 and try to find another window that can take our place as key 275 and/or main. Automatically ignore windows that cannot become 276 key/main and skip the main menu window (which is the only 277 non-obvious window that can become key) unless we have no choice 278 (i.e. all the candidate windows were ordered out.) 279*/ 280- (void) _lossOfKeyOrMainWindow 281{ 282 NSArray *windowList = GSOrderedWindows(); 283 NSUInteger pos = [windowList indexOfObjectIdenticalTo: self]; 284 NSUInteger c = [windowList count]; 285 NSUInteger i; 286 287 // Don't bother when application is closing. 288 if ([NSApp isRunning] == NO) 289 return; 290 291 if (!c) 292 return; 293 294 if (pos == NSNotFound) 295 { 296 pos = c; 297 } 298 299 if ([self isKeyWindow]) 300 { 301 NSWindow *w = [NSApp mainWindow]; 302 303 [self resignKeyWindow]; 304 if (w != nil && w != self 305 && [w canBecomeKeyWindow]) 306 { 307 [w makeKeyWindow]; 308 } 309 else 310 { 311 NSWindow *menu_window = [[NSApp mainMenu] window]; 312 313 // try all windows front to back except self and menu 314 for (i = 0; i < c; i++) 315 { 316 if (i != pos) 317 { 318 w = [windowList objectAtIndex: i]; 319 if ([w isVisible] && [w canBecomeKeyWindow] 320 && w != menu_window) 321 { 322 [w makeKeyWindow]; 323 break; 324 } 325 } 326 } 327 328 /* 329 * if we didn't find a possible key window - use the main menu window 330 */ 331 if (i == c) 332 { 333 if (menu_window != nil) 334 { 335 // FIXME: Why this call and not makeKeyWindow? 336 [GSServerForWindow(menu_window) setinputfocus: 337 [menu_window windowNumber]]; 338 } 339 } 340 } 341 } 342 343 if ([self isMainWindow]) 344 { 345 NSWindow *w = [NSApp keyWindow]; 346 347 [self resignMainWindow]; 348 if (w != nil && [w canBecomeMainWindow]) 349 { 350 [w makeMainWindow]; 351 } 352 else 353 { 354 // try all windows front to back except self 355 for (i = 0; i < c; i++) 356 { 357 if (i != pos) 358 { 359 w = [windowList objectAtIndex: i]; 360 if ([w isVisible] && [w canBecomeMainWindow]) 361 { 362 [w makeMainWindow]; 363 break; 364 } 365 } 366 } 367 } 368 } 369} 370 371- (NSView *) _windowView 372{ 373 return _wv; 374} 375 376/* 377 * This is just the Apple name for our _windowView method. 378 */ 379- (NSView *) _borderView 380{ 381 return _wv; 382} 383 384/* Support method to properly implement the 'screen' method for NSWindow. 385 According to documentation the 'screen' method should return the screen 386 that the window "show up the most or nil". This method supports the 'screen' 387 method and internal requests for the correct 'screen' based on the 388 supplied frame request. 389*/ 390- (NSScreen *) _screenForFrame: (NSRect)frame 391{ 392 // FIXME: We always return the first screen, if there is no overlap. 393 // Other code relies on [window screen] not returning nil. 394 CGFloat largest = -1.0; 395 NSArray *screens = [NSScreen screens]; 396 NSInteger index = 0; 397 NSScreen *theScreen = nil; 398 399 for (index = 0; index < [screens count]; ++index) 400 { 401 NSScreen *screen = [screens objectAtIndex: index]; 402 NSRect sframe = [screen frame]; 403 NSRect iframe = NSIntersectionRect(frame, sframe); 404 CGFloat isize = NSWidth(iframe) * NSHeight(iframe); 405 406 if (isize > largest) 407 { 408 largest = isize; 409 theScreen = screen; 410 } 411 } 412 NSDebugLLog(@"NSWindow", @"%s: frame: %@ screen: %@ size: %ld\n", __PRETTY_FUNCTION__, 413 NSStringFromRect(frame), theScreen, (long)largest); 414 415 return theScreen; 416} 417 418@end 419 420 421@interface NSMiniWindow : NSWindow 422@end 423 424@implementation NSMiniWindow 425 426- (BOOL) canBecomeMainWindow 427{ 428 return NO; 429} 430 431- (BOOL) canBecomeKeyWindow 432{ 433 return NO; 434} 435 436- (void) _initDefaults 437{ 438 [super _initDefaults]; 439 [self setExcludedFromWindowsMenu: YES]; 440 [self setReleasedWhenClosed: NO]; 441 /* App icons and mini windows are displayed at dock level by default. Yet, 442 with the current window level mapping in -back, some window managers 443 will order pop up and context menus behind app icons and mini windows. 444 Therefore, it is possible to have app icons and mini windows displayed 445 at normal window level under control of a user preference. */ 446 // See also NSIconWindow _initDefaults in NSApplication.m 447 if ([[NSUserDefaults standardUserDefaults] 448 boolForKey: @"GSAllowWindowsOverIcons"] == YES) 449 _windowLevel = NSDockWindowLevel; 450} 451 452@end 453 454@interface NSMiniWindowView : NSView 455{ 456 NSCell *imageCell; 457 NSTextFieldCell *titleCell; 458} 459- (void) setImage: (NSImage*)anImage; 460- (void) setTitle: (NSString*)aString; 461@end 462 463static NSCell *tileCell = nil; 464 465static NSSize scaledIconSizeForSize(NSSize imageSize) 466{ 467 NSSize iconSize, retSize; 468 469 iconSize = GSGetIconSize(); 470 retSize.width = imageSize.width * iconSize.width / 64; 471 retSize.height = imageSize.height * iconSize.height / 64; 472 return retSize; 473} 474 475@implementation NSMiniWindowView 476 477+ (void) initialize 478{ 479 NSImage *tileImage; 480 NSSize iconSize; 481 482 iconSize = GSGetIconSize(); 483 484 tileImage = [[NSImage imageNamed:@"common_MiniWindowTile"] copy]; 485 [tileImage setScalesWhenResized: YES]; 486 [tileImage setSize: iconSize]; 487 488 tileCell = [[NSCell alloc] initImageCell: tileImage]; 489 RELEASE(tileImage); 490 [tileCell setBordered: NO]; 491} 492 493- (BOOL) acceptsFirstMouse: (NSEvent*)theEvent 494{ 495 return YES; 496} 497 498- (void) dealloc 499{ 500 TEST_RELEASE(imageCell); 501 TEST_RELEASE(titleCell); 502 [super dealloc]; 503} 504 505- (void) drawRect: (NSRect)rect 506{ 507 NSSize iconSize = GSGetIconSize(); 508 509 [tileCell drawWithFrame: NSMakeRect(0, 0, iconSize.width, iconSize.height) 510 inView: self]; 511 [imageCell 512 drawWithFrame: NSMakeRect(iconSize.width / 8, 513 (iconSize.height / 16), 514 iconSize.width - ((iconSize.width / 8) * 2), 515 iconSize.height - ((iconSize.height / 8) * 2)) 516 inView: self]; 517 [titleCell drawWithFrame: NSMakeRect(3, iconSize.height - 13, 518 iconSize.width - 6, 10) 519 inView: self]; 520} 521 522- (void) mouseDown: (NSEvent*)theEvent 523{ 524 if ([theEvent clickCount] >= 2) 525 { 526 NSWindow *w = [_window counterpart]; 527 [w deminiaturize: self]; 528 } 529 else 530 { 531 NSPoint lastLocation; 532 NSPoint location; 533 NSUInteger eventMask = NSLeftMouseDownMask | NSLeftMouseUpMask 534 | NSPeriodicMask | NSOtherMouseUpMask | NSRightMouseUpMask; 535 NSDate *theDistantFuture = [NSDate distantFuture]; 536 BOOL done = NO; 537 538 lastLocation = [theEvent locationInWindow]; 539 [NSEvent startPeriodicEventsAfterDelay: 0.02 withPeriod: 0.02]; 540 541 while (!done) 542 { 543 theEvent = [NSApp nextEventMatchingMask: eventMask 544 untilDate: theDistantFuture 545 inMode: NSEventTrackingRunLoopMode 546 dequeue: YES]; 547 548 switch ([theEvent type]) 549 { 550 case NSRightMouseUp: 551 case NSOtherMouseUp: 552 case NSLeftMouseUp: 553 /* right mouse up or left mouse up means we're done */ 554 done = YES; 555 break; 556 case NSPeriodic: 557 location = [_window mouseLocationOutsideOfEventStream]; 558 if (NSEqualPoints(location, lastLocation) == NO) 559 { 560 NSPoint origin = [_window frame].origin; 561 562 origin.x += (location.x - lastLocation.x); 563 origin.y += (location.y - lastLocation.y); 564 [_window setFrameOrigin: origin]; 565 } 566 break; 567 568 default: 569 break; 570 } 571 } 572 [NSEvent stopPeriodicEvents]; 573 } 574} 575 576- (void) setImage: (NSImage*)anImage 577{ 578 NSImage *imgCopy = [anImage copy]; 579 580 [imgCopy setScalesWhenResized: YES]; 581 if (imgCopy != nil) 582 { 583 [imgCopy setSize: scaledIconSizeForSize([imgCopy size])]; 584 } 585 586 if (imageCell == nil) 587 { 588 imageCell = [[NSCell alloc] initImageCell: imgCopy]; 589 [imageCell setBordered: NO]; 590 } 591 else 592 { 593 [imageCell setImage: imgCopy]; 594 } 595 RELEASE(imgCopy); 596 [self setNeedsDisplay: YES]; 597} 598 599- (void) setTitle: (NSString*)aString 600{ 601 if (titleCell == nil) 602 { 603 CGFloat fontSize; 604 605 titleCell = [[NSTextFieldCell alloc] initTextCell: aString]; 606 [titleCell setSelectable: NO]; 607 [titleCell setEditable: NO]; 608 [titleCell setBordered: NO]; 609 [titleCell setAlignment: NSCenterTextAlignment]; 610 [titleCell setDrawsBackground: NO]; 611 [titleCell setTextColor: [NSColor whiteColor]]; 612 fontSize = [NSFont systemFontSizeForControlSize: NSMiniControlSize]; 613 [titleCell setFont: [NSFont systemFontOfSize: fontSize]]; 614 } 615 else 616 { 617 [titleCell setStringValue: aString]; 618 } 619 [self setNeedsDisplay: YES]; 620} 621 622@end 623 624 625 626/***************************************************************************** 627 * 628 * NSWindow 629 * 630 *****************************************************************************/ 631 632/** 633 <unit> 634 <heading>NSWindow</heading> 635 636 <p> Instances of the NSWindow class handle on-screen windows, their 637 associated NSViews, and events generate by the user. An NSWindow's 638 size is defined by its frame rectangle, which encompasses its entire 639 structure, and its content rectangle, which includes only the 640 content. 641 </p> 642 643 <p> Every NSWindow has a content view, the NSView which forms the 644 root of the window's view hierarchy. This view can be set using the 645 <code>setContentView:</code> method, and accessed through the 646 <code>contentView</code> method. <code>setContentView:</code> 647 replaces the default content view created by NSWindow. 648 </p> 649 650 <p> Other views may be added to the window by using the content 651 view's <code>addSubview:</code> method. These subviews can also 652 have subviews added, forming a tree structure, the view hierarchy. 653 When an NSWindow must display itself, it causes this hierarchy to 654 draw itself. Leaf nodes in the view hierarchy are drawn last, 655 causing them to potentially obscure views further up in the 656 hierarchy. 657 </p> 658 659 <p> A delegate can be specified for an NSWindow, which will receive 660 notifications of events pertaining to the window. The delegate is 661 set using <code>setDelegate:</code>, and can be retrieved using 662 <code>delegate</code>. The delegate can restrain resizing by 663 implementing the <code>windowWillResize: toSize:</code> method, or 664 control the closing of the window by implementing 665 <code>windowShouldClose:</code>. 666 </p> 667 668 </unit> 669*/ 670@implementation NSWindow 671 672/* 673 * Class variables 674 */ 675static SEL ccSel; 676static SEL ctSel; 677static IMP ccImp; 678static IMP ctImp; 679static Class responderClass; 680static Class viewClass; 681static NSMutableSet *autosaveNames; 682static NSMapTable *windowmaps = NULL; 683static NSMapTable *windowUndoManagers = NULL; 684static NSNotificationCenter *nc = nil; 685 686/* 687 * Class methods 688 */ 689+ (void) initialize 690{ 691 if (self == [NSWindow class]) 692 { 693 [self setVersion: 3]; 694 ccSel = @selector(_checkCursorRectangles:forEvent:); 695 ctSel = @selector(_checkTrackingRectangles:forEvent:); 696 ccImp = [self instanceMethodForSelector: ccSel]; 697 ctImp = [self instanceMethodForSelector: ctSel]; 698 responderClass = [NSResponder class]; 699 viewClass = [NSView class]; 700 autosaveNames = [NSMutableSet new]; 701 windowmaps = NSCreateMapTable(NSIntMapKeyCallBacks, 702 NSNonRetainedObjectMapValueCallBacks, 20); 703 nc = [NSNotificationCenter defaultCenter]; 704 705 [self exposeBinding: NSTitleBinding]; 706 } 707} 708 709+ (void) removeFrameUsingName: (NSString*)name 710{ 711 if (name != nil) 712 { 713 NSString *key; 714 715 key = [NSString stringWithFormat: @"NSWindow Frame %@", name]; 716 [[NSUserDefaults standardUserDefaults] removeObjectForKey: key]; 717 } 718} 719 720+ (NSRect) contentRectForFrameRect: (NSRect)aRect 721 styleMask: (NSUInteger)aStyle 722{ 723 if (!windowDecorator) 724 windowDecorator = [GSWindowDecorationView windowDecorator]; 725 726 return [windowDecorator contentRectForFrameRect: aRect 727 styleMask: aStyle]; 728} 729 730+ (NSRect) frameRectForContentRect: (NSRect)aRect 731 styleMask: (NSUInteger)aStyle 732{ 733 if (!windowDecorator) 734 windowDecorator = [GSWindowDecorationView windowDecorator]; 735 736 return [windowDecorator frameRectForContentRect: aRect 737 styleMask: aStyle]; 738} 739 740+ (CGFloat) minFrameWidthWithTitle: (NSString *)aTitle 741 styleMask: (NSUInteger)aStyle 742{ 743 if (!windowDecorator) 744 windowDecorator = [GSWindowDecorationView windowDecorator]; 745 746 return [windowDecorator minFrameWidthWithTitle: aTitle 747 styleMask: aStyle]; 748} 749 750/* default Screen and window depth */ 751+ (NSWindowDepth) defaultDepthLimit 752{ 753 return [[NSScreen deepestScreen] depth]; 754} 755 756+ (void)menuChanged: (NSMenu*)aMenu 757{ 758 // FIXME: This method is for MS Windows only, does nothing 759 // on other window systems 760} 761 762/* 763 * Instance methods 764 */ 765- (id) init 766{ 767 NSUInteger style; 768 769 style = NSTitledWindowMask | NSClosableWindowMask 770 | NSMiniaturizableWindowMask | NSResizableWindowMask; 771 772 return [self initWithContentRect: NSZeroRect 773 styleMask: style 774 backing: NSBackingStoreBuffered 775 defer: NO]; 776} 777 778/* 779It is important to make sure that the window is in a meaningful state after 780this has been called, and that the backend window can be recreated later, 781since one-shot windows may have their backend windows created and terminated 782many times. 783*/ 784- (void) _terminateBackendWindow 785{ 786 if (_windowNum) 787 { 788 [_wv setWindowNumber: 0]; 789 790 /* Check for context also as it might have disappeared before us */ 791 if (_context && _gstate) 792 { 793 GSUndefineGState(_context, _gstate); 794 _gstate = 0; 795 } 796 797 if (_context) 798 { 799 /* 800 If there was a context, clear it and let it remove the 801 window in that process. This indirection is needed so solve the 802 circular references between the window and the context. 803 But first undo the release call in _startBackendWindow. 804 */ 805 RETAIN(self); 806 DESTROY(_context); 807 } 808 809 [GSServerForWindow(self) termwindow: _windowNum]; 810 NSMapRemove(windowmaps, (void*)(intptr_t)_windowNum); 811 _windowNum = 0; 812 } 813} 814 815- (void) dealloc 816{ 817 // Remove all key value bindings for this object. 818 [GSKeyValueBinding unbindAllForObject: self]; 819 820 DESTROY(_toolbar); 821 [nc removeObserver: self]; 822 [[self class] _removeAutodisplayedWindow: self]; 823 [NSApp removeWindowsItem: self]; 824 [NSApp _windowWillDealloc: self]; 825 826 NSAssert([NSApp keyWindow] != self, @"window being deallocated is key"); 827 NSAssert([NSApp mainWindow] != self, @"window being deallocated is main"); 828 829 if (windowUndoManagers != NULL) 830 NSMapRemove(windowUndoManagers, self); 831 832 if (_autosaveName != nil) 833 { 834 [autosaveNames removeObject: _autosaveName]; 835 _autosaveName = nil; 836 } 837 838 if (_counterpart != 0 && (_styleMask & NSMiniWindowMask) == 0) 839 { 840 NSWindow *mini = [NSApp windowWithWindowNumber: _counterpart]; 841 842 _counterpart = 0; 843 DESTROY(mini); 844 } 845 846 /* Terminate backend window early so that the receiver is no longer returned 847 from GSOrderedWindows() or GSAllWindows(). This helps to prevent crashes 848 due to a race with some lame window managers under X that do not update 849 the _NET_CLIENT_LIST_STACKING property quickly enough. GSOrderedWindows() 850 may be called (indirectly) when a tooltip is visible while a window is 851 deallocated. */ 852 if (_windowNum) 853 { 854 [self _terminateBackendWindow]; 855 } 856 857 /* Clean references to this window - important if some of the views 858 are not deallocated now */ 859 [_wv _viewWillMoveToWindow: nil]; 860 /* NB: releasing the window view does not necessarily result in the 861 deallocation of the window's views ! - some of them might be 862 retained for some other reason by the programmer or by other 863 parts of the code */ 864 DESTROY(_wv); 865 DESTROY(_fieldEditor); 866 DESTROY(_backgroundColor); 867 DESTROY(_representedFilename); 868 DESTROY(_miniaturizedTitle); 869 DESTROY(_miniaturizedImage); 870 DESTROY(_windowTitle); 871 DESTROY(_rectsBeingDrawn); 872 DESTROY(_initialFirstResponder); 873 DESTROY(_defaultButtonCell); 874 DESTROY(_cachedImage); 875 DESTROY(_children); 876 DESTROY(_lastLeftMouseDownView); 877 DESTROY(_lastRightMouseDownView); 878 DESTROY(_lastOtherMouseDownView); 879 DESTROY(_lastDragView); 880 DESTROY(_screen); 881 882 /* 883 * FIXME This should not be necessary - the views should have removed 884 * their drag types, so we should already have been removed. 885 */ 886 [GSServerForWindow(self) removeDragTypes: nil fromWindow: self]; 887 888 if (_delegate != nil) 889 { 890 [nc removeObserver: _delegate name: nil object: self]; 891 _delegate = nil; 892 } 893 894 [super dealloc]; 895} 896 897- (NSString*) description 898{ 899 return [[super description] stringByAppendingFormat: @"Number: %ld Title: %@", 900 (long) [self windowNumber], [self title]]; 901} 902 903- (void) _startBackendWindow 904{ 905 NSDictionary *info; 906 907 NSMapInsert(windowmaps, (void*)(intptr_t)_windowNum, self); 908 909 // Make sure not to create an autoreleased object, 910 // as this will lead to problems when the window is deallocated. 911 info = [[NSDictionary alloc] 912 initWithObjects: &self 913 forKeys: &NSGraphicsContextDestinationAttributeName 914 count: 1]; 915 _context = [[NSGraphicsContext alloc] initWithContextInfo: info]; 916 RELEASE(info); 917 if (_context) 918 { 919 // Now the context retains the window, release it once to make up 920 RELEASE(self); 921 } 922 923 // Set window in new _gstate 924 _gstate = GSDefineGState(_context); 925 926 { 927 NSRect frame = _frame; 928 frame.origin = NSZeroPoint; 929 [_wv setFrame: frame]; 930 [_wv setWindowNumber: _windowNum]; 931 [_wv setDocumentEdited: _f.is_edited]; 932 [_wv setNeedsDisplay: YES]; 933 } 934} 935 936- (void) _initBackendWindow 937{ 938 NSCountedSet *dragTypes; 939 GSDisplayServer *srv = GSCurrentServer(); 940 941 /* If we were deferred or one shot, our drag types may not have 942 been registered properly in the backend. Remove them then re-add 943 them when we create the window */ 944 dragTypes = [srv dragTypesForWindow: self]; 945 if (dragTypes) 946 { 947 // As this is the original entry, it will change soon. 948 // We use a copy to reregister the same types later on. 949 dragTypes = [dragTypes copy]; 950 951 /* Now we need to remove all the drag types for this window. */ 952 [srv removeDragTypes: nil fromWindow: self]; 953 } 954 955 _windowNum = [srv window: _frame 956 : _backingType 957 : _styleMask 958 : [_screen screenNumber]]; 959 if (_windowNum == 0) 960 [NSException raise:@"No Window" format:@"Failed to obtain window from the back end"]; 961 [srv setwindowlevel: [self level] : _windowNum]; 962 if (_parent != nil) 963 [srv setParentWindow: [_parent windowNumber] 964 forChildWindow: _windowNum]; 965 966 // Set up context 967 [self _startBackendWindow]; 968 969 /* Ok, now add the drag types back */ 970 if (dragTypes) 971 { 972 id type; 973 NSMutableArray *dragTypesArray = [NSMutableArray array]; 974 NSEnumerator *enumerator = [dragTypes objectEnumerator]; 975 976 NSDebugLLog(@"NSWindow", @"Resetting drag types for window"); 977 /* Now we need to restore the drag types. */ 978 979 /* Put all the drag types to the dragTypesArray - counted 980 * with their multiplicity. 981 */ 982 while ((type = [enumerator nextObject]) != nil) 983 { 984 NSUInteger i, count = [dragTypes countForObject: type]; 985 986 for (i = 0; i < count; i++) 987 { 988 [dragTypesArray addObject: type]; 989 } 990 } 991 992 /* Now store the array. */ 993 [srv addDragTypes: dragTypesArray toWindow: self]; 994 // Free our local copy. 995 RELEASE(dragTypes); 996 } 997 998 /* Other stuff we need to do for deferred windows */ 999 if (!NSEqualSizes(_minimumSize, NSZeroSize)) 1000 [self setMinSize: _minimumSize]; 1001 if (!NSEqualSizes(_maximumSize, NSZeroSize)) 1002 [self setMaxSize: _maximumSize]; 1003 if (!NSEqualSizes(_increments, NSZeroSize)) 1004 [self setResizeIncrements: _increments]; 1005 1006 NSDebugLLog(@"NSWindow", @"Created NSWindow window frame %@", 1007 NSStringFromRect(_frame)); 1008} 1009 1010/* 1011 * Initializing and getting a new NSWindow object 1012 */ 1013/** 1014 <p> Initializes the receiver with a content rect of 1015 <var>contentRect</var>, a style mask of <var>styleMask</var>, and a 1016 backing store type of <var>backingType</var>. This is the designated 1017 initializer. 1018 </p> 1019 1020 <p> The style mask values are <code>NSTitledWindowMask</code>, for a 1021 window with a title, <code>NSClosableWindowMask</code>, for a window 1022 with a close widget, <code>NSMiniaturizableWindowMask</code>, for a 1023 window with a miniaturize widget, and 1024 <code>NSResizableWindowMask</code>, for a window with a resizing 1025 widget. These mask values can be OR'd in any combination. 1026 </p> 1027 1028 <p> Backing store values are <code>NSBackingStoreBuffered</code>, 1029 <code>NSBackingStoreRetained</code> and 1030 <code>NSBackingStoreNonretained</code>. 1031 </p> 1032*/ 1033- (id) initWithContentRect: (NSRect)contentRect 1034 styleMask: (NSUInteger)aStyle 1035 backing: (NSBackingStoreType)bufferingType 1036 defer: (BOOL)flag 1037{ 1038 NSRect cframe; 1039 1040 NSAssert(NSApp, 1041 @"The shared NSApplication instance must be created before windows " 1042 @"can be created."); 1043 1044 NSDebugLLog(@"NSWindow", @"NSWindow start of init\n"); 1045 1046 // FIXME: This hack is here to work around a gorm decoding problem. 1047 if (_windowNum) 1048 { 1049 NSLog(@"Window already initialized %d", (int)_windowNum); 1050 return self; 1051 } 1052 1053 /* Initialize attributes and flags */ 1054 [super init]; 1055 [self _initDefaults]; 1056 1057 _attachedSheet = nil; 1058 _backingType = bufferingType; 1059 _styleMask = aStyle; 1060 ASSIGN(_screen, [NSScreen mainScreen]); 1061 _depthLimit = [_screen depth]; 1062 1063 _frame = [NSWindow frameRectForContentRect: contentRect styleMask: aStyle]; 1064 _minimumSize = NSMakeSize(_frame.size.width - contentRect.size.width + 1, 1065 _frame.size.height - contentRect.size.height + 1); 1066 _maximumSize = NSMakeSize (10e4, 10e4); 1067 1068 [self setNextResponder: NSApp]; 1069 1070 _f.cursor_rects_enabled = YES; 1071 _f.cursor_rects_valid = NO; 1072 1073 /* Create the window view */ 1074 cframe.origin = NSZeroPoint; 1075 cframe.size = _frame.size; 1076 if (!windowDecorator) 1077 windowDecorator = [GSWindowDecorationView windowDecorator]; 1078 1079 _wv = [windowDecorator newWindowDecorationViewWithFrame: cframe 1080 window: self]; 1081 [_wv _viewWillMoveToWindow: self]; 1082 [_wv setNextResponder: self]; 1083 1084 /* Create the content view */ 1085 cframe.origin = NSZeroPoint; 1086 cframe.size = contentRect.size; 1087 [self setContentView: AUTORELEASE([[NSView alloc] initWithFrame: cframe])]; 1088 1089 /* rectBeingDrawn is variable used to optimize flushing the backing store. 1090 It is set by NSGraphicsContext during a lockFocus to tell NSWindow what 1091 part a view is drawing in, so NSWindow only has to flush that portion */ 1092 _rectsBeingDrawn = RETAIN([NSMutableArray arrayWithCapacity: 10]); 1093 1094 /* Create window (if not deferred) */ 1095 _windowNum = 0; 1096 _gstate = 0; 1097 if (flag == NO) 1098 { 1099 NSDebugLLog(@"NSWindow", @"Creating NSWindow\n"); 1100 [self _initBackendWindow]; 1101 } 1102 else 1103 NSDebugLLog(@"NSWindow", @"Deferring NSWindow creation\n"); 1104 1105 [nc addObserver: self 1106 selector: @selector(colorListChanged:) 1107 name: NSColorListDidChangeNotification 1108 object: nil]; 1109 [nc addObserver: self 1110 selector: @selector(applicationDidChangeScreenParameters:) 1111 name: NSApplicationDidChangeScreenParametersNotification 1112 object: NSApp]; 1113 1114 NSDebugLLog(@"NSWindow", @"NSWindow end of init\n"); 1115 return self; 1116} 1117 1118/** 1119 <p> Initializes the receiver with a content rect of 1120 <var>contentRect</var>, a style mask of <var>styleMask</var>, a 1121 backing store type of <var>backingType</var> and a boolean 1122 <var>flag</var>. <var>flag</var> specifies whether the window 1123 should be created now (<code>NO</code>), or when it is displayed 1124 (<code>YES</code>). 1125 </p> 1126 1127 <p> The style mask values are <code>NSTitledWindowMask</code>, for a 1128 window with a title, <code>NSClosableWindowMask</code>, for a window 1129 with a close widget, <code>NSMiniaturizableWindowMask</code>, for a 1130 window with a miniaturize widget, and 1131 <code>NSResizableWindowMask</code>, for a window with a resizing 1132 widget. These mask values can be OR'd in any combination. 1133 </p> 1134 1135 <p> Backing store values are <code>NSBackingStoreBuffered</code>, 1136 <code>NSBackingStoreRetained</code> and 1137 <code>NSBackingStoreNonretained</code>. 1138 </p> 1139*/ 1140- (id) initWithContentRect: (NSRect)contentRect 1141 styleMask: (NSUInteger)aStyle 1142 backing: (NSBackingStoreType)bufferingType 1143 defer: (BOOL)flag 1144 screen: (NSScreen*)aScreen 1145{ 1146 self = [self initWithContentRect: contentRect 1147 styleMask: aStyle 1148 backing: bufferingType 1149 defer: flag]; 1150 if (self && aScreen != nil) 1151 { 1152 ASSIGN(_screen, aScreen); 1153 _depthLimit = [_screen depth]; 1154 } 1155 return self; 1156} 1157 1158- (id) initWithWindowRef: (void *)windowRef 1159{ 1160 NSRect contentRect; 1161 unsigned int aStyle; 1162 NSBackingStoreType bufferingType; 1163 NSScreen* aScreen; 1164 int screen; 1165 NSInteger winNum; 1166 GSDisplayServer *srv = GSCurrentServer(); 1167 1168 // Get the properties for the underlying window 1169 winNum = [srv nativeWindow: windowRef : &contentRect : &bufferingType 1170 : &aStyle : &screen]; 1171 1172 // Get the screen for the right screen number. 1173 aScreen = [[NSScreen alloc] _initWithScreenNumber: screen]; 1174 1175 // Set up a NSWindow with the same properties 1176 self = [self initWithContentRect: contentRect 1177 styleMask: aStyle 1178 backing: bufferingType 1179 defer: YES 1180 screen: aScreen]; 1181 RELEASE(aScreen); 1182 1183 // Fake the initialisation of the backend 1184 _windowNum = winNum; 1185 1186 // Set up context 1187 [self _startBackendWindow]; 1188 1189 return self; 1190} 1191 1192-(void) colorListChanged:(NSNotification*)notif 1193{ 1194 if ([[notif object] isEqual: [NSColorList colorListNamed:@"System"]]) 1195 { 1196 [_wv setNeedsDisplay:YES]; 1197 } 1198} 1199 1200- (NSRect) contentRectForFrameRect: (NSRect)frameRect 1201{ 1202 return [_wv contentRectForFrameRect: frameRect styleMask: _styleMask]; 1203} 1204 1205- (NSRect) frameRectForContentRect: (NSRect)contentRect 1206{ 1207 return [_wv frameRectForContentRect: contentRect styleMask: _styleMask]; 1208} 1209 1210/* 1211 * Accessing the content view 1212 */ 1213- (id) contentView 1214{ 1215 return _contentView; 1216} 1217 1218/** 1219 Sets the window's content view to <var>aView</var>, replacing any 1220 previous content view. */ 1221- (void) setContentView: (NSView*)aView 1222{ 1223 if (aView == _contentView) 1224 return; 1225 1226 if (_contentView != nil) 1227 { 1228 [_contentView removeFromSuperview]; 1229 } 1230 _contentView = aView; 1231 1232 if (_contentView != nil) 1233 { 1234 [_wv setContentView: _contentView]; 1235 } 1236} 1237 1238/* 1239 * Window graphics 1240 */ 1241- (NSColor*) backgroundColor 1242{ 1243 return _backgroundColor; 1244} 1245 1246- (NSString*) representedFilename 1247{ 1248 return _representedFilename; 1249} 1250 1251- (void) setBackgroundColor: (NSColor*)color 1252{ 1253 ASSIGN(_backgroundColor, color); 1254 [_wv setBackgroundColor: color]; 1255} 1256 1257- (void) setRepresentedFilename: (NSString*)aString 1258{ 1259 ASSIGN(_representedFilename, aString); 1260} 1261 1262/** Sets the window's title to the string <var>aString</var>. */ 1263- (void) setTitle: (NSString*)aString 1264{ 1265 if ([_windowTitle isEqual: aString] == NO) 1266 { 1267 ASSIGNCOPY(_windowTitle, aString); 1268 [self setMiniwindowTitle: _windowTitle]; 1269 [_wv setTitle: _windowTitle]; 1270 if (_f.menu_exclude == NO && _f.has_opened == YES) 1271 { 1272 [NSApp changeWindowsItem: self 1273 title: _windowTitle 1274 filename: NO]; 1275 } 1276 } 1277} 1278 1279static NSString * 1280titleWithRepresentedFilename(NSString *representedFilename) 1281{ 1282 return [NSString stringWithFormat: @"%@ -- %@", 1283 [representedFilename lastPathComponent], 1284 [[representedFilename stringByDeletingLastPathComponent] 1285 stringByAbbreviatingWithTildeInPath]]; 1286} 1287 1288- (BOOL) _hasTitleWithRepresentedFilename 1289{ 1290 NSString *aString = titleWithRepresentedFilename (_representedFilename); 1291 return [_windowTitle isEqualToString: aString]; 1292} 1293 1294- (void) setTitleWithRepresentedFilename: (NSString*)aString 1295{ 1296 [self setRepresentedFilename: aString]; 1297 aString = titleWithRepresentedFilename(aString); 1298 if ([_windowTitle isEqual: aString] == NO) 1299 { 1300 ASSIGNCOPY(_windowTitle, aString); 1301 [self setMiniwindowTitle: _windowTitle]; 1302 [_wv setTitle: _windowTitle]; 1303 if (_f.menu_exclude == NO && _f.has_opened == YES) 1304 { 1305 [NSApp changeWindowsItem: self 1306 title: _windowTitle 1307 filename: YES]; 1308 } 1309 } 1310} 1311 1312- (NSUInteger) styleMask 1313{ 1314 return _styleMask; 1315} 1316 1317/** Returns an NSString containing the text of the window's title. */ 1318- (NSString*) title 1319{ 1320 return _windowTitle; 1321} 1322 1323- (void) setHasShadow: (BOOL)hasShadow 1324{ 1325 _f.has_shadow = hasShadow; 1326 if (_windowNum) 1327 { 1328 [GSServerForWindow(self) setShadow: hasShadow : _windowNum]; 1329 } 1330} 1331 1332- (BOOL) hasShadow 1333{ 1334 return _f.has_shadow; 1335} 1336 1337- (void) invalidateShadow 1338{ 1339// FIXME 1340} 1341 1342- (void) setAlphaValue: (CGFloat)windowAlpha 1343{ 1344 _alphaValue = windowAlpha; 1345 if (_windowNum) 1346 { 1347 [GSServerForWindow(self) setalpha: _alphaValue : _windowNum]; 1348 } 1349} 1350 1351- (CGFloat) alphaValue 1352{ 1353 return _alphaValue; 1354} 1355 1356- (void) setOpaque: (BOOL)isOpaque 1357{ 1358 // FIXME 1359 _f.is_opaque = isOpaque; 1360} 1361 1362- (BOOL) isOpaque 1363{ 1364 return _f.is_opaque; 1365} 1366 1367/* 1368 * Window device attributes 1369 */ 1370- (NSBackingStoreType) backingType 1371{ 1372 return _backingType; 1373} 1374 1375- (NSDictionary*) deviceDescription 1376{ 1377 return [[self screen] deviceDescription]; 1378} 1379 1380- (NSGraphicsContext*) graphicsContext 1381{ 1382 return _context; 1383} 1384 1385- (CGFloat) userSpaceScaleFactor 1386{ 1387 if (_styleMask & NSUnscaledWindowMask) 1388 { 1389 return 1.0; 1390 } 1391 else if (_screen != nil) 1392 { 1393 return [_screen userSpaceScaleFactor]; 1394 } 1395 else 1396 { 1397 return 1.0; 1398 } 1399} 1400 1401- (NSInteger) gState 1402{ 1403 if (_gstate <= 0) 1404 NSDebugLLog(@"NSWindow", @"gState called on deferred window"); 1405 return _gstate; 1406} 1407 1408- (BOOL) isOneShot 1409{ 1410 return _f.is_one_shot; 1411} 1412 1413- (void) setBackingType: (NSBackingStoreType)type 1414{ 1415 _backingType = type; 1416} 1417 1418- (void) setOneShot: (BOOL)flag 1419{ 1420 _f.is_one_shot = flag; 1421} 1422 1423- (NSInteger) windowNumber 1424{ 1425 if (_windowNum <= 0) 1426 NSDebugLLog(@"NSWindow", @"windowNumber called on deferred window"); 1427 return _windowNum; 1428} 1429 1430/* 1431 * The miniwindow 1432 */ 1433- (NSImage*) miniwindowImage 1434{ 1435 return _miniaturizedImage; 1436} 1437 1438- (NSString*) miniwindowTitle 1439{ 1440 return _miniaturizedTitle; 1441} 1442 1443- (void) setMiniwindowImage: (NSImage*)image 1444{ 1445 ASSIGN(_miniaturizedImage, image); 1446 if (_counterpart != 0 && (_styleMask & NSMiniWindowMask) == 0) 1447 { 1448 NSMiniWindow *mini; 1449 id v; 1450 1451 mini = (NSMiniWindow*)[NSApp windowWithWindowNumber: _counterpart]; 1452 v = [mini contentView]; 1453 if ([v respondsToSelector: @selector(setImage:)]) 1454 { 1455 [v setImage: [self miniwindowImage]]; 1456 } 1457 } 1458} 1459 1460- (void) setMiniwindowTitle: (NSString*)title 1461{ 1462 ASSIGN(_miniaturizedTitle, title); 1463 if (_counterpart != 0 && (_styleMask & NSMiniWindowMask) == 0) 1464 { 1465 NSMiniWindow *mini; 1466 id v; 1467 1468 mini = (NSMiniWindow*)[NSApp windowWithWindowNumber: _counterpart]; 1469 v = [mini contentView]; 1470 if ([v respondsToSelector: @selector(setTitle:)]) 1471 { 1472 [v setTitle: [self miniwindowTitle]]; 1473 } 1474 } 1475} 1476 1477- (NSWindow*) counterpart 1478{ 1479 if (_counterpart == 0) 1480 return nil; 1481 return [NSApp windowWithWindowNumber: _counterpart]; 1482} 1483 1484/* 1485 * The field editor 1486 */ 1487- (void) endEditingFor: (id)anObject 1488{ 1489 NSText *t = [self fieldEditor: NO 1490 forObject: anObject]; 1491 1492 if (t && (_firstResponder == t)) 1493 { 1494 // Change first responder first to avoid recusion. 1495 _firstResponder = self; 1496 [_firstResponder becomeFirstResponder]; 1497 [nc postNotificationName: NSTextDidEndEditingNotification 1498 object: t]; 1499 [t setText: @""]; 1500 [t setDelegate: nil]; 1501 [t removeFromSuperview]; 1502 } 1503} 1504 1505- (NSText*) fieldEditor: (BOOL)createFlag forObject: (id)anObject 1506{ 1507 /* ask delegate if it can provide a field editor */ 1508 if ((_delegate != anObject) 1509 && [_delegate respondsToSelector: 1510 @selector(windowWillReturnFieldEditor:toObject:)]) 1511 { 1512 NSText *editor; 1513 1514 editor = [_delegate windowWillReturnFieldEditor: self 1515 toObject: anObject]; 1516 1517 if (editor != nil) 1518 { 1519 return editor; 1520 } 1521 } 1522 /* 1523 * Each window has a global text field editor, if it doesn't exist create it 1524 * if create flag is set 1525 */ 1526 if (!_fieldEditor && createFlag) 1527 { 1528 _fieldEditor = [NSText new]; 1529 [_fieldEditor setFieldEditor: YES]; 1530 } 1531 1532 return _fieldEditor; 1533} 1534 1535/* 1536 * Window controller 1537 */ 1538- (void) setWindowController: (NSWindowController*)windowController 1539{ 1540 /* The window controller owns us, we only keep a weak reference to 1541 it */ 1542 _windowController = windowController; 1543} 1544 1545- (id) windowController 1546{ 1547 return _windowController; 1548} 1549 1550/* 1551 * Window status and ordering 1552 */ 1553- (void) becomeKeyWindow 1554{ 1555 if (_f.is_key == NO) 1556 { 1557 _f.is_key = YES; 1558 1559 if ((!_firstResponder) || (_firstResponder == self)) 1560 { 1561 if (!_initialFirstResponder) 1562 { 1563 [self recalculateKeyViewLoop]; 1564 } 1565 if (_initialFirstResponder) 1566 { 1567 [self makeFirstResponder: _initialFirstResponder]; 1568 } 1569 } 1570 1571 [_firstResponder becomeFirstResponder]; 1572 if ((_firstResponder != self) 1573 && [_firstResponder respondsToSelector: @selector(becomeKeyWindow)]) 1574 { 1575 [_firstResponder becomeKeyWindow]; 1576 } 1577 1578 [_wv setInputState: GSTitleBarKey]; 1579 [GSServerForWindow(self) setinputfocus: _windowNum]; 1580 [self resetCursorRects]; 1581 [nc postNotificationName: NSWindowDidBecomeKeyNotification object: self]; 1582 NSDebugLLog(@"NSWindow", @"%@ is now key window", [self title]); 1583 } 1584} 1585 1586- (void) becomeMainWindow 1587{ 1588 if (_f.is_main == NO) 1589 { 1590 _f.is_main = YES; 1591 if (_f.is_key == NO) 1592 { 1593 [_wv setInputState: GSTitleBarMain]; 1594 } 1595 [nc postNotificationName: NSWindowDidBecomeMainNotification object: self]; 1596 NSDebugLLog(@"NSWindow", @"%@ is now main window", [self title]); 1597 } 1598} 1599 1600/** Returns YES if the receiver can be made key. If this method returns 1601 NO, the window will not be made key. This implementation returns YES 1602 if the window is resizable or has a title bar. You can override this 1603 method to change it's behavior */ 1604- (BOOL) canBecomeKeyWindow 1605{ 1606 if ((NSResizableWindowMask | NSTitledWindowMask) & _styleMask) 1607 return YES; 1608 else 1609 return NO; 1610} 1611 1612/** Returns YES if the receiver can be the main window. If this method 1613 returns NO, the window will not become the main window. This 1614 implementation returns YES if the window is resizable or has a 1615 title bar and is visible and is not an NSPanel. You can override 1616 this method to change it's behavior */ 1617- (BOOL) canBecomeMainWindow 1618{ 1619 if (!_f.visible) 1620 return NO; 1621 if ((NSResizableWindowMask | NSTitledWindowMask) & _styleMask) 1622 return YES; 1623 else 1624 return NO; 1625} 1626 1627- (BOOL) hidesOnDeactivate 1628{ 1629 return _f.hides_on_deactivate; 1630} 1631 1632- (void) setCanHide: (BOOL)flag 1633{ 1634 _f.can_hide = flag; 1635} 1636 1637- (BOOL) canHide 1638{ 1639 return _f.can_hide; 1640} 1641 1642- (BOOL) isKeyWindow 1643{ 1644 return _f.is_key; 1645} 1646 1647- (BOOL) isMainWindow 1648{ 1649 return _f.is_main; 1650} 1651 1652- (BOOL) isMiniaturized 1653{ 1654 return _f.is_miniaturized; 1655} 1656 1657- (BOOL) isVisible 1658{ 1659 return _f.visible; 1660} 1661 1662- (NSInteger) level 1663{ 1664 return _windowLevel; 1665} 1666 1667- (void) makeKeyAndOrderFront: (id)sender 1668{ 1669 [self deminiaturize: self]; 1670 /* 1671 * If a window is ordered in, make sure that the application isn't hidden, 1672 * and is active. 1673 */ 1674 if ([self canBecomeKeyWindow]) 1675 [NSApp unhide: self]; 1676 [self orderFrontRegardless]; 1677 [self makeKeyWindow]; 1678 /* 1679 * OPENSTEP makes a window the main window when it makes it the key window. 1680 * So we do the same (though the documentation doesn't mention it). 1681 */ 1682 [self makeMainWindow]; 1683} 1684 1685- (void) makeKeyWindow 1686{ 1687 if (!_f.visible || _f.is_miniaturized || _f.is_key == YES) 1688 { 1689 return; 1690 } 1691 if (![self canBecomeKeyWindow]) 1692 return; 1693 [[NSApp keyWindow] resignKeyWindow]; 1694 1695 [self becomeKeyWindow]; 1696} 1697 1698- (void) makeMainWindow 1699{ 1700 if (!_f.visible || _f.is_miniaturized || _f.is_main == YES) 1701 { 1702 return; 1703 } 1704 if (![self canBecomeMainWindow]) 1705 return; 1706 [[NSApp mainWindow] resignMainWindow]; 1707 [self becomeMainWindow]; 1708} 1709 1710/** 1711 * Orders the window to the back of its level. Equivalent to 1712 * -orderWindow:relativeTo: with arguments NSWindowBelow and 0. 1713 */ 1714- (void) orderBack: (id)sender 1715{ 1716 [self orderWindow: NSWindowBelow relativeTo: 0]; 1717} 1718 1719/** 1720 * If the application is active, orders the window to the front in its 1721 * level. If the application is not active, the window is ordered in as 1722 * far forward as possible in its level without being ordered in front 1723 * of the key or main window of the currently active app. The current key 1724 * and main window status is not changed. Equivalent to 1725 * -orderWindow:relativeTo: with arguments NSWindowAbove and 0. 1726 */ 1727- (void) orderFront: (id)sender 1728{ 1729 [self orderWindow: NSWindowAbove relativeTo: 0]; 1730} 1731 1732/** 1733 Orders the window to the front in its level (even in front of the 1734 key and main windows of the current app) regardless of whether the 1735 app is current or not. This method should only be used in rare cases 1736 where the app is cooperating with another app that is displaying 1737 data for it. The current key and main window status is not changed. 1738*/ 1739- (void) orderFrontRegardless 1740{ 1741 [self orderWindow: NSWindowAbove relativeTo: -1]; 1742} 1743 1744/** 1745 * Orders the window out from the screen. Equivalent to 1746 * -orderWindow:relativeTo: with arguments NSWindowOut and 0. 1747 */ 1748- (void) orderOut: (id)sender 1749{ 1750 [self orderWindow: NSWindowOut relativeTo: 0]; 1751} 1752 1753/** 1754 <p> 1755 If place is NSWindowOut, removes the window from the screen. If 1756 place is NSWindowAbove, places the window directly above otherWin, 1757 or directly above all windows in its level if otherWin is 0. If 1758 place is NSWindowBelow, places the window directly below otherWin, 1759 or directly below all windows in its level if otherWin is 0. 1760 </p> 1761 <p>If otherWin is zero and the key window is at the same window level 1762 as the receiver, the receiver cannot be positioned above the key window. 1763 </p> 1764 <p> 1765 If place is NSWindowAbove or NSWindowBelow and the application is 1766 hidden, the application is unhidden. 1767 </p> 1768*/ 1769/* 1770 As a special undocumented case (for -orderFrontRegardless), if otherWin 1771 is minus one, then the backend should not try to keep the window below the 1772 current key/main window 1773*/ 1774- (void) orderWindow: (NSWindowOrderingMode)place relativeTo: (NSInteger)otherWin 1775{ 1776 GSDisplayServer *srv = GSServerForWindow(self); 1777 BOOL display = NO; 1778 1779 if (YES == [[NSUserDefaults standardUserDefaults] 1780 boolForKey: @"GSBackgroundApp"]) 1781 { 1782 return; 1783 } 1784 1785 if (place == NSWindowOut) 1786 { 1787 if (_windowNum == 0) 1788 { 1789 return; /* This deferred window was never ordered in. */ 1790 } 1791 _f.visible = NO; 1792 /* 1793 * Don't keep trying to update the window while it is ordered out 1794 */ 1795 [[self class] _removeAutodisplayedWindow: self]; 1796 [self _lossOfKeyOrMainWindow]; 1797 } 1798 else 1799 { 1800 /* Windows need to be constrained when displayed or resized - but only 1801 titled windows are constrained. Also, and this is the tricky part, 1802 don't constrain if we are merely unhiding the window or if it's 1803 already visible and is just being reordered. */ 1804 if ((_styleMask & NSTitledWindowMask) 1805 && [NSApp isHidden] == NO 1806 && _f.visible == NO) 1807 { 1808 NSRect nframe = [self constrainFrameRect: _frame 1809 toScreen: [self screen]]; 1810 [self setFrame: nframe display: NO]; 1811 } 1812 // create deferred window 1813 if (_windowNum == 0) 1814 { 1815 [self _initBackendWindow]; 1816 display = YES; 1817 } 1818 } 1819 1820 /* If a hide on deactivate window is explicitly ordered in or out while 1821 the application is not active, remove it from the list of inactive 1822 windows. */ 1823 if ([self hidesOnDeactivate] && ![NSApp isActive]) 1824 { 1825 [NSApp _setWindow: self inactive: NO]; 1826 } 1827 1828 // Draw content before backend window ordering 1829 if (display) 1830 [_wv display]; 1831 else if (place != NSWindowOut) 1832 [_wv displayIfNeeded]; 1833 1834 /* The backend will keep us below the current key window unless we 1835 force it not too */ 1836 if ((otherWin == 0 1837 || otherWin == [[NSApp keyWindow] windowNumber] 1838 || otherWin == [[NSApp mainWindow] windowNumber]) 1839 && [NSApp isActive]) 1840 otherWin = -1; 1841 1842 [srv orderwindow: place : otherWin : _windowNum]; 1843 if (display) 1844 [self display]; 1845 1846 if (place != NSWindowOut) 1847 { 1848 /* 1849 * Once we are ordered back in, we will want to update the window 1850 * whenever there is anything to do. 1851 */ 1852 [[self class] _addAutodisplayedWindow: self]; 1853 1854 if (_f.has_closed == YES) 1855 { 1856 _f.has_closed = NO; /* A closed window has re-opened */ 1857 } 1858 if (_f.has_opened == NO) 1859 { 1860 _f.has_opened = YES; 1861 if (_f.menu_exclude == NO) 1862 { 1863 [NSApp addWindowsItem: self 1864 title: _windowTitle 1865 filename: [self _hasTitleWithRepresentedFilename]]; 1866 } 1867 } 1868 if ([self isKeyWindow] == YES) 1869 { 1870 [_wv setInputState: GSTitleBarKey]; 1871 [srv setinputfocus: _windowNum]; 1872 } 1873 _f.visible = YES; 1874 } 1875 else if ([self isOneShot]) 1876 { 1877 [self _terminateBackendWindow]; 1878 } 1879} 1880 1881- (void) resignKeyWindow 1882{ 1883 if (_f.is_key == YES) 1884 { 1885 if ((_firstResponder != self) 1886 && [_firstResponder respondsToSelector: @selector(resignKeyWindow)]) 1887 [_firstResponder resignKeyWindow]; 1888 1889 _f.is_key = NO; 1890 1891 if (_f.is_main == YES) 1892 { 1893 [_wv setInputState: GSTitleBarMain]; 1894 } 1895 else 1896 { 1897 [_wv setInputState: GSTitleBarNormal]; 1898 } 1899 [self discardCursorRects]; 1900 1901 [nc postNotificationName: NSWindowDidResignKeyNotification object: self]; 1902 } 1903} 1904 1905- (void) resignMainWindow 1906{ 1907 if (_f.is_main == YES) 1908 { 1909 _f.is_main = NO; 1910 if (_f.is_key == YES) 1911 { 1912 [_wv setInputState: GSTitleBarKey]; 1913 } 1914 else 1915 { 1916 [_wv setInputState: GSTitleBarNormal]; 1917 } 1918 [nc postNotificationName: NSWindowDidResignMainNotification object: self]; 1919 } 1920} 1921 1922- (void) setHidesOnDeactivate: (BOOL)flag 1923{ 1924 if (flag != _f.hides_on_deactivate) 1925 { 1926 _f.hides_on_deactivate = flag; 1927 if (![NSApp isActive]) 1928 { 1929 if (flag) 1930 { 1931 if (_f.visible) 1932 { 1933 /* Order is important here. We must first order out the window 1934 and then add it to the inactive list, since -orderOut: 1935 removes the receiver from the inactive list. */ 1936 [self orderOut: nil]; 1937 [NSApp _setWindow: self inactive: YES]; 1938 } 1939 } 1940 else 1941 { 1942 if ([NSApp _isWindowInactive: self]) 1943 { 1944 [NSApp _setWindow: self inactive: NO]; 1945 [self orderFront: nil]; 1946 } 1947 } 1948 } 1949 } 1950} 1951 1952- (void) setLevel: (NSInteger)newLevel 1953{ 1954 if (_windowLevel != newLevel) 1955 { 1956 _windowLevel = newLevel; 1957 if (_windowNum > 0) 1958 { 1959 GSDisplayServer *srv = GSServerForWindow(self); 1960 [srv setwindowlevel: _windowLevel : _windowNum]; 1961 } 1962 } 1963} 1964 1965- (NSPoint) cascadeTopLeftFromPoint: (NSPoint)topLeftPoint 1966{ 1967 NSRect cRect; 1968 1969 if (NSEqualPoints(topLeftPoint, NSZeroPoint) == YES) 1970 { 1971 topLeftPoint.x = NSMinX(_frame); 1972 topLeftPoint.y = NSMaxY(_frame); 1973 } 1974 1975 [self setFrameTopLeftPoint: topLeftPoint]; 1976 cRect = [self contentRectForFrameRect: _frame]; 1977 topLeftPoint.x = NSMinX(cRect); 1978 topLeftPoint.y = NSMaxY(cRect); 1979 1980 /* make sure the new point is inside the screen */ 1981 if ([self screen]) 1982 { 1983 NSRect screenRect; 1984 1985 screenRect = [[self screen] visibleFrame]; 1986 if (topLeftPoint.x >= NSMaxX(screenRect)) 1987 { 1988 topLeftPoint.x = NSMinX(screenRect); 1989 } 1990 if (topLeftPoint.y <= NSMinY(screenRect)) 1991 { 1992 topLeftPoint.y = NSMaxY(screenRect); 1993 } 1994 } 1995 1996 return topLeftPoint; 1997} 1998 1999- (BOOL) showsResizeIndicator 2000{ 2001 // TODO 2002 NSLog(@"Method %s is not implemented for class %s", 2003 "showsResizeIndicator", "NSWindow"); 2004 return YES; 2005} 2006 2007- (void) setShowsResizeIndicator: (BOOL)show 2008{ 2009 // TODO 2010 NSLog(@"Method %s is not implemented for class %s", 2011 "setShowsResizeIndicator:", "NSWindow"); 2012} 2013 2014- (BOOL) preservesContentDuringLiveResize 2015{ 2016 return _f.preserves_content_during_live_resize; 2017} 2018 2019- (void) setPreservesContentDuringLiveResize: (BOOL)flag 2020{ 2021 _f.preserves_content_during_live_resize = flag; 2022} 2023 2024- (void) setFrame: (NSRect)frameRect 2025 display: (BOOL)displayFlag 2026 animate: (BOOL)animationFlag 2027{ 2028 if (animationFlag && !NSEqualRects(_frame, frameRect)) 2029 { 2030 // time that the resize is expected to take in seconds 2031 NSTimeInterval resizeTime; 2032 NSArray *animations; 2033 NSViewAnimation *viewAnimation; 2034 2035 resizeTime = [self animationResizeTime: frameRect]; 2036 animations = [NSArray arrayWithObject: 2037 [NSDictionary dictionaryWithObjectsAndKeys: 2038 self, NSViewAnimationTargetKey, 2039 [NSValue valueWithRect: frameRect], NSViewAnimationEndFrameKey, 2040 nil]]; 2041 viewAnimation = [[NSViewAnimation alloc] initWithViewAnimations: animations]; 2042 [viewAnimation setAnimationBlockingMode: NSAnimationNonblocking]; 2043 [viewAnimation setDuration: resizeTime]; 2044 if (animationDelegate == nil) 2045 { 2046 animationDelegate = [[GSWindowAnimationDelegate alloc] init]; 2047 } 2048 // The delegate handles the release of the viewAnimation 2049 [viewAnimation setDelegate: animationDelegate]; 2050 [viewAnimation startAnimation]; 2051 //AUTORELEASE(viewAnimation); 2052 } 2053 else 2054 { 2055 [self setFrame: frameRect display: displayFlag]; 2056 } 2057} 2058 2059- (NSTimeInterval) animationResizeTime: (NSRect)newFrame 2060{ 2061 static float resizeTime = 0; 2062 float maxDiff; 2063 2064 if (resizeTime == 0) 2065 { 2066 NSNumber *num; 2067 num = [[NSUserDefaults standardUserDefaults] 2068 objectForKey: @"NSWindowResizeTime"]; 2069 if (num != nil) 2070 { 2071 resizeTime = [num floatValue]; 2072 } 2073 else 2074 { 2075 resizeTime = 0.20; 2076 } 2077 } 2078 2079 // Find the biggest difference 2080 maxDiff = fabs(newFrame.origin.x - _frame.origin.x); 2081 maxDiff = MAX(maxDiff, fabs(newFrame.origin.y - _frame.origin.y)); 2082 maxDiff = MAX(maxDiff, fabs(newFrame.size.width - _frame.size.width)); 2083 maxDiff = MAX(maxDiff, fabs(newFrame.size.height - _frame.size.height)); 2084 2085 return (maxDiff * resizeTime) / 150; 2086} 2087 2088- (void) center 2089{ 2090 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; 2091 NSSize screenSize = screenFrame.size; 2092 NSPoint origin = screenFrame.origin; 2093 2094 origin.x += (screenSize.width - _frame.size.width) / 2; 2095 origin.y += (screenSize.height - _frame.size.height) / 2; 2096 2097 [self setFrameOrigin: origin]; 2098} 2099 2100/** 2101 * Given a proposed frame rectangle, return a modified version 2102 * which will fit inside the screen. 2103 */ 2104- (NSRect) constrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen 2105{ 2106 NSRect screenRect; 2107 CGFloat difference; 2108 2109 if (nil == screen) 2110 { 2111 return frameRect; 2112 } 2113 2114 screenRect = [screen visibleFrame]; 2115 2116 if (NSHeight(frameRect) < NSHeight(screenRect)) 2117 { 2118 /* Move top edge of the window inside the screen */ 2119 difference = NSMaxY (frameRect) - NSMaxY (screenRect); 2120 if (difference > 0) 2121 { 2122 frameRect.origin.y -= difference; 2123 } 2124 else 2125 { 2126 /* Move bottom edge of the window inside the screen */ 2127 difference = screenRect.origin.y - frameRect.origin.y; 2128 if (difference > 0) 2129 { 2130 frameRect.origin.y += difference; 2131 } 2132 } 2133 } 2134 else 2135 { 2136 /* If the window is resizable, resize it so that 2137 it fits on the screen. */ 2138 if (_styleMask & NSResizableWindowMask) 2139 { 2140 /* Ensure that resizing doesn't make window smaller than minimum */ 2141 if (_minimumSize.height < NSHeight(screenRect)) 2142 { 2143 frameRect.origin.y = NSMinY(screenRect); 2144 frameRect.size.height = NSHeight(screenRect); 2145 } 2146 else 2147 { 2148 frameRect.origin.y = NSMaxY(screenRect) - _minimumSize.height; 2149 frameRect.size.height = _minimumSize.height; 2150 } 2151 } 2152 else 2153 { 2154 /* Move top edge of the window to the screen limit */ 2155 frameRect.origin.y -= NSMaxY(frameRect) - NSMaxY(screenRect); 2156 } 2157 } 2158 2159 if (NSWidth(frameRect) < NSWidth(screenRect)) 2160 { 2161 /* Move right edge of the window inside the screen */ 2162 difference = NSMaxX (frameRect) - NSMaxX (screenRect); 2163 if (difference > 0) 2164 { 2165 frameRect.origin.x -= difference; 2166 } 2167 else 2168 { 2169 /* Move left edge of the window inside the screen */ 2170 difference = screenRect.origin.x - frameRect.origin.x; 2171 if (difference > 0) 2172 { 2173 frameRect.origin.x += difference; 2174 } 2175 } 2176 } 2177 else 2178 { 2179 /* If the window is resizable, resize it so that 2180 it fits on the screen. */ 2181 if (_styleMask & NSResizableWindowMask) 2182 { 2183 /* Ensure that resizing doesn't make window smaller than minimum */ 2184 if (_minimumSize.width < NSWidth(screenRect)) 2185 { 2186 frameRect.origin.x = NSMinX(screenRect); 2187 frameRect.size.width = NSWidth(screenRect); 2188 } 2189 else 2190 { 2191 frameRect.origin.x = NSMaxX(screenRect) - _minimumSize.width; 2192 frameRect.size.width = _minimumSize.width; 2193 } 2194 } 2195 else 2196 { 2197 /* Move right edge of the window to the screen limit */ 2198 frameRect.origin.x -= NSMaxX(frameRect) - NSMaxX(screenRect); 2199 } 2200 } 2201 2202 return frameRect; 2203} 2204 2205- (NSRect) frame 2206{ 2207 return _frame; 2208} 2209 2210- (NSSize) minSize 2211{ 2212 return _minimumSize; 2213} 2214 2215- (NSSize) maxSize 2216{ 2217 return _maximumSize; 2218} 2219 2220- (void) setContentSize: (NSSize)aSize 2221{ 2222 NSRect r = _frame; 2223 2224 r.size = aSize; 2225 r = [self frameRectForContentRect: r]; 2226 r.origin = _frame.origin; 2227 [self setFrame: r display: YES]; 2228} 2229 2230- (void) _applyFrame: (NSRect )frameRect 2231{ 2232 if (_windowNum) 2233 { 2234 [GSServerForWindow(self) placewindow: frameRect : _windowNum]; 2235 } 2236 else 2237 { 2238 _frame = frameRect; 2239 frameRect.origin = NSZeroPoint; 2240 [_wv setFrame: frameRect]; 2241 } 2242} 2243 2244- (void) setFrame: (NSRect)frameRect display: (BOOL)flag 2245{ 2246 if (_maximumSize.width > 0 && frameRect.size.width > _maximumSize.width) 2247 { 2248 frameRect.size.width = _maximumSize.width; 2249 } 2250 if (_maximumSize.height > 0 && frameRect.size.height > _maximumSize.height) 2251 { 2252 frameRect.size.height = _maximumSize.height; 2253 } 2254 if (frameRect.size.width < _minimumSize.width) 2255 { 2256 frameRect.size.width = _minimumSize.width; 2257 } 2258 if (frameRect.size.height < _minimumSize.height) 2259 { 2260 frameRect.size.height = _minimumSize.height; 2261 } 2262 2263 /* Windows need to be constrained when displayed or resized - but only 2264 titled windows are constrained */ 2265 if (_styleMask & NSTitledWindowMask) 2266 { 2267 frameRect = [self constrainFrameRect: frameRect 2268 toScreen: [self _screenForFrame: frameRect]]; 2269 } 2270 2271 // If nothing changes, don't send it to the backend and don't redisplay 2272 if (NSEqualRects(_frame, frameRect)) 2273 return; 2274 2275 if (NSEqualPoints(_frame.origin, frameRect.origin) == NO) 2276 [nc postNotificationName: NSWindowWillMoveNotification object: self]; 2277 2278 /* 2279 * Now we can tell the graphics context to do the actual resizing. 2280 * We will recieve an event to tell us when the resize is done. 2281 */ 2282 [self _applyFrame: frameRect]; 2283 2284 if (flag) 2285 [self display]; 2286} 2287 2288- (void) setFrameOrigin: (NSPoint)aPoint 2289{ 2290 NSRect r = _frame; 2291 2292 r.origin = aPoint; 2293 [self setFrame: r display: NO]; 2294} 2295 2296- (void) setFrameTopLeftPoint: (NSPoint)aPoint 2297{ 2298 NSRect r = _frame; 2299 2300 r.origin = aPoint; 2301 r.origin.y -= _frame.size.height; 2302 [self setFrame: r display: NO]; 2303} 2304 2305- (void) setMinSize: (NSSize)aSize 2306{ 2307 if (aSize.width < 1) 2308 aSize.width = 1; 2309 if (aSize.height < 1) 2310 aSize.height = 1; 2311 _minimumSize = aSize; 2312 if (_windowNum > 0) 2313 [GSServerForWindow(self) setminsize: aSize : _windowNum]; 2314} 2315 2316- (void) setMaxSize: (NSSize)aSize 2317{ 2318 /* 2319 * Documented maximum size for macOS-X - do we need this restriction? 2320 */ 2321 if (aSize.width > 10000) 2322 aSize.width = 10000; 2323 if (aSize.height > 10000) 2324 aSize.height = 10000; 2325 _maximumSize = aSize; 2326 if (_windowNum > 0) 2327 [GSServerForWindow(self) setmaxsize: aSize : _windowNum]; 2328} 2329 2330- (NSSize) resizeIncrements 2331{ 2332 return _increments; 2333} 2334 2335- (void) setResizeIncrements: (NSSize)aSize 2336{ 2337 _increments = aSize; 2338 if (_windowNum > 0) 2339 [GSServerForWindow(self) setresizeincrements: aSize : _windowNum]; 2340} 2341 2342- (NSSize) aspectRatio 2343{ 2344 // FIXME: This method is missing 2345 return NSMakeSize(1, 1); 2346} 2347 2348- (void) setAspectRatio: (NSSize)ratio 2349{ 2350 // FIXME: This method is missing 2351} 2352 2353- (NSSize) contentMaxSize 2354{ 2355// FIXME 2356 NSRect rect; 2357 2358 rect.origin = NSMakePoint(0, 0); 2359 rect.size = [self maxSize]; 2360 rect = [self contentRectForFrameRect: rect]; 2361 return rect.size; 2362} 2363 2364- (void) setContentMaxSize: (NSSize)size 2365{ 2366// FIXME 2367 NSRect rect; 2368 2369 rect.origin = NSMakePoint(0, 0); 2370 rect.size = size; 2371 rect = [self frameRectForContentRect: rect]; 2372 [self setMaxSize: rect.size]; 2373} 2374 2375- (NSSize) contentMinSize 2376{ 2377// FIXME 2378 NSRect rect; 2379 2380 rect.origin = NSMakePoint(0, 0); 2381 rect.size = [self minSize]; 2382 rect = [self contentRectForFrameRect: rect]; 2383 return rect.size; 2384} 2385 2386- (void) setContentMinSize: (NSSize)size 2387{ 2388// FIXME 2389 NSRect rect; 2390 2391 rect.origin = NSMakePoint(0, 0); 2392 rect.size = size; 2393 rect = [self frameRectForContentRect: rect]; 2394 [self setMinSize: rect.size]; 2395} 2396 2397- (NSSize) contentAspectRatio 2398{ 2399// FIXME 2400 return NSMakeSize(1, 1); 2401} 2402 2403- (void) setContentAspectRatio: (NSSize)ratio 2404{ 2405// FIXME 2406} 2407 2408- (NSSize) contentResizeIncrements 2409{ 2410// FIXME 2411 return [self resizeIncrements]; 2412} 2413 2414- (void) setContentResizeIncrements: (NSSize)increments 2415{ 2416// FIXME 2417 [self setResizeIncrements: increments]; 2418} 2419 2420/** 2421 * Convert from a point in the base coordinate system for the window 2422 * to a point in the screen coordinate system. 2423 */ 2424- (NSPoint) convertBaseToScreen: (NSPoint)aPoint 2425{ 2426 NSPoint screenPoint; 2427 2428 screenPoint.x = _frame.origin.x + aPoint.x; 2429 screenPoint.y = _frame.origin.y + aPoint.y; 2430 return screenPoint; 2431} 2432 2433/** 2434 * Convert from a point in the screen coordinate system to a point in the 2435 * screen coordinate system of the receiver. 2436 */ 2437- (NSPoint) convertScreenToBase: (NSPoint)aPoint 2438{ 2439 NSPoint basePoint; 2440 2441 basePoint.x = aPoint.x - _frame.origin.x; 2442 basePoint.y = aPoint.y - _frame.origin.y; 2443 return basePoint; 2444} 2445 2446/** 2447 * Converts aRect from the coordinate system of the screen 2448 * to the coordinate system of the window. 2449 */ 2450 2451- (NSRect) convertRectFromScreen: (NSRect)aRect 2452{ 2453 NSRect result = aRect; 2454 NSPoint origin = result.origin; 2455 NSPoint newOrigin = [self convertScreenToBase: origin]; 2456 result.origin = newOrigin; 2457 return result; 2458} 2459 2460/** 2461 * Converts aRect from the window coordinate system to a rect in 2462 * the screen coordinate system. 2463 */ 2464- (NSRect) convertRectToScreen: (NSRect)aRect 2465{ 2466 NSRect result = aRect; 2467 NSPoint origin = result.origin; 2468 NSPoint newOrigin = [self convertBaseToScreen: origin]; 2469 result.origin = newOrigin; 2470 return result; 2471} 2472 2473/* 2474 * Managing the display 2475 */ 2476- (void) disableFlushWindow 2477{ 2478 _disableFlushWindow++; 2479} 2480 2481- (void) display 2482{ 2483 if (_gstate == 0 || _f.visible == NO) 2484 return; 2485 2486 [_wv display]; 2487 [self discardCachedImage]; 2488 _f.views_need_display = NO; 2489} 2490 2491- (void) displayIfNeeded 2492{ 2493 if (_gstate == 0 || _f.visible == NO) 2494 return; 2495 2496 if (_f.views_need_display) 2497 { 2498 [_wv displayIfNeeded]; 2499 [self discardCachedImage]; 2500 _f.views_need_display = NO; 2501 } 2502} 2503 2504- (void) update 2505{ 2506 [nc postNotificationName: NSWindowDidUpdateNotification object: self]; 2507} 2508 2509- (void) flushWindowIfNeeded 2510{ 2511 if (_disableFlushWindow == 0 && _f.needs_flush == YES) 2512 { 2513 [self flushWindow]; 2514 } 2515} 2516 2517/** 2518 * Flush all drawing in the windows buffer to the screen unless the window 2519 * is not buffered or flushing is not enabled. 2520 */ 2521- (void) flushWindow 2522{ 2523 NSUInteger i; 2524 2525 /* 2526 * If flushWindow is called while flush is disabled 2527 * mark self as needing a flush, then return 2528 */ 2529 if (_disableFlushWindow) 2530 { 2531 _f.needs_flush = YES; 2532 return; 2533 } 2534 2535 /* 2536 * Just flush graphics if backing is not buffered. 2537 * The documentation actually says that this is wrong ... the method 2538 * should do nothing when the backingType is NSBackingStoreNonretained 2539 */ 2540 if (_backingType == NSBackingStoreNonretained) 2541 { 2542 [_context flushGraphics]; 2543 return; 2544 } 2545 2546 /* Check for special case of flushing while we are lock focused. 2547 For instance, when we are highlighting a button. */ 2548 if (NSIsEmptyRect(_rectNeedingFlush)) 2549 { 2550 if ([_rectsBeingDrawn count] == 0) 2551 { 2552 _f.needs_flush = NO; 2553 return; 2554 } 2555 } 2556 2557 /* 2558 * Accumulate the rectangles from all nested focus locks. 2559 */ 2560 i = [_rectsBeingDrawn count]; 2561 while (i-- > 0) 2562 { 2563 _rectNeedingFlush = NSUnionRect(_rectNeedingFlush, 2564 [[_rectsBeingDrawn objectAtIndex: i] rectValue]); 2565 } 2566 2567 if (_windowNum > 0) 2568 { 2569 [GSServerForWindow(self) flushwindowrect: _rectNeedingFlush 2570 : _windowNum]; 2571 } 2572 _f.needs_flush = NO; 2573 _rectNeedingFlush = NSZeroRect; 2574} 2575 2576- (void) enableFlushWindow 2577{ 2578 if (_disableFlushWindow > 0) 2579 { 2580 _disableFlushWindow--; 2581 } 2582} 2583 2584- (BOOL) isAutodisplay 2585{ 2586 return _f.is_autodisplay; 2587} 2588 2589- (BOOL) isFlushWindowDisabled 2590{ 2591 return _disableFlushWindow == 0 ? NO : YES; 2592} 2593 2594- (void) setAutodisplay: (BOOL)flag 2595{ 2596 _f.is_autodisplay = flag; 2597} 2598 2599- (void) setViewsNeedDisplay: (BOOL)flag 2600{ 2601 if (_f.views_need_display != flag) 2602 { 2603 _f.views_need_display = flag; 2604 if (flag) 2605 { 2606 /* TODO: this call most likely shouldn't be here */ 2607 [NSApp setWindowsNeedUpdate: YES]; 2608 } 2609 } 2610} 2611 2612- (BOOL) viewsNeedDisplay 2613{ 2614 return _f.views_need_display; 2615} 2616 2617- (void) cacheImageInRect: (NSRect)aRect 2618{ 2619 NSView *cacheView; 2620 NSRect cacheRect; 2621 2622 aRect = NSIntegralRect (NSIntersectionRect (aRect, [_wv frame])); 2623 _cachedImageOrigin = aRect.origin; 2624 DESTROY(_cachedImage); 2625 2626 if (NSIsEmptyRect (aRect)) 2627 { 2628 return; 2629 } 2630 2631 cacheRect.origin = NSZeroPoint; 2632 cacheRect.size = aRect.size; 2633 _cachedImage = [[NSCachedImageRep alloc] initWithWindow: nil 2634 rect: cacheRect]; 2635 cacheView = [[_cachedImage window] contentView]; 2636 [cacheView lockFocus]; 2637 NSCopyBits (_gstate, aRect, NSZeroPoint); 2638 [cacheView unlockFocus]; 2639} 2640 2641- (void) discardCachedImage 2642{ 2643 DESTROY(_cachedImage); 2644} 2645 2646- (void) restoreCachedImage 2647{ 2648 if (_cachedImage == nil) 2649 { 2650 return; 2651 } 2652 [_wv lockFocus]; 2653 NSCopyBits ([[_cachedImage window] gState], 2654 [_cachedImage rect], 2655 _cachedImageOrigin); 2656 [_wv unlockFocus]; 2657} 2658 2659- (void) useOptimizedDrawing: (BOOL)flag 2660{ 2661 _f.optimize_drawing = flag; 2662} 2663 2664- (BOOL) canStoreColor 2665{ 2666 if (NSNumberOfColorComponents(NSColorSpaceFromDepth(_depthLimit)) > 1) 2667 { 2668 return YES; 2669 } 2670 else 2671 { 2672 return NO; 2673 } 2674} 2675 2676/** Returns the screen the window is on. Unlike (apparently) OpenStep 2677 and MacOSX, GNUstep does not support windows being split across 2678 multiple screens */ 2679- (NSScreen *) deepestScreen 2680{ 2681 return [self screen]; 2682} 2683 2684- (NSWindowDepth) depthLimit 2685{ 2686 return _depthLimit; 2687} 2688 2689- (BOOL) hasDynamicDepthLimit 2690{ 2691 return _f.dynamic_depth_limit; 2692} 2693 2694/** Returns the screen the window is on. */ 2695- (NSScreen *) screen 2696{ 2697 // Only recompute the screen if the current screen 2698 // doesn't contain the whole window. 2699 // FIXME: Containing half the window would be enough 2700 if (_screen != nil) 2701 { 2702 NSRect sframe = [_screen frame]; 2703 if (NSContainsRect(sframe, _frame)) 2704 { 2705 return _screen; 2706 } 2707 } 2708 ASSIGN(_screen, [self _screenForFrame: _frame]); 2709 return _screen; 2710} 2711 2712- (void) applicationDidChangeScreenParameters: (NSNotification *)aNotif 2713{ 2714 NSRect oldScreenFrame = [_screen frame]; 2715 int screenNumber = [_screen screenNumber]; 2716 NSRect newScreenFrame; 2717 NSRect newFrame; 2718 NSEnumerator *e; 2719 NSScreen *scr; 2720 2721 // We need to get new screen from renewed screen list because 2722 // [NSScreen mainScreen] returns NSScreen object of key window and that object 2723 // will never be released. 2724 e = [[NSScreen screens] objectEnumerator]; 2725 while ((scr = [e nextObject])) 2726 { 2727 if ([scr screenNumber] == screenNumber) 2728 { 2729 ASSIGN(_screen, scr); 2730 break; 2731 } 2732 } 2733 2734 // Do not adjust frame for mini and appicon windows - it's a WM's job. 2735 if ([self isKindOfClass: [NSMiniWindow class]] || self == [NSApp iconWindow]) 2736 return; 2737 2738 newScreenFrame = [_screen frame]; 2739 2740 newFrame = _frame; 2741 // Screen Y origin change. 2742 newFrame.origin.y += newScreenFrame.origin.y - oldScreenFrame.origin.y; 2743 // Screen height change. 2744 newFrame.origin.y += newScreenFrame.size.height - oldScreenFrame.size.height; 2745 // Screen X origin change. Screen width change shouldn't affect our frame. 2746 newFrame.origin.x += newScreenFrame.origin.x - oldScreenFrame.origin.x; 2747 2748 /* Call backend's `placewindow::` directly because our origin in OpenStep 2749 coordinates might be unchanged and `setFrame:display:` has check 2750 for it. */ 2751 [self _applyFrame: newFrame]; 2752 [self display]; 2753 2754 if (_autosaveName != nil) 2755 { 2756 [self saveFrameUsingName: _autosaveName]; 2757 } 2758} 2759 2760- (void) setDepthLimit: (NSWindowDepth)limit 2761{ 2762 if (limit == 0) 2763 { 2764 limit = [[self class] defaultDepthLimit]; 2765 } 2766 2767 _depthLimit = limit; 2768} 2769 2770- (void) setDynamicDepthLimit: (BOOL)flag 2771{ 2772 _f.dynamic_depth_limit = flag; 2773} 2774 2775- (NSWindowCollectionBehavior)collectionBehavior 2776{ 2777 //TODO: we don't handle collections yet and perhaps never will fully 2778 return 0; 2779} 2780 2781- (void)setCollectionBehavior:(NSWindowCollectionBehavior)props 2782{ 2783 //TODO we don't handle collections yet. Perhaps certain features can be mapped on existing ones 2784 //other features are Expose specific or anyway probably not implementable 2785} 2786 2787/* 2788 * Cursor management 2789 */ 2790- (BOOL) areCursorRectsEnabled 2791{ 2792 return _f.cursor_rects_enabled; 2793} 2794 2795- (void) disableCursorRects 2796{ 2797 _f.cursor_rects_enabled = NO; 2798} 2799 2800static void 2801discardCursorRectsForView(NSView *theView) 2802{ 2803 if (theView != nil) 2804 { 2805 if (theView->_rFlags.has_currects) 2806 { 2807 [theView discardCursorRects]; 2808 } 2809 2810 if (theView->_rFlags.has_subviews) 2811 { 2812 NSArray *s = theView->_sub_views; 2813 NSUInteger count = [s count]; 2814 2815 if (count) 2816 { 2817 NSView *subs[count]; 2818 NSUInteger i; 2819 2820 [s getObjects: subs]; 2821 for (i = 0; i < count; i++) 2822 { 2823 discardCursorRectsForView(subs[i]); 2824 } 2825 } 2826 } 2827 } 2828} 2829 2830- (void) discardCursorRects 2831{ 2832 discardCursorRectsForView(_wv); 2833} 2834 2835- (void) enableCursorRects 2836{ 2837 _f.cursor_rects_enabled = YES; 2838} 2839 2840- (void) invalidateCursorRectsForView: (NSView*)aView 2841{ 2842 if (aView->_rFlags.valid_rects) 2843 { 2844 [aView discardCursorRects]; 2845 2846 if (_f.cursor_rects_valid) 2847 { 2848 if (_f.is_key && _f.cursor_rects_enabled) 2849 { 2850 NSEvent *e = [NSEvent otherEventWithType: NSAppKitDefined 2851 location: NSMakePoint(-1, -1) 2852 modifierFlags: 0 2853 timestamp: 0 2854 windowNumber: _windowNum 2855 context: GSCurrentContext() 2856 subtype: -1 2857 data1: 0 2858 data2: 0]; 2859 [self postEvent: e atStart: YES]; 2860 } 2861 _f.cursor_rects_valid = NO; 2862 } 2863 } 2864} 2865 2866static void 2867resetCursorRectsForView(NSView *theView) 2868{ 2869 if (theView != nil) 2870 { 2871 [theView resetCursorRects]; 2872 2873 if (theView->_rFlags.has_subviews) 2874 { 2875 NSArray *s = theView->_sub_views; 2876 NSUInteger count = [s count]; 2877 2878 if (count) 2879 { 2880 NSView *subs[count]; 2881 NSUInteger i; 2882 2883 [s getObjects: subs]; 2884 for (i = 0; i < count; i++) 2885 { 2886 resetCursorRectsForView(subs[i]); 2887 } 2888 } 2889 } 2890 } 2891} 2892 2893static void 2894checkCursorRectanglesEntered(NSView *theView, NSEvent *theEvent, NSPoint lastPoint) 2895{ 2896 2897 /* 2898 * Check cursor rectangles for the subviews 2899 */ 2900 if (theView->_rFlags.has_subviews) 2901 { 2902 NSArray *sb = theView->_sub_views; 2903 NSUInteger count = [sb count]; 2904 2905 if (count > 0) 2906 { 2907 NSView *subs[count]; 2908 NSUInteger i; 2909 2910 [sb getObjects: subs]; 2911 for (i = 0; i < count; ++i) 2912 { 2913 if (![subs[i] isHidden]) 2914 { 2915 checkCursorRectanglesEntered(subs[i], theEvent, lastPoint); 2916 } 2917 } 2918 } 2919 } 2920 2921 if (theView->_rFlags.valid_rects) 2922 { 2923 NSArray *tr = theView->_cursor_rects; 2924 NSUInteger count = [tr count]; 2925 2926 // Loop through cursor rectangles 2927 if (count > 0) 2928 { 2929 GSTrackingRect *rects[count]; 2930 NSPoint loc = [theEvent locationInWindow]; 2931 NSUInteger i; 2932 2933 [tr getObjects: rects]; 2934 2935 for (i = 0; i < count; ++i) 2936 { 2937 GSTrackingRect *r = rects[i]; 2938 BOOL last; 2939 BOOL now; 2940 2941 if ([r isValid] == NO) 2942 continue; 2943 2944 /* 2945 * Check for presence of point in rectangle. 2946 */ 2947 last = NSMouseInRect(lastPoint, r->rectangle, NO); 2948 now = NSMouseInRect(loc, r->rectangle, NO); 2949 2950 // Mouse entered 2951 if ((!last) && (now)) 2952 { 2953 NSEvent *e; 2954 2955 e = [NSEvent enterExitEventWithType: NSCursorUpdate 2956 location: loc 2957 modifierFlags: [theEvent modifierFlags] 2958 timestamp: 0 2959 windowNumber: [theEvent windowNumber] 2960 context: [theEvent context] 2961 eventNumber: 0 2962 trackingNumber: (int)YES 2963 userData: (void*)r]; 2964 [NSApp postEvent: e atStart: YES]; 2965 //NSLog(@"Add enter event %@ for view %@ rect %@", e, theView, NSStringFromRect(r->rectangle)); 2966 } 2967 } 2968 } 2969 } 2970} 2971 2972static void 2973checkCursorRectanglesExited(NSView *theView, NSEvent *theEvent, NSPoint lastPoint) 2974{ 2975 if (theView->_rFlags.valid_rects) 2976 { 2977 NSArray *tr = theView->_cursor_rects; 2978 NSUInteger count = [tr count]; 2979 2980 // Loop through cursor rectangles 2981 if (count > 0) 2982 { 2983 GSTrackingRect *rects[count]; 2984 NSPoint loc = [theEvent locationInWindow]; 2985 NSUInteger i; 2986 2987 [tr getObjects: rects]; 2988 2989 for (i = 0; i < count; ++i) 2990 { 2991 GSTrackingRect *r = rects[i]; 2992 BOOL last; 2993 BOOL now; 2994 2995 if ([r isValid] == NO) 2996 continue; 2997 2998 /* 2999 * Check for presence of point in rectangle. 3000 */ 3001 last = NSMouseInRect(lastPoint, r->rectangle, NO); 3002 now = NSMouseInRect(loc, r->rectangle, NO); 3003 3004 // Mouse exited 3005 if ((last) && (!now)) 3006 { 3007 NSEvent *e; 3008 3009 e = [NSEvent enterExitEventWithType: NSCursorUpdate 3010 location: loc 3011 modifierFlags: [theEvent modifierFlags] 3012 timestamp: 0 3013 windowNumber: [theEvent windowNumber] 3014 context: [theEvent context] 3015 eventNumber: 0 3016 trackingNumber: (int)NO 3017 userData: (void*)r]; 3018 [NSApp postEvent: e atStart: YES]; 3019 //[NSApp postEvent: e atStart: NO]; 3020 //NSLog(@"Add exit event %@ for view %@ rect %@", e, theView, NSStringFromRect(r->rectangle)); 3021 } 3022 } 3023 } 3024 } 3025 3026 /* 3027 * Check cursor rectangles for the subviews 3028 */ 3029 if (theView->_rFlags.has_subviews) 3030 { 3031 NSArray *sb = theView->_sub_views; 3032 NSUInteger count = [sb count]; 3033 3034 if (count > 0) 3035 { 3036 NSView *subs[count]; 3037 NSUInteger i; 3038 3039 [sb getObjects: subs]; 3040 for (i = 0; i < count; ++i) 3041 { 3042 if (![subs[i] isHidden]) 3043 { 3044 checkCursorRectanglesExited(subs[i], theEvent, lastPoint); 3045 } 3046 } 3047 } 3048 } 3049} 3050 3051- (void) resetCursorRects 3052{ 3053 [self discardCursorRects]; 3054 resetCursorRectsForView(_wv); 3055 _f.cursor_rects_valid = YES; 3056 3057 if (_f.is_key && _f.cursor_rects_enabled) 3058 { 3059 NSPoint loc = [self mouseLocationOutsideOfEventStream]; 3060 if (NSMouseInRect(loc, [_wv bounds], NO)) 3061 { 3062 NSEvent *e = [NSEvent mouseEventWithType: NSMouseMoved 3063 location: loc 3064 modifierFlags: 0 3065 timestamp: 0 3066 windowNumber: _windowNum 3067 context: GSCurrentContext() 3068 eventNumber: 0 3069 clickCount: 0 3070 pressure: 0]; 3071 _lastPoint = NSMakePoint(-1,-1); 3072 checkCursorRectanglesEntered(_wv, e, _lastPoint); 3073 _lastPoint = loc; 3074 } 3075 } 3076} 3077 3078/* 3079 * Handling user actions and events 3080 */ 3081- (void) close 3082{ 3083 if (_f.has_closed == NO) 3084 { 3085 CREATE_AUTORELEASE_POOL(pool); 3086 _f.has_closed = YES; 3087 3088 /* The NSWindowCloseNotification might result in us being 3089 deallocated. To make sure self stays valid as long as is 3090 necessary, we retain ourselves here and balance it with a 3091 release later (unless we're supposed to release ourselves when 3092 we close). 3093 */ 3094 if (!_f.is_released_when_closed) 3095 { 3096 RETAIN(self); 3097 } 3098 3099 [nc postNotificationName: NSWindowWillCloseNotification object: self]; 3100 _f.has_opened = NO; 3101 [NSApp removeWindowsItem: self]; 3102 [self orderOut: self]; 3103 3104 if (_f.is_miniaturized == YES) 3105 { 3106 NSWindow *mini = GSWindowWithNumber(_counterpart); 3107 GSRemoveIcon(mini); 3108 } 3109 3110 [pool drain]; 3111 RELEASE(self); 3112 } 3113} 3114 3115/* Private Method. Many X Window managers will just deminiaturize us without 3116 telling us to do it ourselves. Deal with it. 3117*/ 3118- (void) _didDeminiaturize: sender 3119{ 3120 if (_f.is_miniaturized == YES) 3121 { 3122 _f.is_miniaturized = NO; 3123 _f.visible = YES; 3124 if (self == [NSApp iconWindow]) 3125 { 3126 [self orderOut: self]; 3127 if ([NSApp isActive] == NO) 3128 { 3129 [NSApp activateIgnoringOtherApps: YES]; 3130 } 3131 if ([NSApp isHidden] == YES) 3132 { 3133 [NSApp unhide: self]; 3134 } 3135 } 3136 [nc postNotificationName: NSWindowDidDeminiaturizeNotification 3137 object: self]; 3138 } 3139} 3140 3141/** 3142 Causes the window to deminiaturize. Normally you would not call this 3143 method directly. A window is automatically deminiaturized by the 3144 user via a mouse click event. Does nothing it the window isn't 3145 miniaturized. */ 3146- (void) deminiaturize: sender 3147{ 3148 if (!_f.is_miniaturized) 3149 return; 3150 3151 /* At least with X-Windows, the counterpart is tied to us, so it will 3152 automatically be ordered out when we are deminiaturized */ 3153 if (_counterpart != 0) 3154 { 3155 NSWindow *mini = GSWindowWithNumber(_counterpart); 3156 3157 GSRemoveIcon(mini); 3158 [mini orderOut: self]; 3159 } 3160 3161 _f.is_miniaturized = NO; 3162 [self makeKeyAndOrderFront: self]; 3163 [self _didDeminiaturize: sender]; 3164} 3165 3166/** 3167 Returns YES, if the document has been changed. 3168*/ 3169- (BOOL) isDocumentEdited 3170{ 3171 return _f.is_edited; 3172} 3173 3174 3175/** 3176 Returns YES, if the window is released when it is closed. 3177*/ 3178- (BOOL) isReleasedWhenClosed 3179{ 3180 return _f.is_released_when_closed; 3181} 3182 3183/** 3184 Causes the window to miniaturize, that is the window is removed from 3185 the screen and it's counterpart (mini)window is displayed. Does 3186 nothing if the window can't be miniaturized (eg. because it's already 3187 miniaturized). */ 3188- (void) miniaturize: (id)sender 3189{ 3190 GSDisplayServer *srv = GSServerForWindow(self); 3191 NSSize iconSize = [GSCurrentServer() iconSize]; 3192 3193 if (_f.is_miniaturized || (_styleMask & NSMiniWindowMask)) 3194 { 3195 /* Can't miniaturize a miniwindow or a miniaturized window. 3196 */ 3197 return; 3198 } 3199 3200 if (self == [NSApp iconWindow]) 3201 { 3202 if (NO == [[NSUserDefaults standardUserDefaults] 3203 boolForKey: @"GSSuppressAppIcon"]) 3204 { 3205 return; 3206 } 3207 } 3208 else if ((!(_styleMask & (NSIconWindowMask | NSMiniaturizableWindowMask))) 3209 || (_styleMask & NSMiniWindowMask) 3210 || (![self isVisible])) 3211 { 3212 return; 3213 } 3214 3215 [nc postNotificationName: NSWindowWillMiniaturizeNotification 3216 object: self]; 3217 3218 _f.is_miniaturized = YES; 3219 /* Make sure we're not defered */ 3220 if (_windowNum == 0) 3221 { 3222 [self _initBackendWindow]; 3223 } 3224 /* 3225 * Ensure that we have a miniwindow counterpart. 3226 */ 3227 if (_counterpart == 0 && [srv appOwnsMiniwindow]) 3228 { 3229 NSWindow *mini; 3230 NSMiniWindowView *v; 3231 NSRect rect = NSMakeRect(0, 0, iconSize.height, iconSize.width); 3232 3233 mini = [[NSMiniWindow alloc] initWithContentRect: rect 3234 styleMask: NSMiniWindowMask 3235 backing: NSBackingStoreBuffered 3236 defer: NO]; 3237 mini->_counterpart = [self windowNumber]; 3238 _counterpart = [mini windowNumber]; 3239 v = [[NSMiniWindowView alloc] initWithFrame: rect]; 3240 [v setImage: [self miniwindowImage]]; 3241 [v setTitle: [self miniwindowTitle]]; 3242 [mini setContentView: v]; 3243 RELEASE(v); 3244 } 3245 [self _lossOfKeyOrMainWindow]; 3246 [srv miniwindow: _windowNum]; 3247 _f.visible = NO; 3248 3249 /* 3250 * We must order the miniwindow in so that we will start sending 3251 * it messages to tell it to display itsself when neccessary. 3252 */ 3253 if (_counterpart != 0) 3254 { 3255 NSRect iconRect; 3256 NSWindow *mini = GSWindowWithNumber(_counterpart); 3257 iconRect = GSGetIconFrame(mini); 3258 [mini setFrame: iconRect display: YES]; 3259 [mini orderFront: self]; 3260 } 3261 [nc postNotificationName: NSWindowDidMiniaturizeNotification 3262 object: self]; 3263} 3264 3265/** 3266 Causes the window to close. Calls the windowShouldClose: method 3267 on the delegate to determine if it should close and calls 3268 shouldCloseWindowController on the controller for the receiver. 3269*/ 3270- (void) performClose: (id)sender 3271{ 3272 /* Don't close if a modal session is running and we are not the 3273 modal window */ 3274 if ([NSApp modalWindow] && self != [NSApp modalWindow]) 3275 { 3276 /* Panel that work in modal session can be closed nevertheless */ 3277 if (![self worksWhenModal]) 3278 return; 3279 } 3280 3281 /* self must have a close button in order to be closed */ 3282 if (!(_styleMask & NSClosableWindowMask)) 3283 { 3284 NSBeep(); 3285 return; 3286 } 3287 3288 if (_windowController) 3289 { 3290 NSDocument *document = [_windowController document]; 3291 3292 if (document && ![document shouldCloseWindowController: _windowController]) 3293 { 3294 NSBeep(); 3295 return; 3296 } 3297 } 3298 if ([_delegate respondsToSelector: @selector(windowShouldClose:)]) 3299 { 3300 /* 3301 * if delegate responds to windowShouldClose query it to see if 3302 * it's ok to close the window 3303 */ 3304 if (![_delegate windowShouldClose: self]) 3305 { 3306 NSBeep(); 3307 return; 3308 } 3309 } 3310 else 3311 { 3312 /* 3313 * else if self responds to windowShouldClose query 3314 * self to see if it's ok to close self 3315 */ 3316 if ([self respondsToSelector: @selector(windowShouldClose:)]) 3317 { 3318 if (![self windowShouldClose: self]) 3319 { 3320 NSBeep(); 3321 return; 3322 } 3323 } 3324 } 3325 3326 // FIXME: The button should be highlighted 3327 [self close]; 3328} 3329 3330/** 3331 Performs the key equivalent represented by theEvent. 3332 */ 3333- (BOOL) performKeyEquivalent: (NSEvent*)theEvent 3334{ 3335 if (_contentView) 3336 return [_contentView performKeyEquivalent: theEvent]; 3337 return NO; 3338} 3339 3340/** 3341 * Miniaturize the receiver ... as long as its style mask includes 3342 * NSMiniaturizableWindowMask (and as long as the receiver is not an 3343 * icon or mini window itsself). Calls -miniaturize: to do this.<br /> 3344 * Beeps if the window can't be miniaturised.<br /> 3345 * Should ideally provide visual feedback (highlighting the miniaturize 3346 * button as if it had been clicked) first ... but that's not yet implemented. 3347 */ 3348- (void) performMiniaturize: (id)sender 3349{ 3350 if ((!(_styleMask & NSMiniaturizableWindowMask)) 3351 || (_styleMask & (NSIconWindowMask | NSMiniWindowMask))) 3352 { 3353 NSBeep(); 3354 return; 3355 } 3356 3357 // FIXME: The button should be highlighted 3358 [self miniaturize: sender]; 3359} 3360 3361+ (NSButton *) standardWindowButton: (NSWindowButton)button 3362 forStyleMask: (NSUInteger) mask 3363{ 3364 return [[GSTheme theme] standardWindowButton: button 3365 forStyleMask: mask]; 3366} 3367 3368- (NSButton *) standardWindowButton: (NSWindowButton)button 3369{ 3370 return [_wv viewWithTag: button]; 3371} 3372 3373- (BOOL) showsToolbarButton 3374{ 3375 return _f.shows_toolbar_button; 3376} 3377 3378- (void) setShowsToolbarButton: (BOOL)flag 3379{ 3380 _f.shows_toolbar_button = flag; 3381} 3382 3383- (NSInteger) resizeFlags 3384{ 3385 // FIXME: The implementation is missing 3386 return 0; 3387} 3388 3389/** 3390 Set document edit status. If YES, then, if the receiver has a close 3391 button, the close button will show a broken X. If NO, then, if the reciever 3392 has a close button, the close button will show a solid X. 3393 */ 3394- (void) setDocumentEdited: (BOOL)flag 3395{ 3396 if (_f.is_edited != flag) 3397 { 3398 _f.is_edited = flag; 3399 if (_f.menu_exclude == NO && _f.has_opened == YES) 3400 { 3401 [NSApp updateWindowsItem: self]; 3402 } 3403 [_wv setDocumentEdited: flag]; 3404 } 3405} 3406 3407/** 3408 Get an undo manager from the delegate or create one. 3409 */ 3410- (NSUndoManager*) undoManager 3411{ 3412 NSUndoManager *undo = nil; 3413 3414 if ([_delegate respondsToSelector: @selector(windowWillReturnUndoManager:)]) 3415 { 3416 undo = [_delegate windowWillReturnUndoManager: self]; 3417 } 3418 else if (_windowController) 3419 { 3420 NSDocument *document = [_windowController document]; 3421 3422 if (document) 3423 undo = [document undoManager]; 3424 } 3425 3426 if (undo == nil) 3427 { 3428 if (windowUndoManagers == NULL) 3429 windowUndoManagers = 3430 NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, 3431 NSObjectMapValueCallBacks, 0); 3432 else 3433 undo = NSMapGet(windowUndoManagers, self); 3434 3435 if (undo == nil) 3436 { 3437 undo = [[NSUndoManager alloc] init]; 3438 NSMapInsertKnownAbsent(windowUndoManagers, self, undo); 3439 [undo release]; 3440 } 3441 } 3442 return undo; 3443} 3444 3445- (void) undo: (id)sender 3446{ 3447 [[_firstResponder undoManager] undo]; 3448} 3449 3450- (void) redo: (id)sender 3451{ 3452 [[_firstResponder undoManager] redo]; 3453} 3454 3455/** 3456 If YES, then the window is released when the close method is called. 3457 */ 3458- (void) setReleasedWhenClosed: (BOOL)flag 3459{ 3460 _f.is_released_when_closed = flag; 3461} 3462 3463/* 3464 * Aiding event handling 3465 */ 3466- (BOOL) acceptsMouseMovedEvents 3467{ 3468 return _f.accepts_mouse_moved; 3469} 3470 3471- (void) setAcceptsMouseMovedEvents: (BOOL)flag 3472{ 3473 _f.accepts_mouse_moved = flag; 3474} 3475 3476- (BOOL) ignoresMouseEvents 3477{ 3478 return _f.ignores_mouse_events; 3479} 3480 3481- (void) setIgnoresMouseEvents: (BOOL)flag 3482{ 3483 _f.ignores_mouse_events = flag; 3484 [GSServerForWindow(self) setIgnoreMouse: flag : _windowNum]; 3485} 3486 3487- (NSEvent*) currentEvent 3488{ 3489 return [NSApp currentEvent]; 3490} 3491 3492- (void) discardEventsMatchingMask: (NSUInteger)mask 3493 beforeEvent: (NSEvent*)lastEvent 3494{ 3495 [NSApp discardEventsMatchingMask: mask beforeEvent: lastEvent]; 3496} 3497 3498/** 3499 Returns the first responder of the window. 3500 */ 3501- (NSResponder*) firstResponder 3502{ 3503 return _firstResponder; 3504} 3505 3506/** 3507 Returns YES, if the window can accept first responder. The default 3508 implementation of this method returns YES. 3509 */ 3510- (BOOL) acceptsFirstResponder 3511{ 3512 return YES; 3513} 3514 3515/** 3516 Makes aResponder the first responder within the receiver. 3517 */ 3518- (BOOL) makeFirstResponder: (NSResponder*)aResponder 3519{ 3520 if (_firstResponder == aResponder) 3521 return YES; 3522 3523 if (aResponder != nil) 3524 { 3525 if (![aResponder isKindOfClass: responderClass]) 3526 return NO; 3527 3528 if (![aResponder acceptsFirstResponder]) 3529 { 3530 return NO; 3531 } 3532 } 3533 3534 /* So that the implementation of -resignFirstResponder in 3535 _firstResponder might ask for what will be the new first 3536 responder by calling our method _futureFirstResponder */ 3537 _futureFirstResponder = aResponder; 3538 3539 /* 3540 * If there is a first responder tell it to resign. 3541 * Change only if it replies YES. 3542 */ 3543 if ((_firstResponder) && (![_firstResponder resignFirstResponder])) 3544 { 3545 return NO; 3546 } 3547 3548 _firstResponder = aResponder; 3549 if ((aResponder == nil) || ![_firstResponder becomeFirstResponder]) 3550 { 3551 _firstResponder = self; 3552 [_firstResponder becomeFirstResponder]; 3553 return (aResponder == nil); 3554 } 3555 3556 return YES; 3557} 3558 3559/** 3560 Sets the initial first responder of the receiver. 3561 */ 3562- (void) setInitialFirstResponder: (NSView*)aView 3563{ 3564 if ([aView isKindOfClass: viewClass]) 3565 { 3566 ASSIGN(_initialFirstResponder, aView); 3567 } 3568} 3569 3570/** 3571 returns the initial first responder of the receiver. 3572 */ 3573- (NSView*) initialFirstResponder 3574{ 3575 return _initialFirstResponder; 3576} 3577 3578/** 3579 Processes theEvent when a key is pressed while within 3580 the window. 3581 */ 3582- (void) keyDown: (NSEvent*)theEvent 3583{ 3584 NSString *characters = [theEvent characters]; 3585 unichar character = 0; 3586 3587 if ([characters length] > 0) 3588 { 3589 character = [characters characterAtIndex: 0]; 3590 } 3591 3592 if (character == NSHelpFunctionKey) 3593 { 3594 [NSHelpManager setContextHelpModeActive: YES]; 3595 return; 3596 } 3597 3598 // If this is a BACKTAB event, move to the previous key view 3599 if (character == NSBackTabCharacter) 3600 { 3601 [self selectPreviousKeyView: self]; 3602 return; 3603 } 3604 3605 // If this is a TAB or TAB+SHIFT event, move to the next key view 3606 if (character == NSTabCharacter) 3607 { 3608 if ([theEvent modifierFlags] & NSShiftKeyMask) 3609 [self selectPreviousKeyView: self]; 3610 else 3611 [self selectNextKeyView: self]; 3612 return; 3613 } 3614 3615 // If this is an ESC event, abort modal loop 3616 if (character == 0x001b) 3617 { 3618 if ([NSApp modalWindow] == self) 3619 { 3620 // NB: The following *never* returns. 3621 [NSApp abortModal]; 3622 } 3623 return; 3624 } 3625 3626 if (character == NSEnterCharacter 3627 || character == NSFormFeedCharacter 3628 || character == NSCarriageReturnCharacter) 3629 { 3630 if (_defaultButtonCell && _f.default_button_cell_key_disabled == NO) 3631 { 3632 [_defaultButtonCell performClick: self]; 3633 return; 3634 } 3635 } 3636 3637 // Discard null character events such as a Shift event after a tab key 3638 if ([characters length] == 0) 3639 return; 3640 3641 // FIXME: Why is this here, is the code still needed or a left over hack? 3642 // Try to process the event as a key equivalent 3643 // without Command having being pressed 3644 { 3645 NSEvent *new_event 3646 = [NSEvent keyEventWithType: [theEvent type] 3647 location: NSZeroPoint 3648 modifierFlags: ([theEvent modifierFlags] | NSCommandKeyMask) 3649 timestamp: [theEvent timestamp] 3650 windowNumber: [theEvent windowNumber] 3651 context: [theEvent context] 3652 characters: characters 3653 charactersIgnoringModifiers: [theEvent 3654 charactersIgnoringModifiers] 3655 isARepeat: [theEvent isARepeat] 3656 keyCode: [theEvent keyCode]]; 3657 if ([self performKeyEquivalent: new_event]) 3658 return; 3659 } 3660 3661 // Otherwise, pass the event up 3662 [super keyDown: theEvent]; 3663} 3664 3665- (void) keyUp: (NSEvent*)theEvent 3666{ 3667 if ([NSHelpManager isContextHelpModeActive]) 3668 { 3669 NSString *characters = [theEvent characters]; 3670 unichar character = 0; 3671 3672 if ([characters length] > 0) 3673 { 3674 character = [characters characterAtIndex: 0]; 3675 } 3676 if (character == NSHelpFunctionKey) 3677 { 3678 [NSHelpManager setContextHelpModeActive: NO]; 3679 return; 3680 } 3681 } 3682 3683 [super keyUp: theEvent]; 3684} 3685 3686/* Return mouse location in reciever's base coord system, ignores event 3687 * loop status */ 3688- (NSPoint) mouseLocationOutsideOfEventStream 3689{ 3690 int screen; 3691 NSPoint p; 3692 3693 screen = [_screen screenNumber]; 3694 p = [GSServerForWindow(self) mouseLocationOnScreen: screen window: NULL]; 3695 if (p.x != -1) 3696 p = [self convertScreenToBase: p]; 3697 return p; 3698} 3699 3700- (NSEvent*) nextEventMatchingMask: (NSUInteger)mask 3701{ 3702 return [NSApp nextEventMatchingMask: mask 3703 untilDate: [NSDate distantFuture] 3704 inMode: NSEventTrackingRunLoopMode 3705 dequeue: YES]; 3706} 3707 3708- (NSEvent*) nextEventMatchingMask: (NSUInteger)mask 3709 untilDate: (NSDate*)expiration 3710 inMode: (NSString*)mode 3711 dequeue: (BOOL)deqFlag 3712{ 3713 return [NSApp nextEventMatchingMask: mask 3714 untilDate: expiration 3715 inMode: mode 3716 dequeue: deqFlag]; 3717} 3718 3719- (void) postEvent: (NSEvent*)event atStart: (BOOL)flag 3720{ 3721 [NSApp postEvent: event atStart: flag]; 3722} 3723 3724- (void) _checkTrackingRectangles: (NSView*)theView 3725 forEvent: (NSEvent*)theEvent 3726{ 3727 if (theView == nil) 3728 return; 3729 if (theView->_rFlags.has_trkrects) 3730 { 3731 BOOL isFlipped = [theView isFlipped]; 3732 NSArray *tr = theView->_tracking_rects; 3733 NSUInteger count = [tr count]; 3734 3735 /* 3736 * Loop through the tracking rectangles 3737 */ 3738 if (count > 0) 3739 { 3740 GSTrackingRect *rects[count]; 3741 NSPoint loc = [theEvent locationInWindow]; 3742 NSPoint lastPoint = _lastPoint; 3743 NSRect vr = [theView visibleRect]; 3744 NSUInteger i; 3745 3746 lastPoint = [theView convertPoint: lastPoint fromView: nil]; 3747 loc = [theView convertPoint: loc fromView: nil]; 3748 [tr getObjects: rects]; 3749 3750 for (i = 0; i < count; ++i) 3751 { 3752 BOOL last; 3753 BOOL now; 3754 GSTrackingRect *r = rects[i]; 3755 NSRect tr = NSIntersectionRect(vr, r->rectangle); 3756 3757 if ([r isValid] == NO) 3758 continue; 3759 /* Check mouse at last point */ 3760 last = NSMouseInRect(lastPoint, tr, isFlipped); 3761 /* Check mouse at current point */ 3762 now = NSMouseInRect(loc, tr, isFlipped); 3763 3764 if ((!last) && (now)) // Mouse entered event 3765 { 3766 if (r->flags.checked == NO) 3767 { 3768 if ([r->owner respondsToSelector: 3769 @selector(mouseEntered:)]) 3770 r->flags.ownerRespondsToMouseEntered = YES; 3771 if ([r->owner respondsToSelector: 3772 @selector(mouseExited:)]) 3773 r->flags.ownerRespondsToMouseExited = YES; 3774 r->flags.checked = YES; 3775 } 3776 if (r->flags.ownerRespondsToMouseEntered) 3777 { 3778 NSEvent *e; 3779 3780 e = [NSEvent enterExitEventWithType: NSMouseEntered 3781 location: loc 3782 modifierFlags: [theEvent modifierFlags] 3783 timestamp: 0 3784 windowNumber: [theEvent windowNumber] 3785 context: NULL 3786 eventNumber: 0 3787 trackingNumber: r->tag 3788 userData: r->user_data]; 3789 [r->owner mouseEntered: e]; 3790 } 3791 } 3792 3793 if ((last) && (!now)) // Mouse exited event 3794 { 3795 if (r->flags.checked == NO) 3796 { 3797 if ([r->owner respondsToSelector: 3798 @selector(mouseEntered:)]) 3799 r->flags.ownerRespondsToMouseEntered = YES; 3800 if ([r->owner respondsToSelector: 3801 @selector(mouseExited:)]) 3802 r->flags.ownerRespondsToMouseExited = YES; 3803 r->flags.checked = YES; 3804 } 3805 if (r->flags.ownerRespondsToMouseExited) 3806 { 3807 NSEvent *e; 3808 3809 e = [NSEvent enterExitEventWithType: NSMouseExited 3810 location: loc 3811 modifierFlags: [theEvent modifierFlags] 3812 timestamp: 0 3813 windowNumber: [theEvent windowNumber] 3814 context: NULL 3815 eventNumber: 0 3816 trackingNumber: r->tag 3817 userData: r->user_data]; 3818 [r->owner mouseExited: e]; 3819 } 3820 } 3821 } 3822 } 3823 } 3824 3825 /* 3826 * Check tracking rectangles for the subviews 3827 */ 3828 if (theView->_rFlags.has_subviews) 3829 { 3830 NSArray *sb = theView->_sub_views; 3831 NSUInteger count = [sb count]; 3832 3833 if (count > 0) 3834 { 3835 NSView *subs[count]; 3836 NSUInteger i; 3837 3838 [sb getObjects: subs]; 3839 for (i = 0; i < count; ++i) 3840 { 3841 if (![subs[i] isHidden]) 3842 (*ctImp)(self, ctSel, subs[i], theEvent); 3843 } 3844 } 3845 } 3846} 3847 3848- (void) _checkCursorRectangles: (NSView*)theView forEvent: (NSEvent*)theEvent 3849{ 3850 // As we add the events to the front of the queue, we need to add the last 3851 // events first. That is, first the enter evnts from inner to outer and 3852 // then the exit events 3853 checkCursorRectanglesEntered(theView, theEvent, _lastPoint); 3854 checkCursorRectanglesExited(theView, theEvent, _lastPoint); 3855 //[GSServerForWindow(self) _printEventQueue]; 3856} 3857 3858- (void) _processResizeEvent 3859{ 3860 if (_windowNum && _gstate) 3861 { 3862 [GSServerForWindow(self) setWindowdevice: _windowNum 3863 forContext: _context]; 3864 GSReplaceGState(_context, _gstate); 3865 } 3866 3867 [self update]; 3868} 3869 3870- (void) mouseDown: (NSEvent*)theEvent 3871{ 3872 // Quietly discard an unused mouse down. 3873} 3874 3875- (BOOL) becomesKeyOnlyIfNeeded 3876{ 3877 return NO; 3878} 3879 3880/** Handles mouse and other events sent to the receiver by NSApplication. 3881 Do not invoke this method directly. 3882*/ 3883- (void) sendEvent: (NSEvent*)theEvent 3884{ 3885 NSView *v; 3886 NSEventType type; 3887 3888 /* 3889 If the backend reacts slowly, events (eg. mouse down) might arrive for a 3890 window that has been ordered out (and thus is logically invisible). We 3891 need to ignore those events. Otherwise, eg. clicking twice on a button 3892 that ends a modal session and closes the window with the button might 3893 cause the button to be pressed twice, which causes Bad Things to happen 3894 when it tries to stop a modal session twice. 3895 3896 We let NSAppKitDefined events through since they deal with window ordering. 3897 */ 3898 if (!_f.visible && [theEvent type] != NSAppKitDefined) 3899 { 3900 NSDebugLLog(@"NSEvent", @"Discard (window not visible) %@", theEvent); 3901 return; 3902 } 3903 3904 if (!_f.cursor_rects_valid) 3905 { 3906 [self resetCursorRects]; 3907 } 3908 3909 type = [theEvent type]; 3910 if ([self ignoresMouseEvents] 3911 && GSMouseEventMask == NSEventMaskFromType(type)) 3912 { 3913 NSDebugLLog(@"NSEvent", @"Discard (window ignoring mouse) %@", theEvent); 3914 return; 3915 } 3916 3917 switch (type) 3918 { 3919 case NSLeftMouseDown: 3920 { 3921 BOOL wasKey = _f.is_key; 3922 3923 if (_f.has_closed == NO) 3924 { 3925 v = [_wv hitTest: [theEvent locationInWindow]]; 3926 if (_f.is_key == NO && _windowLevel != NSDesktopWindowLevel) 3927 { 3928 /* NSPanel modification: check becomesKeyOnlyIfNeeded. */ 3929 if (![self becomesKeyOnlyIfNeeded] 3930 || [v needsPanelToBecomeKey]) 3931 { 3932 v = nil; 3933 [self makeKeyAndOrderFront: self]; 3934 } 3935 } 3936 /* Activate the app *after* making the receiver key, as app 3937 activation tries to make the previous key window key. 3938 However, don't activate the app after a single click into 3939 the app icon or a miniwindow. This allows dragging app 3940 icons and miniwindows without unnecessarily switching 3941 applications (cf. Sect. 4 of the OpenStep UI Guidelines). 3942 */ 3943 if ((_styleMask & (NSIconWindowMask | NSMiniWindowMask)) == 0 3944 && [NSApp isActive] == NO) 3945 { 3946 v = nil; 3947 [NSApp activateIgnoringOtherApps: YES]; 3948 } 3949 // Activating the app may change the window layout. 3950 if (v == nil) 3951 { 3952 v = [_wv hitTest: [theEvent locationInWindow]]; 3953 } 3954 if (_lastLeftMouseDownView) 3955 { 3956 DESTROY(_lastLeftMouseDownView); 3957 } 3958 // Don't make buttons first responder otherwise they cannot 3959 // send actions to the current first responder. 3960 // TODO: First responder status update would more cleanly 3961 // handled by -mouseDown in each control subclass (Mac OS X 3962 // seems to do that). 3963 if (_firstResponder != v && ![v isKindOfClass: [NSButton class]]) 3964 { 3965 // Only try to set first responder, when the view wants it. 3966 if ([v acceptsFirstResponder] && ![self makeFirstResponder: v]) 3967 { 3968 return; 3969 } 3970 } 3971 if (wasKey == YES || [v acceptsFirstMouse: theEvent] == YES) 3972 { 3973 if ([NSHelpManager isContextHelpModeActive]) 3974 { 3975 [v helpRequested: theEvent]; 3976 } 3977 else 3978 { 3979 ASSIGN(_lastLeftMouseDownView, v); 3980 if (toolTipVisible != nil) 3981 { 3982 /* Inform the tooltips system that we have had 3983 * a mouse down so it should stop displaying. 3984 */ 3985 [toolTipVisible mouseDown: theEvent]; 3986 } 3987 [v mouseDown: theEvent]; 3988 } 3989 } 3990 else 3991 { 3992 [self mouseDown: theEvent]; 3993 } 3994 } 3995 else 3996 { 3997 NSDebugLLog(@"NSEvent", @"Discard (window closed) %@", theEvent); 3998 } 3999 _lastPoint = [theEvent locationInWindow]; 4000 break; 4001 } 4002 4003 case NSLeftMouseUp: 4004 v = AUTORELEASE(RETAIN(_lastLeftMouseDownView)); 4005 DESTROY(_lastLeftMouseDownView); 4006 if (v == nil) 4007 break; 4008 [v mouseUp: theEvent]; 4009 _lastPoint = [theEvent locationInWindow]; 4010 break; 4011 4012 case NSOtherMouseDown: 4013 v = [_wv hitTest: [theEvent locationInWindow]]; 4014 ASSIGN(_lastOtherMouseDownView, v); 4015 [v otherMouseDown: theEvent]; 4016 _lastPoint = [theEvent locationInWindow]; 4017 break; 4018 4019 case NSOtherMouseUp: 4020 v = AUTORELEASE(RETAIN(_lastOtherMouseDownView)); 4021 DESTROY(_lastOtherMouseDownView); 4022 if (v == nil) 4023 break; 4024 [v otherMouseUp: theEvent]; 4025 _lastPoint = [theEvent locationInWindow]; 4026 break; 4027 4028 case NSRightMouseDown: 4029 v = [_wv hitTest: [theEvent locationInWindow]]; 4030 ASSIGN(_lastRightMouseDownView, v); 4031 [v rightMouseDown: theEvent]; 4032 _lastPoint = [theEvent locationInWindow]; 4033 break; 4034 4035 case NSRightMouseUp: 4036 v = AUTORELEASE(RETAIN(_lastRightMouseDownView)); 4037 DESTROY(_lastRightMouseDownView); 4038 if (v == nil) 4039 break; 4040 [v rightMouseUp: theEvent]; 4041 _lastPoint = [theEvent locationInWindow]; 4042 break; 4043 4044 case NSLeftMouseDragged: 4045 case NSOtherMouseDragged: 4046 case NSRightMouseDragged: 4047 case NSMouseMoved: 4048 switch (type) 4049 { 4050 case NSLeftMouseDragged: 4051 [_lastLeftMouseDownView mouseDragged: theEvent]; 4052 break; 4053 case NSOtherMouseDragged: 4054 [_lastOtherMouseDownView otherMouseDragged: theEvent]; 4055 break; 4056 case NSRightMouseDragged: 4057 [_lastRightMouseDownView rightMouseDragged: theEvent]; 4058 break; 4059 default: 4060 if (_f.accepts_mouse_moved) 4061 { 4062 /* 4063 * If the window is set to accept mouse movements, we need to 4064 * forward the mouse movement to the correct view. 4065 */ 4066 v = [_wv hitTest: [theEvent locationInWindow]]; 4067 4068 /* If the view is displaying a tooltip, we should 4069 * send mouse movements to the tooltip system so 4070 * that the window can track the mouse. 4071 */ 4072 if (toolTipVisible != nil) 4073 { 4074 [toolTipVisible mouseMoved: theEvent]; 4075 } 4076 else 4077 { 4078 [v mouseMoved: theEvent]; 4079 } 4080 } 4081 break; 4082 } 4083 4084 /* 4085 * We need to go through all of the views, and if there is any with 4086 * a tracking rectangle then we need to determine if we should send 4087 * a NSMouseEntered or NSMouseExited event. 4088 */ 4089 (*ctImp)(self, ctSel, _wv, theEvent); 4090 4091 if (_f.is_key) 4092 { 4093 /* 4094 * We need to go through all of the views, and if there is any with 4095 * a cursor rectangle then we need to determine if we should send a 4096 * cursor update event. 4097 */ 4098 if (_f.cursor_rects_enabled) 4099 { 4100 (*ccImp)(self, ccSel, _wv, theEvent); 4101 } 4102 } 4103 4104 _lastPoint = [theEvent locationInWindow]; 4105 break; 4106 4107 case NSMouseEntered: 4108 case NSMouseExited: 4109 break; 4110 4111 case NSKeyDown: 4112 /* Always shift keyboard focus to the next and previous key view, 4113 * respectively, upon receiving Ctrl-Tab and Ctrl-Shift-Tab keyboard 4114 * events. This means that the key view loop won't get stuck in views 4115 * that interpret the Tab key differently, e.g., NSTextView. (cf. the 4116 * Keyboard Interface Control section in Apple's Cocoa Event-Handling 4117 * Guide). 4118 */ 4119 if (([theEvent modifierFlags] & NSControlKeyMask) 4120 && [[theEvent charactersIgnoringModifiers] isEqualToString: @"\t"]) 4121 { 4122 if ([theEvent modifierFlags] & NSShiftKeyMask) 4123 [self selectPreviousKeyView: self]; 4124 else 4125 [self selectNextKeyView: self]; 4126 } 4127 else 4128 [_firstResponder keyDown: theEvent]; 4129 break; 4130 4131 case NSKeyUp: 4132 [_firstResponder keyUp: theEvent]; 4133 break; 4134 4135 case NSFlagsChanged: 4136 [_firstResponder flagsChanged: theEvent]; 4137 break; 4138 4139 case NSCursorUpdate: 4140 { 4141 GSTrackingRect *r =(GSTrackingRect*)[theEvent userData]; 4142 NSCursor *c = (NSCursor*)[r owner]; 4143 4144 // Don't update the cursor if the window isn't the key window. 4145 if (!_f.is_key) 4146 { 4147 break; 4148 } 4149 4150 if ([theEvent trackingNumber]) // It's a mouse entered 4151 { 4152 /* Only send the event mouse entered if the 4153 * cursor rectangle is valid. */ 4154 if ([r isValid]) 4155 { 4156 [c mouseEntered: theEvent]; 4157 4158 /* This could seems redundant, but ensure the correct 4159 * value to use in events mouse moved. And avoids strange 4160 * issues with cursor. */ 4161 _lastPoint = [theEvent locationInWindow]; 4162 } 4163 } 4164 else // it is a mouse exited 4165 { 4166 [c mouseExited: theEvent]; 4167 } 4168 } 4169 break; 4170 4171 case NSScrollWheel: 4172 v = [_wv hitTest: [theEvent locationInWindow]]; 4173 [v scrollWheel: theEvent]; 4174 break; 4175 4176 case NSAppKitDefined: 4177 { 4178 id dragInfo; 4179 int action; 4180 NSEvent *e; 4181 GSAppKitSubtype sub = [theEvent subtype]; 4182 4183 switch (sub) 4184 { 4185 case GSAppKitWindowMoved: 4186 { 4187 NSScreen *oldScreen = _screen; 4188 4189 _frame.origin.x = (CGFloat)[theEvent data1]; 4190 _frame.origin.y = (CGFloat)[theEvent data2]; 4191 NSDebugLLog(@"Moving", @"Move event: %d %@", 4192 (int)_windowNum, NSStringFromPoint(_frame.origin)); 4193 if (_autosaveName != nil) 4194 { 4195 [self saveFrameUsingName: _autosaveName]; 4196 } 4197 [nc postNotificationName: NSWindowDidMoveNotification 4198 object: self]; 4199 if ([self screen] != oldScreen) 4200 { 4201 [nc postNotificationName: NSWindowDidChangeScreenNotification 4202 object: self]; 4203 } 4204 } 4205 break; 4206 4207 case GSAppKitWindowResized: 4208 { 4209 NSRect newFrame; 4210 4211 newFrame.size.width = [theEvent data1]; 4212 newFrame.size.height = [theEvent data2]; 4213 /* Resize events always move the frame origin. The new origin 4214 is stored in the event location field. */ 4215 newFrame.origin = [theEvent locationInWindow]; 4216 4217 /* FIXME: For a user resize we should call windowWillResize:toSize: 4218 on the delegate. 4219 */ 4220 _frame = newFrame; 4221 newFrame.origin = NSZeroPoint; 4222 [_wv setFrame: newFrame]; 4223 [_wv setNeedsDisplay: YES]; 4224 4225 if (_autosaveName != nil) 4226 { 4227 [self saveFrameUsingName: _autosaveName]; 4228 } 4229 4230 [self _processResizeEvent]; 4231 [nc postNotificationName: NSWindowDidResizeNotification 4232 object: self]; 4233 break; 4234 } 4235 4236 case GSAppKitRegionExposed: 4237 { 4238 NSRect region; 4239 4240 region.size.width = [theEvent data1]; 4241 region.size.height = [theEvent data2]; 4242 region.origin = [theEvent locationInWindow]; 4243 switch (_backingType) 4244 { 4245 case NSBackingStoreBuffered: 4246 case NSBackingStoreRetained: 4247 /* 4248 * The backend may have the region buffered ... 4249 * so we add it to the rectangle to be flushed 4250 * and set the flag to say that a flush is required. 4251 */ 4252 _rectNeedingFlush 4253 = NSUnionRect(_rectNeedingFlush, region); 4254 _f.needs_flush = YES; 4255 /* Some or all of the window has not been drawn, 4256 * so we must at least make sure that the exposed 4257 * region gets drawn before its backing store is 4258 * flushed ... otherwise we might actually flush 4259 * bogus data from an out of date buffer. 4260 * Maybe we should call 4261 * [_wv displayIfNeededInRect: region] 4262 * but why not do all drawing at this point so 4263 * that if we get another expose event immediately 4264 * (eg. something is dragged over the window and 4265 * we get a series of expose events) we can just 4266 * flush without having to draw again. 4267 */ 4268 [self displayIfNeeded]; 4269 [self flushWindowIfNeeded]; 4270 break; 4271 4272 default: 4273 /* non-retained ... so we need to redraw the exposed 4274 * region here. 4275 */ 4276 [_wv setNeedsDisplayInRect: region]; 4277 break; 4278 } 4279 } 4280 break; 4281 4282 case GSAppKitWindowClose: 4283 [self performClose: NSApp]; 4284 break; 4285 4286 case GSAppKitWindowDeminiaturize: 4287 [self _didDeminiaturize: NSApp]; 4288 break; 4289 4290 case GSAppKitWindowMiniaturize: 4291 [self performMiniaturize: NSApp]; 4292 break; 4293 4294 case GSAppKitAppHide: 4295 [NSApp hide: self]; 4296 break; 4297 4298 case GSAppKitWindowFocusIn: 4299 if (_f.is_miniaturized) 4300 { 4301 /* Window Manager just deminiaturized us */ 4302 [self deminiaturize: self]; 4303 } 4304 if ([NSApp modalWindow] 4305 && self != [NSApp modalWindow] 4306 && ![self worksWhenModal]) 4307 { 4308 /* Ignore this request. We're in a modal loop and the 4309 user pressed on the title bar of another window. */ 4310 break; 4311 } 4312 if ([self canBecomeKeyWindow] == YES) 4313 { 4314 NSDebugLLog(@"Focus", @"Making %d key", (int)_windowNum); 4315 [self makeKeyWindow]; 4316 [self makeMainWindow]; 4317 [NSApp activateIgnoringOtherApps: YES]; 4318 } 4319 if (self == [[NSApp mainMenu] window]) 4320 { 4321 /* We should really find another window that can become 4322 key (if possible) 4323 */ 4324 [self _lossOfKeyOrMainWindow]; 4325 } 4326 break; 4327 4328 case GSAppKitWindowFocusOut: 4329 break; 4330 4331 case GSAppKitWindowLeave: 4332 /* we ignore this event for a window that is already closed */ 4333 if (_f.has_closed == YES) 4334 break; 4335 4336 /* 4337 * We need to go through all of the views, and if there 4338 * is any with a tracking rectangle then we need to 4339 * determine if we should send a NSMouseExited event. */ 4340 (*ctImp)(self, ctSel, _wv, theEvent); 4341 4342 if (_f.is_key) 4343 { 4344 /* 4345 * We need to go through all of the views, and if 4346 * there is any with a cursor rectangle then we need 4347 * to determine if we should send a cursor update 4348 * event. */ 4349 if (_f.cursor_rects_enabled) 4350 { 4351 checkCursorRectanglesExited(_wv, theEvent, _lastPoint); 4352 } 4353 } 4354 4355 _lastPoint = NSMakePoint(-1, -1); 4356 break; 4357 4358 case GSAppKitWindowEnter: 4359 break; 4360 4361 4362#define GSPerformDragSelector(view, sel, info, action) \ 4363 if ([view window] == self) \ 4364 { \ 4365 id target = view; \ 4366 \ 4367 if (target == _wv) \ 4368 { \ 4369 if (_delegate != nil \ 4370 && [_delegate respondsToSelector: sel] == YES) \ 4371 { \ 4372 target = _delegate; \ 4373 } \ 4374 else \ 4375 { \ 4376 target = self; \ 4377 } \ 4378 } \ 4379 \ 4380 if ([target respondsToSelector: sel]) \ 4381 { \ 4382 action = (intptr_t)[target performSelector: sel \ 4383 withObject: info]; \ 4384 } \ 4385 } 4386 4387#define GSPerformVoidDragSelector(view, sel, info) \ 4388 if ([view window] == self) \ 4389 { \ 4390 id target = view; \ 4391 \ 4392 if (target == _wv) \ 4393 { \ 4394 if (_delegate != nil \ 4395 && [_delegate respondsToSelector: sel] == YES) \ 4396 { \ 4397 target = _delegate; \ 4398 } \ 4399 else \ 4400 { \ 4401 target = self; \ 4402 } \ 4403 } \ 4404 \ 4405 if ([target respondsToSelector: sel]) \ 4406 { \ 4407 [target performSelector: sel withObject: info]; \ 4408 } \ 4409 } 4410 4411 case GSAppKitDraggingEnter: 4412 case GSAppKitDraggingUpdate: 4413 { 4414 BOOL isEntry; 4415 4416 dragInfo = [GSServerForWindow(self) dragInfo]; 4417 v = [_wv hitTest: [theEvent locationInWindow]]; 4418 4419 while (v != nil) 4420 { 4421 if (v->_rFlags.has_draginfo != 0 4422 && GSViewAcceptsDrag(v, dragInfo)) 4423 break; 4424 v = [v superview]; 4425 } 4426 if (v == nil) 4427 { 4428 v = _wv; 4429 } 4430 if (_lastDragView == v) 4431 { 4432 isEntry = NO; 4433 } 4434 else 4435 { 4436 isEntry = YES; 4437 if (_lastDragView != nil && _f.accepts_drag) 4438 { 4439 NSDebugLLog(@"NSDragging", @"Dragging exit"); 4440 GSPerformVoidDragSelector(_lastDragView, 4441 @selector(draggingExited:), dragInfo); 4442 } 4443 ASSIGN(_lastDragView, v); 4444 _f.accepts_drag = GSViewAcceptsDrag(v, dragInfo); 4445 } 4446 if (_f.accepts_drag) 4447 { 4448 if (isEntry == YES) 4449 { 4450 action = NSDragOperationNone; 4451 NSDebugLLog(@"NSDragging", @"Dragging entered"); 4452 GSPerformDragSelector(v, @selector(draggingEntered:), 4453 dragInfo, action); 4454 } 4455 else 4456 { 4457 action = _lastDragOperationMask; 4458 NSDebugLLog(@"NSDragging", @"Dragging updated"); 4459 GSPerformDragSelector(v, @selector(draggingUpdated:), 4460 dragInfo, action); 4461 } 4462 } 4463 else 4464 { 4465 action = NSDragOperationNone; 4466 } 4467 4468 e = [NSEvent otherEventWithType: NSAppKitDefined 4469 location: [theEvent locationInWindow] 4470 modifierFlags: 0 4471 timestamp: 0 4472 windowNumber: _windowNum 4473 context: GSCurrentContext() 4474 subtype: GSAppKitDraggingStatus 4475 data1: [theEvent data1] 4476 data2: action]; 4477 4478 _lastDragOperationMask = action; 4479 [dragInfo postDragEvent: e]; 4480 break; 4481 } 4482 4483 case GSAppKitDraggingStatus: 4484 NSDebugLLog(@"NSDragging", 4485 @"Internal: dropped GSAppKitDraggingStatus event"); 4486 break; 4487 4488 case GSAppKitDraggingExit: 4489 NSDebugLLog(@"NSDragging", @"GSAppKitDraggingExit"); 4490 dragInfo = [GSServerForWindow(self) dragInfo]; 4491 if (_lastDragView && _f.accepts_drag) 4492 { 4493 NSDebugLLog(@"NSDragging", @"Dragging exit"); 4494 GSPerformVoidDragSelector(_lastDragView, 4495 @selector(draggingExited:), dragInfo); 4496 } 4497 _lastDragOperationMask = NSDragOperationNone; 4498 DESTROY(_lastDragView); 4499 break; 4500 4501 case GSAppKitDraggingDrop: 4502 NSDebugLLog(@"NSDragging", @"GSAppKitDraggingDrop"); 4503 dragInfo = [GSServerForWindow(self) dragInfo]; 4504 if (_lastDragView && _f.accepts_drag 4505 && _lastDragOperationMask != NSDragOperationNone) 4506 { 4507 action = YES; 4508 GSPerformDragSelector(_lastDragView, 4509 @selector(prepareForDragOperation:), dragInfo, action); 4510 if (action) 4511 { 4512 action = NO; 4513 GSPerformDragSelector(_lastDragView, 4514 @selector(performDragOperation:), dragInfo, action); 4515 } 4516 if (action) 4517 { 4518 GSPerformVoidDragSelector(_lastDragView, 4519 @selector(concludeDragOperation:), dragInfo); 4520 } 4521 } 4522 _lastDragOperationMask = NSDragOperationNone; 4523 DESTROY(_lastDragView); 4524 e = [NSEvent otherEventWithType: NSAppKitDefined 4525 location: [theEvent locationInWindow] 4526 modifierFlags: 0 4527 timestamp: 0 4528 windowNumber: _windowNum 4529 context: GSCurrentContext() 4530 subtype: GSAppKitDraggingFinished 4531 data1: [theEvent data1] 4532 data2: 0]; 4533 [dragInfo postDragEvent: e]; 4534 break; 4535 4536 case GSAppKitDraggingFinished: 4537 _lastDragOperationMask = NSDragOperationNone; 4538 DESTROY(_lastDragView); 4539 NSDebugLLog(@"NSDragging", 4540 @"Internal: dropped GSAppKitDraggingFinished event"); 4541 break; 4542 4543 default: 4544 break; 4545 } 4546 } 4547 break; 4548 4549 case NSPeriodic: 4550 case NSSystemDefined: 4551 case NSApplicationDefined: 4552 break; 4553 4554 case NSTabletPoint: 4555 case NSTabletProximity: 4556 // FIXME: Tablet events 4557 break; 4558 } 4559} 4560 4561- (BOOL) shouldBeTreatedAsInkEvent: (NSEvent *)theEvent 4562{ 4563 NSView *v; 4564 4565 v = [_wv hitTest: [theEvent locationInWindow]]; 4566 if (![self isMainWindow]) 4567 { 4568 return (v != _wv); 4569 } 4570 else 4571 { 4572 return [v shouldBeTreatedAsInkEvent: theEvent]; 4573 } 4574} 4575 4576- (BOOL) tryToPerform: (SEL)anAction with: (id)anObject 4577{ 4578 if ([super tryToPerform: anAction with: anObject]) 4579 return YES; 4580 else if (_delegate && [_delegate respondsToSelector: anAction]) 4581 { 4582 [_delegate performSelector: anAction withObject: anObject]; 4583 return YES; 4584 } 4585 else 4586 return NO; 4587} 4588 4589- (BOOL) worksWhenModal 4590{ 4591 return NO; 4592} 4593 4594/** If aView responds to -nextValidKeyView with a new NSView, call 4595 -makeFirstResponder: for the returned view. 4596*/ 4597- (void) selectKeyViewFollowingView: (NSView*)aView 4598{ 4599 NSView *theView = nil; 4600 4601 if ([aView isKindOfClass: viewClass]) 4602 theView = [aView nextValidKeyView]; 4603 if (theView) 4604 { 4605 if (![self makeFirstResponder: theView]) 4606 { 4607 return; 4608 } 4609 if ([theView respondsToSelector:@selector(selectText:)]) 4610 { 4611 _f.selectionDirection = NSSelectingNext; 4612 [(id)theView selectText: self]; 4613 _f.selectionDirection = NSDirectSelection; 4614 } 4615 } 4616} 4617 4618/** If aView responds to -previousValidKeyView with a new NSView, call 4619 -makeFirstResponder: for this view. 4620*/ 4621- (void) selectKeyViewPrecedingView: (NSView*)aView 4622{ 4623 NSView *theView = nil; 4624 4625 if ([aView isKindOfClass: viewClass]) 4626 theView = [aView previousValidKeyView]; 4627 if (theView) 4628 { 4629 if (![self makeFirstResponder: theView]) 4630 { 4631 return; 4632 } 4633 if ([theView respondsToSelector:@selector(selectText:)]) 4634 { 4635 _f.selectionDirection = NSSelectingPrevious; 4636 [(id)theView selectText: self]; 4637 _f.selectionDirection = NSDirectSelection; 4638 } 4639 } 4640} 4641 4642/** This method checks if: 4643 <list> 4644 <item>_firstResponder answers to -nextValidKeyView</item> 4645 <item>_initialFirstResponder answers to -acceptsFirstResponder</item> 4646 <item>_initialFirstResponder answers to -previousValidKeyView</item> 4647 </list> 4648 If any of these checks return a NSView, call -makeFirstResponder: on 4649 this NSView. 4650*/ 4651- (void) selectNextKeyView: (id)sender 4652{ 4653 NSView *theView = nil; 4654 4655 if ([_firstResponder isKindOfClass: viewClass]) 4656 theView = [_firstResponder nextValidKeyView]; 4657 4658 if ((theView == nil) && (_initialFirstResponder)) 4659 { 4660 if ([_initialFirstResponder acceptsFirstResponder]) 4661 theView = _initialFirstResponder; 4662 else 4663 theView = [_initialFirstResponder nextValidKeyView]; 4664 } 4665 4666 if (theView) 4667 { 4668 if (![self makeFirstResponder: theView]) 4669 { 4670 return; 4671 } 4672 if ([theView respondsToSelector:@selector(selectText:)]) 4673 { 4674 _f.selectionDirection = NSSelectingNext; 4675 [(id)theView selectText: self]; 4676 _f.selectionDirection = NSDirectSelection; 4677 } 4678 } 4679} 4680 4681/** This method checks if: 4682 <list> 4683 <item>_firstResponder answers to -previousValidKeyView</item> 4684 <item>_initialFirstResponder answers to -acceptsFirstResponder</item> 4685 <item>_initialFirstResponder answers to -previousValidKeyView</item> 4686 </list> 4687 If any of these checks return a NSView, call -makeFirstResponder: on 4688 this NSView. 4689*/ 4690- (void) selectPreviousKeyView: (id)sender 4691{ 4692 NSView *theView = nil; 4693 4694 if ([_firstResponder isKindOfClass: viewClass]) 4695 theView = [_firstResponder previousValidKeyView]; 4696 4697 if ((theView == nil) && (_initialFirstResponder)) 4698 { 4699 if ([_initialFirstResponder acceptsFirstResponder]) 4700 theView = _initialFirstResponder; 4701 else 4702 theView = [_initialFirstResponder previousValidKeyView]; 4703 } 4704 4705 if (theView) 4706 { 4707 if (![self makeFirstResponder: theView]) 4708 { 4709 return; 4710 } 4711 if ([theView respondsToSelector:@selector(selectText:)]) 4712 { 4713 _f.selectionDirection = NSSelectingPrevious; 4714 [(id)theView selectText: self]; 4715 _f.selectionDirection = NSDirectSelection; 4716 } 4717 } 4718} 4719 4720// This is invoked by selectText: of some views (eg matrixes), 4721// to know whether they have received it from the window, and 4722// if so, in which direction is the selection moving (so that they know 4723// if they should select the last or the first editable cell). 4724/** Returns the value of _selectionDirection, the direction of the 4725current key view.<br /> 4726 See Also: 4727 <list> 4728 <item>-selectKeyViewFollowingView:</item> 4729 <item>-selectKeyViewPrecedingView:</item> 4730 <item>-selectNextKeyView:</item> 4731 <item>-selectPreviousKeyView:</item> 4732 </list> 4733*/ 4734- (NSSelectionDirection) keyViewSelectionDirection 4735{ 4736 return _f.selectionDirection; 4737} 4738 4739- (BOOL) autorecalculatesKeyViewLoop 4740{ 4741 return _f.autorecalculates_keyview_loop; 4742} 4743 4744- (void) setAutorecalculatesKeyViewLoop: (BOOL)flag 4745{ 4746 _f.autorecalculates_keyview_loop = flag; 4747} 4748 4749- (void) recalculateKeyViewLoop 4750{ 4751// Should be called from NSView viewWillMoveToWindow (but only if 4752// -autorecalculatesKeyViewLoop returns YES) 4753 [_contentView _setUpKeyViewLoopWithNextKeyView: _contentView]; 4754 [self setInitialFirstResponder: [_contentView nextValidKeyView]]; 4755} 4756 4757 4758/* 4759 * Dragging 4760 */ 4761- (void) dragImage: (NSImage*)anImage 4762 at: (NSPoint)baseLocation 4763 offset: (NSSize)initialOffset 4764 event: (NSEvent*)event 4765 pasteboard: (NSPasteboard*)pboard 4766 source: (id)sourceObject 4767 slideBack: (BOOL)slideFlag 4768{ 4769 id dragView = [GSServerForWindow(self) dragInfo]; 4770 4771 [NSApp preventWindowOrdering]; 4772 [dragView dragImage: anImage 4773 at: [self convertBaseToScreen: baseLocation] 4774 offset: initialOffset 4775 event: event 4776 pasteboard: pboard 4777 source: sourceObject 4778 slideBack: slideFlag]; 4779} 4780 4781- (void) registerForDraggedTypes: (NSArray*)newTypes 4782{ 4783 [_wv registerForDraggedTypes: newTypes]; 4784} 4785 4786- (void) unregisterDraggedTypes 4787{ 4788 [_wv unregisterDraggedTypes]; 4789} 4790 4791/* 4792 * Services and windows menu support 4793 */ 4794- (BOOL) isExcludedFromWindowsMenu 4795{ 4796 return _f.menu_exclude; 4797} 4798 4799- (void) setExcludedFromWindowsMenu: (BOOL)flag 4800{ 4801 if (_f.menu_exclude != flag) 4802 { 4803 _f.menu_exclude = flag; 4804 if (flag == YES) 4805 { 4806 [NSApp removeWindowsItem: self]; 4807 } 4808 else if (_f.has_opened == YES && flag == NO) 4809 { 4810 [NSApp addWindowsItem: self 4811 title: _windowTitle 4812 filename: [self _hasTitleWithRepresentedFilename]]; 4813 } 4814 } 4815} 4816 4817- (id) validRequestorForSendType: (NSString*)sendType 4818 returnType: (NSString*)returnType 4819{ 4820 id result = nil; 4821 4822 if (_delegate && [_delegate respondsToSelector: _cmd] 4823 && ![_delegate isKindOfClass: [NSResponder class]]) 4824 result = [_delegate validRequestorForSendType: sendType 4825 returnType: returnType]; 4826 4827 if (result == nil) 4828 result = [NSApp validRequestorForSendType: sendType 4829 returnType: returnType]; 4830 return result; 4831} 4832 4833/* 4834 * Saving and restoring the frame 4835 */ 4836- (NSString*) frameAutosaveName 4837{ 4838 return _autosaveName; 4839} 4840 4841- (void) saveFrameUsingName: (NSString*)name 4842{ 4843 NSUserDefaults *defs; 4844 NSString *key; 4845 id obj; 4846 4847 defs = [NSUserDefaults standardUserDefaults]; 4848 obj = [self stringWithSavedFrame]; 4849 key = [NSString stringWithFormat: @"NSWindow Frame %@", name]; 4850 [defs setObject: obj forKey: key]; 4851} 4852 4853- (BOOL) setFrameAutosaveName: (NSString*)name 4854{ 4855 if ([name isEqual: _autosaveName]) 4856 { 4857 return YES; /* That's our name already. */ 4858 } 4859 4860 if ([autosaveNames member: name] != nil) 4861 { 4862 return NO; /* Name in use elsewhere. */ 4863 } 4864 if (_autosaveName != nil) 4865 { 4866 [[self class] removeFrameUsingName: _autosaveName]; 4867 [autosaveNames removeObject: _autosaveName]; 4868 _autosaveName = nil; 4869 } 4870 if (name != nil && [name isEqual: @""] == NO) 4871 { 4872 name = [name copy]; 4873 [autosaveNames addObject: name]; 4874 _autosaveName = name; 4875 RELEASE(name); 4876 if (![self setFrameUsingName: _autosaveName]) 4877 { 4878 [self saveFrameUsingName: _autosaveName]; 4879 } 4880 } 4881 return YES; 4882} 4883 4884- (void) setFrameFromString: (NSString*)string 4885{ 4886 NSScanner *scanner = [NSScanner scannerWithString: string]; 4887 NSRect nRect; 4888 NSRect sRect; 4889 NSRect fRect; 4890 int value; 4891 NSScreen *screen; 4892 4893 /* 4894 * Scan in the window frame (flipped coordinate system). 4895 */ 4896 if ([scanner scanInt: &value] == NO) 4897 { 4898 NSLog(@"Bad window frame format - x-coord missing"); 4899 return; 4900 } 4901 fRect.origin.x = value; 4902 4903 if ([scanner scanInt: &value] == NO) 4904 { 4905 NSLog(@"Bad window frame format - y-coord missing"); 4906 return; 4907 } 4908 fRect.origin.y = value; 4909 4910 if ([scanner scanInt: &value] == NO) 4911 { 4912 NSLog(@"Bad window frame format - width missing"); 4913 return; 4914 } 4915 fRect.size.width = value; 4916 4917 if ([scanner scanInt: &value] == NO) 4918 { 4919 NSLog(@"Bad window frame format - height missing"); 4920 return; 4921 } 4922 fRect.size.height = value; 4923 4924 /* 4925 * Check that the window will come up on screen 4926 */ 4927#if 0 // Not valid since screen frame x/y values can be negative... 4928 if (fRect.origin.x + fRect.size.width < 0) 4929 { 4930 NSLog(@"Bad screen frame - window is off screen"); 4931 return; 4932 } 4933#endif 4934 4935 // if toolbar is showing, adjust saved frame to add the toolbar back in 4936 if ([_toolbar isVisible]) 4937 { 4938 CGFloat toolbarHeight = [[_toolbar _toolbarView] frame].size.height; 4939 fRect.size.height += toolbarHeight; 4940 fRect.origin.y -= toolbarHeight; 4941 } 4942 // if window has a menu, adjust saved frame to add the menu back in 4943 if ([_wv hasMenu]) 4944 { 4945 CGFloat menuBarHeight = [[GSTheme theme] menuHeightForWindow: self]; 4946 fRect.size.height += menuBarHeight; 4947 fRect.origin.y -= menuBarHeight; 4948 } 4949 4950 /* 4951 * Scan in the frame for the area the window was placed in in screen. 4952 */ 4953 if ([scanner scanInt: &value] == NO) 4954 { 4955 NSLog(@"Bad screen frame format - x-coord missing"); 4956 return; 4957 } 4958 sRect.origin.x = value; 4959 4960 if ([scanner scanInt: &value] == NO) 4961 { 4962 NSLog(@"Bad screen frame format - y-coord missing"); 4963 return; 4964 } 4965 sRect.origin.y = value; 4966 4967 if ([scanner scanInt: &value] == NO) 4968 { 4969 NSLog(@"Bad screen frame format - width missing"); 4970 return; 4971 } 4972 sRect.size.width = value; 4973 4974 if ([scanner scanInt: &value] == NO) 4975 { 4976 NSLog(@"Bad screen frame format - height missing"); 4977 return; 4978 } 4979 sRect.size.height = value; 4980 4981 /* 4982 * The screen rectangle gives the area of the screen in which 4983 * the window could be placed (ie a rectangle excluding the dock). 4984 */ 4985 screen = [self _screenForFrame: fRect]; 4986 nRect = [screen visibleFrame]; 4987 4988 /* 4989 * If the new screen drawable area has moved relative to the one in 4990 * which the window was saved, adjust the window position accordingly. 4991 */ 4992 if (NSEqualPoints(nRect.origin, sRect.origin) == NO) 4993 { 4994 fRect.origin.x += nRect.origin.x - sRect.origin.x; 4995 fRect.origin.y += nRect.origin.y - sRect.origin.y; 4996 } 4997 4998 /* 4999 * If the stored screen area is not the same as that currently 5000 * available, we adjust the window frame (position) to try to 5001 * make layout sensible. 5002 */ 5003 if (nRect.size.width != sRect.size.width) 5004 { 5005 fRect.origin.x = nRect.origin.x + (fRect.origin.x - nRect.origin.x) 5006 * (nRect.size.width / sRect.size.width); 5007 } 5008 if (nRect.size.height != sRect.size.height) 5009 { 5010 fRect.origin.y = nRect.origin.y + (fRect.origin.y - nRect.origin.y) 5011 * (nRect.size.height / sRect.size.height); 5012 5013 /* 5014 * If height of the window goes above the screen height, then adjust the window down. 5015 */ 5016 if ((fRect.size.height + fRect.origin.y) > nRect.size.height) 5017 { 5018 fRect.origin.y = nRect.size.height - fRect.size.height; 5019 } 5020 } 5021 5022 // FIXME: Is this check needed? 5023 /* If we aren't resizable (ie. if we don't have a resize bar), make sure 5024 we don't change the size. */ 5025 if (!(_styleMask & NSResizableWindowMask)) 5026 fRect.size = _frame.size; 5027 5028 if (NSEqualSizes(fRect.size, _frame.size) == NO) 5029 { 5030 if ([_delegate respondsToSelector: @selector(windowWillResize:toSize:)]) 5031 { 5032 fRect.size = [_delegate windowWillResize: self 5033 toSize: fRect.size]; 5034 } 5035 } 5036 5037 /* 5038 * Set frame. 5039 */ 5040 [self setFrame: fRect display: (_f.visible) ? YES : NO]; 5041} 5042 5043- (BOOL) setFrameUsingName: (NSString*)name 5044{ 5045 NSUserDefaults *defs; 5046 id obj; 5047 NSString *key; 5048 5049 defs = [NSUserDefaults standardUserDefaults]; 5050 key = [NSString stringWithFormat: @"NSWindow Frame %@", name]; 5051 obj = [defs objectForKey: key]; 5052 if (obj == nil) 5053 return NO; 5054 5055 [self setFrameFromString: obj]; 5056 return YES; 5057} 5058 5059- (BOOL) setFrameUsingName: (NSString *)name 5060 force: (BOOL)force 5061{ 5062 // FIXME 5063 if ((_styleMask & NSResizableWindowMask) || force) 5064 return [self setFrameUsingName: name]; 5065 else 5066 return NO; 5067} 5068 5069- (NSString *) stringWithSavedFrame 5070{ 5071 NSRect fRect; 5072 NSRect sRect; 5073 NSString *autosaveString; 5074 5075 fRect = _frame; 5076 5077 // if toolbar is showing, adjust saved frame to not include the toolbar 5078 if ([_toolbar isVisible]) 5079 { 5080 CGFloat toolbarHeight = [[_toolbar _toolbarView] frame].size.height; 5081 fRect.size.height -= toolbarHeight; 5082 fRect.origin.y += toolbarHeight; 5083 } 5084 // if window has a menu, adjust saved frame to not include the menu 5085 if ([_wv hasMenu]) 5086 { 5087 CGFloat menuBarHeight = [[GSTheme theme] menuHeightForWindow: self]; 5088 fRect.size.height -= menuBarHeight; 5089 fRect.origin.y += menuBarHeight; 5090 } 5091 5092 /* 5093 * The screen rectangle should give the area of the screen in which 5094 * the window could be placed (ie a rectangle excluding the dock). 5095 */ 5096 sRect = [[self screen] visibleFrame]; 5097 autosaveString = [NSString stringWithFormat: @"%d %d %d %d %d %d % d %d ", 5098 (int)fRect.origin.x, (int)fRect.origin.y, 5099 (int)fRect.size.width, (int)fRect.size.height, 5100 (int)sRect.origin.x, (int)sRect.origin.y, 5101 (int)sRect.size.width, (int)sRect.size.height]; 5102 NSDebugLLog(@"NSWindow", @"%s:autosaveName: %@ frame string: %@", __PRETTY_FUNCTION__, 5103 _autosaveName, autosaveString); 5104 5105 return autosaveString; 5106} 5107 5108/* 5109 * Printing and postscript 5110 */ 5111- (NSData *) dataWithEPSInsideRect: (NSRect)rect 5112{ 5113 return [_wv dataWithEPSInsideRect: 5114 [_wv convertRect: rect fromView: nil]]; 5115} 5116 5117- (NSData *) dataWithPDFInsideRect:(NSRect)aRect 5118{ 5119 return [_wv dataWithPDFInsideRect: 5120 [_wv convertRect: aRect fromView: nil]]; 5121} 5122 5123/** 5124 Opens the fax panel to allow the user to fax the contents of 5125 the window view. 5126*/ 5127- (void) fax: (id)sender 5128{ 5129 [_wv fax: sender]; 5130} 5131 5132/** 5133 Opens the print panel to allow the user to print the contents of 5134 the window view. 5135*/ 5136- (void) print: (id)sender 5137{ 5138 [_wv print: sender]; 5139} 5140 5141/* 5142 * Zooming 5143 */ 5144 5145#define DIST 3 5146 5147/** 5148 Returns yes, if the receiver is zoomed. 5149 */ 5150- (BOOL) isZoomed 5151{ 5152 NSRect maxRect = [[self screen] visibleFrame]; 5153 5154 if ([_delegate respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) 5155 { 5156 maxRect = [_delegate windowWillUseStandardFrame: self defaultFrame: maxRect]; 5157 } 5158 else if ([self respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) 5159 { 5160 maxRect = [self windowWillUseStandardFrame: self defaultFrame: maxRect]; 5161 } 5162 else if ([_delegate respondsToSelector: @selector(windowWillResize:toSize:)]) 5163 { 5164 maxRect.size = [_delegate windowWillResize: self toSize: maxRect.size]; 5165 } 5166 else if ([self respondsToSelector: @selector(windowWillResize:toSize:)]) 5167 { 5168 maxRect.size = [self windowWillResize: self toSize: maxRect.size]; 5169 } 5170 5171 // Compare the new frame with the current one 5172 return NSEqualRects(maxRect, _frame); 5173} 5174 5175/** 5176 Performs the zoom method on the receiver. 5177*/ 5178- (void) performZoom: (id)sender 5179{ 5180 // FIXME: We should check for the style and highlight the button 5181 [self zoom: sender]; 5182} 5183 5184/** 5185 Zooms the receiver. This method calls the delegate method 5186 windowShouldZoom:toFrame: to determine if the window should 5187 be allowed to zoom to full screen. 5188*/ 5189- (void) zoom: (id)sender 5190{ 5191 NSRect maxRect = [[self screen] visibleFrame]; 5192 5193 if ([_delegate respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) 5194 { 5195 maxRect = [_delegate windowWillUseStandardFrame: self defaultFrame: maxRect]; 5196 } 5197 else if ([self respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) 5198 { 5199 maxRect = [self windowWillUseStandardFrame: self defaultFrame: maxRect]; 5200 } 5201 5202 maxRect = [self constrainFrameRect: maxRect toScreen: [self screen]]; 5203 5204 // Compare the new frame with the current one 5205 if ((fabs(NSMaxX(maxRect) - NSMaxX(_frame)) < DIST) 5206 && (fabs(NSMaxY(maxRect) - NSMaxY(_frame)) < DIST) 5207 && (fabs(NSMinX(maxRect) - NSMinX(_frame)) < DIST) 5208 && (fabs(NSMinY(maxRect) - NSMinY(_frame)) < DIST)) 5209 { 5210 // Already in zoomed mode, reset user frame, if stored 5211 if (_autosaveName != nil) 5212 { 5213 [self setFrameUsingName: _autosaveName]; 5214 } 5215 return; 5216 } 5217 5218 if ([_delegate respondsToSelector: @selector(windowShouldZoom:toFrame:)]) 5219 { 5220 if (![_delegate windowShouldZoom: self toFrame: maxRect]) 5221 return; 5222 } 5223 else if ([self respondsToSelector: @selector(windowShouldZoom:toFrame:)]) 5224 { 5225 if (![self windowShouldZoom: self toFrame: maxRect]) 5226 return; 5227 } 5228 5229 if (_autosaveName != nil) 5230 { 5231 [self saveFrameUsingName: _autosaveName]; 5232 } 5233 5234 [self setFrame: maxRect display: YES]; 5235} 5236 5237 5238/* 5239 * Default botton 5240 */ 5241 5242- (NSButtonCell *) defaultButtonCell 5243{ 5244 return _defaultButtonCell; 5245} 5246 5247- (void) setDefaultButtonCell: (NSButtonCell *)aCell 5248{ 5249 ASSIGN(_defaultButtonCell, aCell); 5250 _f.default_button_cell_key_disabled = NO; 5251 5252 [aCell setKeyEquivalent: @"\r"]; 5253 [aCell setKeyEquivalentModifierMask: 0]; 5254 [[GSTheme theme] didSetDefaultButtonCell: aCell]; 5255} 5256 5257- (void) disableKeyEquivalentForDefaultButtonCell 5258{ 5259 _f.default_button_cell_key_disabled = YES; 5260} 5261 5262- (void) enableKeyEquivalentForDefaultButtonCell 5263{ 5264 _f.default_button_cell_key_disabled = NO; 5265} 5266 5267- (NSArray *) childWindows 5268{ 5269 return _children; 5270} 5271 5272- (void) addChildWindow: (NSWindow *)child 5273 ordered: (NSWindowOrderingMode)place 5274{ 5275 if (_children == nil) 5276 { 5277 _children = [[NSMutableArray alloc] init]; 5278 } 5279 [_children addObject: child]; 5280 [child setParentWindow: self]; 5281} 5282 5283- (void) removeChildWindow: (NSWindow *)child 5284{ 5285 [_children removeObject: child]; 5286 [child setParentWindow: nil]; 5287} 5288 5289- (NSWindow *) parentWindow 5290{ 5291 return _parent; 5292} 5293 5294- (void) setParentWindow: (NSWindow *)window 5295{ 5296 _parent = window; 5297 5298 if (_windowNum) 5299 { 5300 [GSServerForWindow(self) setParentWindow: [_parent windowNumber] 5301 forChildWindow: _windowNum]; 5302 } 5303} 5304 5305- (BOOL) allowsToolTipsWhenApplicationIsInactive 5306{ 5307 return _f.allows_tooltips_when_inactive; 5308} 5309 5310- (void) setAllowsToolTipsWhenApplicationIsInactive: (BOOL)flag 5311{ 5312 _f.allows_tooltips_when_inactive = flag; 5313} 5314 5315- (BOOL) isMovableByWindowBackground 5316{ 5317 return _f.is_movable_by_window_background; 5318} 5319 5320- (void) setMovableByWindowBackground: (BOOL)flag 5321{ 5322 _f.is_movable_by_window_background = flag; 5323} 5324 5325- (BOOL) displaysWhenScreenProfileChanges 5326{ 5327 return _f.displays_when_screen_profile_changes; 5328} 5329 5330- (void) setDisplaysWhenScreenProfileChanges: (BOOL)flag 5331{ 5332 _f.displays_when_screen_profile_changes = flag; 5333} 5334 5335/* 5336 * Menu item validation 5337 */ 5338 5339- (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>)anItem 5340{ 5341 BOOL result = YES; 5342 SEL action = [anItem action]; 5343 5344 if (sel_isEqual(action, @selector(performClose:))) 5345 { 5346 result = ([self styleMask] & NSClosableWindowMask) ? YES : NO; 5347 } 5348 else if (sel_isEqual(action, @selector(performMiniaturize:))) 5349 { 5350 result = ([self styleMask] & NSMiniaturizableWindowMask) ? YES : NO; 5351 } 5352 else if (sel_isEqual(action, @selector(performZoom:))) 5353 { 5354 result = ([self styleMask] & NSResizableWindowMask) ? YES : NO; 5355 } 5356 else if (sel_isEqual(action, @selector(undo:))) 5357 { 5358 NSUndoManager *undo = [_firstResponder undoManager]; 5359 if (undo == nil) 5360 { 5361 result = NO; 5362 } 5363 else 5364 { 5365 result = [undo canUndo]; 5366 if ([(id)anItem respondsToSelector: @selector(setTitle:)]) 5367 { 5368 if (result) 5369 [(id)anItem setTitle: [undo undoMenuItemTitle]]; 5370 else 5371 [(id)anItem setTitle: 5372 [undo undoMenuTitleForUndoActionName: @""]]; 5373 } 5374 } 5375 } 5376 else if (sel_isEqual(action, @selector(redo:))) 5377 { 5378 NSUndoManager *undo = [_firstResponder undoManager]; 5379 if (undo == nil) 5380 { 5381 result = NO; 5382 } 5383 else 5384 { 5385 result = [undo canRedo]; 5386 if ([(id)anItem respondsToSelector: @selector(setTitle:)]) 5387 { 5388 if (result) 5389 [(id)anItem setTitle: [undo redoMenuItemTitle]]; 5390 else 5391 [(id)anItem setTitle: 5392 [undo redoMenuTitleForUndoActionName: @""]]; 5393 } 5394 } 5395 } 5396 else if (sel_isEqual(action, @selector(toggleToolbarShown:))) 5397 { 5398 NSToolbar *toolbar = [self toolbar]; 5399 5400 if (toolbar == nil) 5401 { 5402 result = NO; 5403 } 5404 else 5405 { 5406 result = YES; 5407 if ([(id)anItem respondsToSelector: @selector(setTitle:)]) 5408 { 5409 if ([toolbar isVisible]) 5410 [(id)anItem setTitle: _(@"Hide Toolbar")]; 5411 else 5412 [(id)anItem setTitle: _(@"Show Toolbar")]; 5413 } 5414 } 5415 } 5416 else if (sel_isEqual(action, @selector(runToolbarCustomizationPalette:))) 5417 { 5418 NSToolbar *toolbar = [self toolbar]; 5419 5420 if (toolbar == nil) 5421 { 5422 result = NO; 5423 } 5424 else 5425 { 5426 result = [toolbar allowsUserCustomization]; 5427 } 5428 } 5429 5430 return result; 5431} 5432 5433- (BOOL) validateMenuItem: (NSMenuItem *)anItem 5434{ 5435 return [self validateUserInterfaceItem: anItem]; 5436} 5437 5438/* 5439 * Assigning a delegate 5440 */ 5441 5442/** 5443 Returns the delegate. 5444 */ 5445- (id) delegate 5446{ 5447 return _delegate; 5448} 5449 5450/** 5451 Sets the delegate to anObject. 5452*/ 5453- (void) setDelegate: (id)anObject 5454{ 5455 if (anObject == _delegate) 5456 { 5457 // don't remove previously registered notifications if delegate is unchanged! 5458 return; 5459 } 5460 5461 if (_delegate) 5462 { 5463 [nc removeObserver: _delegate name: nil object: self]; 5464 } 5465 _delegate = anObject; 5466 5467#define SET_DELEGATE_NOTIFICATION(notif_name) \ 5468 if ([_delegate respondsToSelector: @selector(window##notif_name:)]) \ 5469 [nc addObserver: _delegate \ 5470 selector: @selector(window##notif_name:) \ 5471 name: NSWindow##notif_name##Notification object: self] 5472 5473 SET_DELEGATE_NOTIFICATION(DidBecomeKey); 5474 SET_DELEGATE_NOTIFICATION(DidBecomeMain); 5475 SET_DELEGATE_NOTIFICATION(DidChangeScreen); 5476 SET_DELEGATE_NOTIFICATION(DidDeminiaturize); 5477 SET_DELEGATE_NOTIFICATION(DidExpose); 5478 SET_DELEGATE_NOTIFICATION(DidMiniaturize); 5479 SET_DELEGATE_NOTIFICATION(DidMove); 5480 SET_DELEGATE_NOTIFICATION(DidResignKey); 5481 SET_DELEGATE_NOTIFICATION(DidResignMain); 5482 SET_DELEGATE_NOTIFICATION(DidResize); 5483 SET_DELEGATE_NOTIFICATION(DidUpdate); 5484 SET_DELEGATE_NOTIFICATION(WillClose); 5485 SET_DELEGATE_NOTIFICATION(WillMiniaturize); 5486 SET_DELEGATE_NOTIFICATION(WillMove); 5487} 5488 5489/* 5490 * NSCoding protocol 5491 */ 5492- (void) encodeWithCoder: (NSCoder*)aCoder 5493{ 5494 BOOL flag; 5495 5496 // If were're being initialized from a keyed coder... 5497 if ([aCoder allowsKeyedCoding]) 5498 { 5499 // The docs indicate that there should be an error when directly encoding with 5500 // a keyed coding archiver. We should only encode NSWindow and subclasses 5501 // using NSWindowTemplate. 5502 [NSException raise: NSInvalidArgumentException 5503 format: @"Keyed coding not implemented for %@.", 5504 NSStringFromClass([self class])]; 5505 } 5506 5507 [super encodeWithCoder: aCoder]; 5508 5509 [aCoder encodeRect: [[self contentView] frame]]; 5510 [aCoder encodeValueOfObjCType: @encode(NSUInteger) at: &_styleMask]; 5511 // This used to be int, we need to stay compatible 5512 [aCoder encodeValueOfObjCType: @encode(NSInteger) at: &_backingType]; 5513 5514 [aCoder encodePoint: NSMakePoint(NSMinX([self frame]), NSMaxY([self frame]))]; 5515 [aCoder encodeObject: _contentView]; 5516 [aCoder encodeObject: _backgroundColor]; 5517 [aCoder encodeObject: _representedFilename]; 5518 [aCoder encodeObject: _miniaturizedTitle]; 5519 [aCoder encodeObject: _windowTitle]; 5520 5521 // [aCoder encodeSize: _minimumSize]; 5522 // [aCoder encodeSize: _maximumSize]; 5523 [aCoder encodeSize: [self contentMinSize]]; 5524 [aCoder encodeSize: [self contentMaxSize]]; 5525 5526 [aCoder encodeValueOfObjCType: @encode(NSInteger) at: &_windowLevel]; 5527 5528 flag = _f.menu_exclude; 5529 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5530 flag = _f.is_one_shot; 5531 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5532 flag = _f.is_autodisplay; 5533 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5534 flag = _f.optimize_drawing; 5535 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5536 flag = _f.dynamic_depth_limit; 5537 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5538 flag = _f.cursor_rects_enabled; 5539 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5540 flag = _f.is_released_when_closed; 5541 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5542 flag = _f.hides_on_deactivate; 5543 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5544 flag = _f.accepts_mouse_moved; 5545 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 5546 5547 [aCoder encodeObject: _miniaturizedImage]; 5548 [aCoder encodeConditionalObject: _initialFirstResponder]; 5549} 5550 5551- (id) initWithCoder: (NSCoder*)aDecoder 5552{ 5553 id oldself = self; 5554 BOOL flag; 5555 5556 // If were're being initialized from a keyed coder... 5557 if ([aDecoder allowsKeyedCoding]) 5558 { 5559 // The docs indicate that there should be an error when directly encoding with 5560 // a keyed coding archiver. We should only encode NSWindow and subclasses 5561 // using NSWindowTemplate. 5562 [NSException raise: NSInvalidArgumentException 5563 format: @"Keyed coding not implemented for %@.", 5564 NSStringFromClass([self class])]; 5565 } 5566 5567 5568 if ((self = [super initWithCoder: aDecoder]) == oldself) 5569 { 5570 NSSize aSize; 5571 NSRect aRect; 5572 NSPoint p; 5573 NSUInteger aStyle; 5574 NSBackingStoreType aBacking; 5575 NSInteger level; 5576 id obj; 5577 int version = [aDecoder versionForClassName: @"NSWindow"]; 5578 5579 aRect = [aDecoder decodeRect]; 5580 [aDecoder decodeValueOfObjCType: @encode(NSUInteger) 5581 at: &aStyle]; 5582 // This used to be int, we need to stay compatible 5583 [aDecoder decodeValueOfObjCType: @encode(NSInteger) 5584 at: &aBacking]; 5585 5586 // call the designated initializer.... 5587 self = [self initWithContentRect: aRect 5588 styleMask: aStyle 5589 backing: aBacking 5590 defer: NO]; 5591 5592 p = [aDecoder decodePoint]; 5593 obj = [aDecoder decodeObject]; 5594 [self setContentView: obj]; 5595 obj = [aDecoder decodeObject]; 5596 [self setBackgroundColor: obj]; 5597 obj = [aDecoder decodeObject]; 5598 [self setRepresentedFilename: obj]; 5599 obj = [aDecoder decodeObject]; 5600 [self setMiniwindowTitle: obj]; 5601 obj = [aDecoder decodeObject]; 5602 [self setTitle: obj]; 5603 5604 if (version < 3) 5605 { 5606 aSize = [aDecoder decodeSize]; 5607 [self setMinSize: aSize]; 5608 aSize = [aDecoder decodeSize]; 5609 [self setMaxSize: aSize]; 5610 } 5611 else 5612 { 5613 aSize = [aDecoder decodeSize]; 5614 [self setContentMinSize: aSize]; 5615 aSize = [aDecoder decodeSize]; 5616 [self setContentMaxSize: aSize]; 5617 } 5618 5619 [aDecoder decodeValueOfObjCType: @encode(NSInteger) 5620 at: &level]; 5621 [self setLevel: level]; 5622 5623 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5624 [self setExcludedFromWindowsMenu: flag]; 5625 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5626 [self setOneShot: flag]; 5627 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5628 [self setAutodisplay: flag]; 5629 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5630 [self useOptimizedDrawing: flag]; 5631 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5632 [self setDynamicDepthLimit: flag]; 5633 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5634 if (flag) 5635 [self enableCursorRects]; 5636 else 5637 [self disableCursorRects]; 5638 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5639 [self setReleasedWhenClosed: flag]; 5640 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5641 [self setHidesOnDeactivate: flag]; 5642 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 5643 [self setAcceptsMouseMovedEvents: flag]; 5644 5645 /* If the image has been specified, use it, if not use the default. */ 5646 obj = [aDecoder decodeObject]; 5647 if (obj != nil) 5648 { 5649 ASSIGN(_miniaturizedImage, obj); 5650 } 5651 5652 [aDecoder decodeValueOfObjCType: @encode(id) 5653 at: &_initialFirstResponder]; 5654 5655 [self setFrameTopLeftPoint: p]; 5656 } 5657 5658 return self; 5659} 5660 5661- (void) bind: (NSString *)binding 5662 toObject: (id)anObject 5663 withKeyPath: (NSString *)keyPath 5664 options: (NSDictionary *)options 5665{ 5666 if ([binding isEqual: NSTitleBinding]) 5667 { 5668 GSKeyValueBinding *kvb; 5669 5670 [self unbind: binding]; 5671 kvb = [[GSKeyValueBinding alloc] initWithBinding: @"title" 5672 withName: NSTitleBinding 5673 toObject: anObject 5674 withKeyPath: keyPath 5675 options: options 5676 fromObject: self]; 5677 // The binding will be retained in the binding table 5678 RELEASE(kvb); 5679 } 5680 else 5681 { 5682 [super bind: binding toObject: anObject withKeyPath: keyPath 5683 options: options]; 5684 } 5685} 5686 5687/** 5688 Returns all drawers associated with this window. 5689*/ 5690- (NSArray *) drawers 5691{ 5692 // TODO 5693 NSLog(@"Method %s is not implemented for class %s", 5694 "drawers", "NSWindow"); 5695 return nil; 5696} 5697 5698- (void *)windowRef 5699{ 5700 GSDisplayServer *srv = GSServerForWindow(self); 5701 5702 return [srv windowDevice: _windowNum]; 5703} 5704 5705- (void *) windowHandle 5706{ 5707 // Should only be defined on MS Windows 5708 return (void *)(intptr_t)_windowNum; 5709} 5710 5711- (NSWindow *) attachedSheet 5712{ 5713 return _attachedSheet; 5714} 5715 5716- (NSWindow *) sheetParent 5717{ 5718 return nil; 5719} 5720 5721- (CGFloat) backingScaleFactor 5722{ 5723 return 1.0; 5724} 5725 5726+ (NSInteger)windowNumberAtPoint:(NSPoint)point 5727 belowWindowWithWindowNumber:(NSInteger)windowNumber 5728{ 5729 return 0; 5730} 5731 5732@end 5733 5734@implementation NSWindow (Toolbar) 5735 5736- (void) runToolbarCustomizationPalette: (id)sender 5737{ 5738 [[self toolbar] runCustomizationPalette: sender]; 5739} 5740 5741- (void) toggleToolbarShown: (id)sender 5742{ 5743 NSToolbar *toolbar = [self toolbar]; 5744 BOOL isVisible = [toolbar isVisible]; 5745 5746 if (!toolbar) 5747 return; 5748 5749 // We do this again on a lower level, but doing it here is faster. 5750 if (isVisible) 5751 { 5752 [_wv removeToolbarView: [toolbar _toolbarView]]; 5753 } 5754 else 5755 { 5756 [_wv addToolbarView: [toolbar _toolbarView]]; 5757 } 5758 5759 [toolbar setVisible: !isVisible]; 5760 5761 [self display]; 5762} 5763 5764// Accessors 5765 5766- (NSToolbar *) toolbar 5767{ 5768 return _toolbar; 5769} 5770 5771- (void) setToolbar: (NSToolbar*)toolbar 5772{ 5773 if (toolbar == _toolbar) 5774 return; 5775 5776 if (_toolbar != nil) 5777 { 5778 if ([_toolbar isVisible]) 5779 { 5780 // Throw the last toolbar view out 5781 [_wv removeToolbarView: [_toolbar _toolbarView]]; 5782 } 5783 } 5784 5785 ASSIGN(_toolbar, toolbar); 5786 5787 if (_toolbar != nil) 5788 { 5789 if ([_toolbar isVisible]) 5790 { 5791 // Make the new toolbar view visible 5792 [_wv addToolbarView: [_toolbar _toolbarView]]; 5793 } 5794 } 5795 5796 // To show the changed toolbar 5797 [self displayIfNeeded]; 5798} 5799 5800@end 5801 5802@implementation NSWindow (Menu) 5803 5804- (void) setMenu: (NSMenu *)menu 5805{ 5806 // Do theme specific logic... 5807 [[GSTheme theme] setMenu: menu forWindow: self]; 5808 5809 if([self menu] != menu) 5810 [super setMenu: menu]; 5811} 5812 5813@end 5814 5815/* 5816 * GNUstep backend methods 5817 */ 5818@implementation NSWindow (GNUstepBackend) 5819 5820/* 5821 * Mouse capture/release 5822 */ 5823- (void) _captureMouse: sender 5824{ 5825 NSDebugLLog(@"CaptureMouse", @"Capturing the mouse"); 5826 [GSCurrentServer() capturemouse: _windowNum]; 5827} 5828 5829- (void) _releaseMouse: sender 5830{ 5831 NSDebugLLog(@"CaptureMouse", @"Releasing the mouse"); 5832 [GSCurrentServer() releasemouse]; 5833} 5834 5835- (void) _setVisible: (BOOL)flag 5836{ 5837 _f.visible = flag; 5838} 5839 5840- (void) performDeminiaturize: sender 5841{ 5842 [self deminiaturize: sender]; 5843} 5844 5845/* 5846 * Allow subclasses to init without the backend 5847 * class attempting to create an actual window 5848 */ 5849- (void) _initDefaults 5850{ 5851 _firstResponder = self; 5852// _initialFirstResponder = nil; 5853// _delegate = nil; 5854// _windowNum = 0; 5855// _gstate = 0; 5856 _backgroundColor = RETAIN([NSColor windowBackgroundColor]); 5857 _representedFilename = @"Window"; 5858 _miniaturizedTitle = @"Window"; 5859 _miniaturizedImage = RETAIN([NSApp applicationIconImage]); 5860 _windowTitle = @"Window"; 5861 _lastPoint = NSZeroPoint; 5862 _windowLevel = NSNormalWindowLevel; 5863 5864 _depthLimit = NSDefaultDepth; 5865 _disableFlushWindow = 0; 5866 _alphaValue = 1.0; 5867 5868// _f.accepts_drag = NO; 5869// _f.is_one_shot = NO; 5870// _f.needs_flush = NO; 5871 _f.is_autodisplay = YES; 5872// _f.optimize_drawing = NO; 5873 _f.dynamic_depth_limit = YES; 5874// _f.cursor_rects_enabled = NO; 5875// _f.cursor_rects_valid = NO; 5876// _f.visible = NO; 5877// _f.is_key = NO; 5878// _f.is_main = NO; 5879// _f.is_edited = NO; 5880 _f.is_released_when_closed = YES; 5881// _f.is_miniaturized = NO; 5882// _f.menu_exclude = NO; 5883// _f.hides_on_deactivate = NO; 5884// _f.accepts_mouse_moved = NO; 5885// _f.has_opened = NO; 5886// _f.has_closed = NO; 5887// _f.default_button_cell_key_disabled = NO; 5888 _f.can_hide = YES; 5889// _f.has_shadow = NO; 5890 _f.is_opaque = YES; 5891 _f.views_need_display = YES; 5892 _f.selectionDirection = NSDirectSelection; 5893} 5894 5895@end 5896 5897@implementation NSWindow (GNUstepTextView) 5898- (id) _futureFirstResponder 5899{ 5900 return _futureFirstResponder; 5901} 5902@end 5903 5904@implementation NSApplication(Inactive) 5905- (BOOL) _isWindowInactive: (NSWindow *)window 5906{ 5907 return [_inactive containsObject: window]; 5908} 5909 5910- (void) _setWindow: (NSWindow *)window inactive: (BOOL)inactive 5911{ 5912 if (inactive) 5913 { 5914 [_inactive addObject: window]; 5915 } 5916 else 5917 { 5918 [_inactive removeObject: window]; 5919 } 5920} 5921@end 5922 5923BOOL GSViewAcceptsDrag(NSView *v, id<NSDraggingInfo> dragInfo) 5924{ 5925 NSPasteboard *pb = [dragInfo draggingPasteboard]; 5926 if ([pb availableTypeFromArray: GSGetDragTypes(v)]) 5927 return YES; 5928 return NO; 5929} 5930 5931void NSCountWindows(NSInteger *count) 5932{ 5933 *count = [[GSCurrentServer() windowlist] count]; 5934} 5935 5936void NSWindowList(NSInteger size, NSInteger list[]) 5937{ 5938 NSArray *windowList = [GSCurrentServer() windowlist]; 5939 NSUInteger i, c; 5940 5941 for (i = 0, c = [windowList count]; i < size && i < c; i++) 5942 { 5943 list[i] = [[windowList objectAtIndex: i] integerValue]; 5944 } 5945} 5946 5947NSArray *GSOrderedWindows(void) 5948{ 5949 NSArray *window_list = [GSCurrentServer() windowlist]; 5950 NSMutableArray *ret = [NSMutableArray array]; 5951 NSUInteger i, c; 5952 5953 for (i = 0, c = [window_list count]; i < c; i++) 5954 { 5955 NSInteger windowNumber = [[window_list objectAtIndex: i] integerValue]; 5956 NSWindow *win = GSWindowWithNumber(windowNumber); 5957 5958 [ret addObject: win]; 5959 } 5960 5961 return ret; 5962} 5963 5964 5965NSArray* GSAllWindows(void) 5966{ 5967 if (windowmaps) 5968 return NSAllMapTableValues(windowmaps); 5969 return nil; 5970} 5971 5972NSWindow* GSWindowWithNumber(NSInteger num) 5973{ 5974 if (windowmaps) 5975 return (NSWindow*)NSMapGet(windowmaps, (void*)(intptr_t)num); 5976 return nil; 5977} 5978