1/** <title>NSResponder</title>
2
3   <abstract>Abstract class which is basis of command and event processing</abstract>
4
5   Copyright (C) 1996,1999 Free Software Foundation, Inc.
6
7   Author: Scott Christley <scottc@net-community.com>
8   Date: 1996
9
10   This file is part of the GNUstep GUI Library.
11
12   This library is free software; you can redistribute it and/or
13   modify it under the terms of the GNU Lesser General Public
14   License as published by the Free Software Foundation; either
15   version 2 of the License, or (at your option) any later version.
16
17   This library is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
20   Lesser General Public License for more details.
21
22   You should have received a copy of the GNU Lesser General Public
23   License along with this library; see the file COPYING.LIB.
24   If not, see <http://www.gnu.org/licenses/> or write to the
25   Free Software Foundation, 51 Franklin Street, Fifth Floor,
26   Boston, MA 02110-1301, USA.
27*/
28
29#include "config.h"
30#import <Foundation/NSCoder.h>
31#import <Foundation/NSDebug.h>
32#import <Foundation/NSInvocation.h>
33#import "AppKit/NSResponder.h"
34#import "AppKit/NSApplication.h"
35#import "AppKit/NSMenu.h"
36#import "AppKit/NSEvent.h"
37#import "AppKit/NSGraphics.h"
38#import "AppKit/NSHelpManager.h"
39#import "AppKit/NSInputManager.h"
40
41@implementation NSResponder
42
43/*
44 * Class methods
45 */
46+ (void) initialize
47{
48  if (self == [NSResponder class])
49    {
50      [self setVersion: 1];
51
52      /* Gets the current input manager - this forces it to read the
53         key binding files at this stage.  */
54      [NSInputManager currentInputManager];
55    }
56}
57
58/*
59 * Instance methods
60 */
61/*
62 * Managing the next responder
63 */
64- (NSResponder*) nextResponder
65{
66  return _next_responder;
67}
68
69- (void) setNextResponder: (NSResponder*)aResponder
70{
71  _next_responder = aResponder;
72}
73
74/**
75 * Returns YES if the receiver is able to become the first responder,
76 * NO otherwise.
77 */
78- (BOOL) acceptsFirstResponder
79{
80  return NO;
81}
82
83- (BOOL) becomeFirstResponder
84{
85  return YES;
86}
87
88- (BOOL) resignFirstResponder
89{
90  return YES;
91}
92
93/*
94 * Aid event processing
95 */
96- (BOOL) performKeyEquivalent: (NSEvent*)theEvent
97{
98  return NO;
99}
100
101/**
102 * If the receiver responds to anAction, it performs that method with
103 * anObject as its argument, discards any return value, and return YES.<br />
104 * Otherwise, the next responder in the chain is asked to perform
105 * anAction and the result of that is returned.<br />
106 * If no responder in the chain is able to respond to anAction, then
107 * NO is returned.
108 */
109- (BOOL) tryToPerform: (SEL)anAction with: (id)anObject
110{
111  /* Can we perform the action -then do it */
112  if ([self respondsToSelector: anAction])
113    {
114      IMP actionIMP = [self methodForSelector: anAction];
115      if (0 != actionIMP)
116        {
117          actionIMP(self, anAction, anObject);
118          return YES;
119        }
120      return YES;
121    }
122  else
123    {
124      /* If we cannot perform then try the next responder */
125      if (!_next_responder)
126	return NO;
127      else
128	return [_next_responder tryToPerform: anAction with: anObject];
129    }
130}
131
132- (BOOL) performMnemonic: (NSString*)aString
133{
134  return NO;
135}
136
137- (void) interpretKeyEvents:(NSArray*)eventArray
138{
139  [[NSInputManager currentInputManager] handleKeyboardEvents: eventArray
140					client: self];
141}
142
143- (void) flushBufferedKeyEvents
144{
145}
146
147- (void) doCommandBySelector:(SEL)aSelector
148{
149  if (![self tryToPerform: aSelector with: nil])
150    {
151      NSBeep();
152    }
153}
154
155- (void) insertText: (id)aString
156{
157  if (_next_responder)
158    [_next_responder insertText: aString];
159  else
160    {
161      NSBeep ();
162    }
163}
164
165
166/*
167 * Forwarding event messages
168 */
169- (void) flagsChanged: (NSEvent*)theEvent
170{
171  if (_next_responder)
172    [_next_responder flagsChanged: theEvent];
173  else
174    [self noResponderFor: @selector(flagsChanged:)];
175}
176
177- (void) helpRequested: (NSEvent*)theEvent
178{
179  if ([[NSHelpManager sharedHelpManager]
180    showContextHelpForObject: self
181    locationHint: [theEvent locationInWindow]] == NO)
182    {
183      if (_next_responder)
184	{
185	  [_next_responder helpRequested: theEvent];
186	  return;
187	}
188    }
189  [NSHelpManager setContextHelpModeActive: NO];
190}
191
192- (void) keyDown: (NSEvent*)theEvent
193{
194  if (_next_responder)
195    [_next_responder keyDown: theEvent];
196  else
197    [self noResponderFor: @selector(keyDown:)];
198}
199
200- (void) keyUp: (NSEvent*)theEvent
201{
202  if (_next_responder)
203    [_next_responder keyUp: theEvent];
204  else
205    [self noResponderFor: @selector(keyUp:)];
206}
207
208- (void) otherMouseDown: (NSEvent*)theEvent
209{
210  if (_next_responder)
211    [_next_responder otherMouseDown: theEvent];
212  else
213    [self noResponderFor: @selector(otherMouseDown:)];
214}
215
216- (void) otherMouseDragged: (NSEvent*)theEvent
217{
218  if (_next_responder)
219    [_next_responder otherMouseDragged: theEvent];
220  else
221    [self noResponderFor: @selector(otherMouseDragged:)];
222}
223
224- (void) otherMouseUp: (NSEvent*)theEvent
225{
226  if (_next_responder)
227    [_next_responder otherMouseUp: theEvent];
228  else
229    [self noResponderFor: @selector(otherMouseUp:)];
230}
231
232- (void) mouseDown: (NSEvent*)theEvent
233{
234  if (_next_responder)
235    [_next_responder mouseDown: theEvent];
236  else
237    [self noResponderFor: @selector(mouseDown:)];
238}
239
240- (void) mouseDragged: (NSEvent*)theEvent
241{
242  if (_next_responder)
243    [_next_responder mouseDragged: theEvent];
244  else
245    [self noResponderFor: @selector(mouseDragged:)];
246}
247
248- (void) mouseEntered: (NSEvent*)theEvent
249{
250  if (_next_responder)
251    [_next_responder mouseEntered: theEvent];
252  else
253    [self noResponderFor: @selector(mouseEntered:)];
254}
255
256- (void) mouseExited: (NSEvent*)theEvent
257{
258  if (_next_responder)
259    [_next_responder mouseExited: theEvent];
260  else
261    [self noResponderFor: @selector(mouseExited:)];
262}
263
264- (void) mouseMoved: (NSEvent*)theEvent
265{
266  if (_next_responder)
267    [_next_responder mouseMoved: theEvent];
268  else
269    [self noResponderFor: @selector(mouseMoved:)];
270}
271
272- (void) mouseUp: (NSEvent*)theEvent
273{
274  if (_next_responder)
275    [_next_responder mouseUp: theEvent];
276  else
277    [self noResponderFor: @selector(mouseUp:)];
278}
279
280- (void) noResponderFor: (SEL)eventSelector
281{
282  /* Only beep for key down events */
283  if (sel_isEqual(eventSelector, @selector(keyDown:)))
284    NSBeep();
285}
286
287- (void) rightMouseDown: (NSEvent*)theEvent
288{
289  if (_next_responder != nil)
290    [_next_responder rightMouseDown: theEvent];
291  else
292    [self noResponderFor: @selector(rightMouseDown:)];
293}
294
295- (void) rightMouseDragged: (NSEvent*)theEvent
296{
297  if (_next_responder)
298    [_next_responder rightMouseDragged: theEvent];
299  else
300    [self noResponderFor: @selector(rightMouseDragged:)];
301}
302
303- (void) rightMouseUp: (NSEvent*)theEvent
304{
305  if (_next_responder)
306    [_next_responder rightMouseUp: theEvent];
307  else
308    [self noResponderFor: @selector(rightMouseUp:)];
309}
310
311- (void) scrollWheel: (NSEvent *)theEvent
312{
313  if (_next_responder)
314    [_next_responder scrollWheel: theEvent];
315  else
316    [self noResponderFor: @selector(scrollWheel:)];
317}
318
319/*
320 * Services menu support
321 */
322- (id) validRequestorForSendType: (NSString*)typeSent
323		      returnType: (NSString*)typeReturned
324{
325  if (_next_responder)
326    return [_next_responder validRequestorForSendType: typeSent
327					  returnType: typeReturned];
328  else
329    return nil;
330}
331
332/*
333 * NSCoding protocol
334 * NB. Don't encode responder chain - it's transient information that should
335 * be reconstructed from else where in the encoded archive.
336 */
337- (void) encodeWithCoder: (NSCoder*)aCoder
338{
339  if ([aCoder allowsKeyedCoding])
340    {
341      if (_interface_style != NSNoInterfaceStyle)
342	{
343	  [aCoder encodeInt: _interface_style
344		  forKey: @"NSInterfaceStyle"];
345	}
346
347      if ([self menu] != nil)
348	{
349	  [aCoder encodeObject: [self menu]
350		  forKey: @"NSMenu"];
351	}
352      if ([self nextResponder] != nil)
353	{
354	  [aCoder encodeConditionalObject: [self nextResponder]
355		  forKey: @"NSNextResponder"];
356	}
357    }
358  else
359    {
360      [aCoder encodeValueOfObjCType: @encode(int) at: &_interface_style];
361      [aCoder encodeObject: _menu];
362    }
363}
364
365- (id) initWithCoder: (NSCoder*)aDecoder
366{
367  id obj = nil;
368
369  if ([aDecoder allowsKeyedCoding])
370    {
371      if ([aDecoder containsValueForKey: @"NSInterfaceStyle"])
372	{
373	  _interface_style = [aDecoder decodeIntForKey: @"NSInterfaceStyle"];
374	}
375
376      if ([aDecoder containsValueForKey: @"NSMenu"])
377	{
378	  obj = [aDecoder decodeObjectForKey: @"NSMenu"];
379	}
380
381      if ([aDecoder containsValueForKey: @"NSNextResponder"])
382	{
383	  [self setNextResponder: [aDecoder decodeObjectForKey: @"NSNextResponder"]];
384	}
385    }
386  else
387    {
388      [aDecoder decodeValueOfObjCType: @encode(int) at: &_interface_style];
389      obj = [aDecoder decodeObject];
390    }
391
392  [self setMenu: obj];
393
394  return self;
395}
396- (void) dealloc
397{
398  RELEASE(_menu);
399  [super dealloc];
400}
401- (NSMenu*) menu
402{
403  return _menu;
404}
405
406- (void) setMenu: (NSMenu*)aMenu
407{
408  ASSIGN(_menu, aMenu);
409}
410
411- (NSInterfaceStyle) interfaceStyle
412{
413  return _interface_style;
414}
415
416- (void) setInterfaceStyle: (NSInterfaceStyle)aStyle
417{
418  _interface_style = aStyle;
419}
420
421- (NSUndoManager*) undoManager
422{
423  if (_next_responder)
424    return [_next_responder undoManager];
425  else
426    return nil;
427}
428
429- (BOOL) shouldBeTreatedAsInkEvent: (NSEvent *)theEvent
430{
431  return NO;
432}
433
434- (BOOL)presentError:(NSError *)error
435{
436  error = [self willPresentError: error];
437
438  if (_next_responder)
439    {
440	return [_next_responder presentError: error];
441    }
442  else
443    {
444      return [NSApp presentError: error];
445    }
446}
447
448- (void)presentError:(NSError *)error
449      modalForWindow:(NSWindow *)window
450	    delegate:(id)delegate
451  didPresentSelector:(SEL)sel
452	 contextInfo:(void *)context
453{
454  error = [self willPresentError: error];
455  if (_next_responder)
456    {
457      [_next_responder presentError: error
458		       modalForWindow: window
459		       delegate: delegate
460		       didPresentSelector: sel
461		       contextInfo: context];
462    }
463  else
464    {
465      [NSApp presentError: error
466	     modalForWindow: window
467	     delegate: delegate
468	     didPresentSelector: sel
469	     contextInfo: context];
470    }
471}
472
473- (NSError *) willPresentError: (NSError *)error
474{
475  return error;
476}
477
478@end
479