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