ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/EmulatorView.mm
Revision: 1.8
Committed: 2003-03-11T11:27:20Z (21 years, 3 months ago) by nigel
Branch: MAIN
Changes since 1.7: +48 -13 lines
Log Message:
Corrected mouse co-ordinate processing after full screen resizing,
simplified mouse movement processing for full screen, added a few comments.

File Contents

# User Rev Content
1 nigel 1.1 /*
2     * EmulatorView.mm - Custom NSView for Basilisk II graphics output
3     *
4 nigel 1.8 * $Id: EmulatorView.mm,v 1.7 2002/12/18 11:53:11 nigel Exp $
5 nigel 1.1 *
6     * Basilisk II (C) 1997-2002 Christian Bauer
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22    
23     #import "sysdeps.h" // Types used in Basilisk C++ code,
24    
25     #define DEBUG 0
26     #import <debug.h>
27    
28     #import <Cocoa/Cocoa.h>
29    
30     #import "main_macosx.h" // For WarningAlert() et al prototypes
31     #import "misc_macosx.h" // For InfoSheet() prototype
32     #import "video_macosx.h" // For init_* globals, and bitmap drawing strategy
33    
34     #import "EmulatorView.h"
35    
36     @implementation EmulatorView
37    
38    
39     //
40     // Standard NSView methods that we override
41     //
42    
43     - (id) initWithFrame: (NSRect) frameRect
44     {
45     self = [super initWithFrame: frameRect];
46    
47     output = self; // Set global for access by Basilisk C++ code
48     // bitmap = nil; // Set by readyToDraw:
49     drawView = NO; // Disable drawing until later
50 nigel 1.4 fullScreen = NO;
51 nigel 1.1
52     return self;
53     }
54    
55 nigel 1.8 - (void) awakeFromNib
56     {
57     // Here we store the height of the screen which the app was opened on.
58     // NSApplication's sendEvent: always uses that screen for its mouse co-ords
59     screen_height = (int) [[NSScreen mainScreen] frame].size.height;
60     }
61    
62    
63 nigel 1.5 // Mouse click in this window. If window is not active,
64     // should the click be passed to this view?
65 nigel 1.1 - (BOOL) acceptsFirstMouse: (NSEvent *) event
66     {
67     return [self mouseInView];
68     }
69    
70    
71 nigel 1.8 //
72     // Key event processing.
73     // OS X doesn't send us separate events for the modifier keys
74     // (shift/control/command), so we need to monitor them separately
75     //
76    
77 nigel 1.1 #include <adb.h>
78    
79     static int prevFlags;
80    
81     - (void) flagsChanged: (NSEvent *) event
82     {
83     int flags = [event modifierFlags];
84    
85     if ( (flags & NSAlphaShiftKeyMask) != (prevFlags & NSAlphaShiftKeyMask) )
86     if ( flags & NSAlphaShiftKeyMask )
87     ADBKeyDown(0x39); // CAPS_LOCK
88     else
89     ADBKeyUp(0x39);
90    
91     if ( (flags & NSShiftKeyMask) != (prevFlags & NSShiftKeyMask) )
92     if ( flags & NSShiftKeyMask )
93     ADBKeyDown(0x38); // SHIFT_LEFT
94     else
95     ADBKeyUp(0x38);
96    
97     if ( (flags & NSControlKeyMask) != (prevFlags & NSControlKeyMask) )
98     if ( flags & NSControlKeyMask )
99     ADBKeyDown(0x36); // CTL_LEFT
100     else
101     ADBKeyUp(0x36);
102    
103     if ( (flags & NSAlternateKeyMask) != (prevFlags & NSAlternateKeyMask) )
104     if ( flags & NSAlternateKeyMask )
105     ADBKeyDown(0x3a); // OPTION_LEFT
106     else
107     ADBKeyUp(0x3a);
108    
109     if ( (flags & NSCommandKeyMask) != (prevFlags & NSCommandKeyMask) )
110     if ( flags & NSCommandKeyMask )
111     ADBKeyDown(0x37); // APPLE_LEFT
112     else
113     ADBKeyUp(0x37);
114    
115     prevFlags = flags;
116     }
117    
118 nigel 1.8 //
119     // Windowed mode. We only send mouse/key events
120     // if the OS X mouse is within the little screen
121     //
122 nigel 1.1 - (BOOL) mouseInView: (NSEvent *) event
123     {
124 nigel 1.4 NSRect box;
125 nigel 1.5 NSPoint loc;
126    
127 nigel 1.4 if ( fullScreen )
128 nigel 1.5 {
129     box = displayBox;
130     loc = [NSEvent mouseLocation];
131     }
132 nigel 1.4 else
133 nigel 1.5 {
134 nigel 1.4 box = [self frame];
135 nigel 1.5 loc = [event locationInWindow];
136     }
137    
138     D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f, box.size.width=%f, box.size.height=%f", __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y, box.size.width, box.size.height));
139 nigel 1.1 return [self mouse: loc inRect: box];
140     }
141    
142     - (BOOL) mouseInView
143     {
144     NSPoint loc = [[self window] mouseLocationOutsideOfEventStream];
145     NSRect box = [self frame];
146     D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f",
147     __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y));
148     return [self mouse: loc inRect: box];
149     }
150    
151     //
152     // Custom methods
153     //
154    
155     - (void) benchmark
156     {
157     int i;
158     float seconds;
159     NSDate *startDate;
160    
161     if ( ! drawView )
162     return;
163    
164     drawView = NO;
165     [self lockFocus];
166     startDate = [NSDate date];
167     for (i = 1; i < 300; ++i )
168     #ifdef NSBITMAP
169     [bitmap draw];
170     #endif
171     #ifdef CGIMAGEREF
172 nigel 1.7 cgDrawInto([self bounds], cgImgRep);
173 nigel 1.1 #endif
174     #ifdef CGDRAWBITMAP
175     [self CGDrawBitmap];
176     #endif
177     seconds = -[startDate timeIntervalSinceNow];
178     [self unlockFocus];
179     drawView = YES;
180    
181     InfoSheet(@"Benchmark run. 300 frames.",
182     [NSString stringWithFormat:
183     @"%.2f seconds, %.3f frames per second", seconds, i/seconds],
184     @"Thanks", [self window]);
185     }
186    
187     // Return a TIFF for a snapshot of the screen image
188     - (NSData *) TIFFrep
189     {
190     #ifdef NSBITMAP
191     return [bitmap TIFFRepresentation];
192     #else
193     WarningAlert("How do I get a TIFF from a CGImageRef?");
194     #endif
195     return nil;
196     }
197    
198     // Enable display of, and drawing into, the view
199     #ifdef NSBITMAP
200     - (void) readyToDraw: (NSBitmapImageRep *) theBitmap
201     imageWidth: (short) width
202     imageHeight: (short) height
203     {
204 nigel 1.8 D(NSLog(@"readyToDraw: theBitmap=%lx\n", theBitmap));
205    
206 nigel 1.1 bitmap = theBitmap;
207 nigel 1.7 numBytes = [theBitmap bytesPerRow] * height;
208 nigel 1.1 #endif
209     #ifdef CGIMAGEREF
210     - (void) readyToDraw: (CGImageRef) image
211     imageWidth: (short) width
212     imageHeight: (short) height
213     {
214 nigel 1.8 D(NSLog(@"readyToDraw: theBitmap=%lx\n", [cgImgRef bitmap]));
215    
216 nigel 1.7 cgImgRep = image;
217 nigel 1.8 numBytes = CGImageGetBytesPerRow(image) * height;
218 nigel 1.1 #endif
219     #ifdef CGDRAWBITMAP
220     - (void) readyToDraw: (void *) theBitmap
221     width: (short) width
222     height: (short) height
223     bps: (short) bitsPerSample
224     spp: (short) samplesPerPixel
225     bpp: (short) bitsPerPixel
226     bpr: (int) bpr
227     isPlanar: (BOOL) planar
228     hasAlpha: (BOOL) alpha
229     {
230 nigel 1.8 D(NSLog(@"readyToDraw: theBitmap=%lx\n", theBitmap));
231    
232 nigel 1.1 bitmap = theBitmap;
233     bps = bitsPerSample;
234     spp = samplesPerPixel;
235     bpp = bitsPerPixel;
236     bytesPerRow = bpr;
237     isPlanar = planar;
238     hasAlpha = alpha;
239 nigel 1.7 numBytes = bpr * height;
240 nigel 1.1 #endif
241     x = width, y = height;
242     drawView = YES;
243     [[self window] setAcceptsMouseMovedEvents: YES];
244     // [[self window] setInitialFirstResponder: self];
245     [[self window] makeFirstResponder: self];
246     }
247    
248     - (void) disableDrawing
249     {
250     drawView = NO;
251     }
252    
253 nigel 1.5 - (void) startedFullScreen: (CGDirectDisplayID) display
254 nigel 1.4 {
255 nigel 1.5 CGRect displayBounds = CGDisplayBounds(display);
256    
257 nigel 1.4 fullScreen = YES;
258 nigel 1.5 memcpy(&displayBox, &displayBounds, sizeof(displayBox));
259 nigel 1.4 }
260    
261 nigel 1.1 - (short) width
262     {
263     return (short)[self bounds].size.width;
264     }
265    
266     - (short) height
267     {
268     return (short)[self bounds].size.height;
269     }
270    
271 nigel 1.4 - (BOOL) isFullScreen
272     {
273     return fullScreen;
274     }
275    
276 nigel 1.1 - (BOOL) isOpaque
277     {
278     return drawView;
279     }
280    
281     - (BOOL) processKeyEvent: (NSEvent *) event
282     {
283 nigel 1.4 if ( fullScreen || [self acceptsFirstMouse: event] )
284 nigel 1.1 if ( [event isARepeat] )
285     return NO;
286     else
287     return YES;
288    
289     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
290     return NO;
291     }
292    
293     - (void) keyDown: (NSEvent *) event
294     {
295     if ( [self processKeyEvent: event] )
296 nigel 1.2 {
297     int code = [event keyCode];
298    
299     if ( code == 126 ) code = 0x3e; // CURS_UP
300     if ( code == 125 ) code = 0x3d; // CURS_DOWN
301     if ( code == 124 ) code = 0x3c; // CURS_RIGHT
302     if ( code == 123 ) code = 0x3b; // CURS_LEFT
303    
304     ADBKeyDown(code);
305     }
306 nigel 1.1 }
307    
308     - (void) keyUp: (NSEvent *) event
309     {
310     if ( [self processKeyEvent: event] )
311 nigel 1.2 {
312     int code = [event keyCode];
313    
314     if ( code == 126 ) code = 0x3e; // CURS_UP
315     if ( code == 125 ) code = 0x3d; // CURS_DOWN
316     if ( code == 124 ) code = 0x3c; // CURS_RIGHT
317     if ( code == 123 ) code = 0x3b; // CURS_LEFT
318    
319     ADBKeyUp(code);
320     }
321 nigel 1.1 }
322    
323 nigel 1.8
324     - (void) fullscreenMouseMove
325     {
326     NSPoint location = [NSEvent mouseLocation];
327    
328     D(NSLog (@"%s - loc.x=%f, loc.y=%f",
329     __PRETTY_FUNCTION__, location.x, location.y));
330     D(NSLog (@"%s - Sending ADBMouseMoved(%d,%d). (%d-%d)",
331     __PRETTY_FUNCTION__, (int)location.x,
332     screen_height - (int)location.y, screen_height, (int)location.y));
333     ADBMouseMoved((int)location.x, screen_height - (int)location.y);
334     }
335    
336 nigel 1.1 static NSPoint mouse; // Previous/current mouse location
337    
338     - (BOOL) processMouseMove: (NSEvent *) event
339     {
340 nigel 1.5 NSPoint location;
341 nigel 1.1
342 nigel 1.4 if ( fullScreen )
343 nigel 1.8 {
344     [self fullscreenMouseMove];
345     return YES;
346     }
347    
348     location = [self convertPoint: [event locationInWindow] fromView:nil];
349    
350     D(NSLog (@"%s - loc.x=%f, loc.y=%f",
351     __PRETTY_FUNCTION__, location.x, location.y));
352 nigel 1.1
353 nigel 1.5 if ( NSEqualPoints(location, mouse) )
354 nigel 1.1 return NO;
355    
356 nigel 1.5 mouse = location;
357 nigel 1.1
358     #ifdef CAN_RESIZE_VIEW
359     int mouseY = y - y * mouse.y / [self height];
360     int mouseX = x * mouse.x / [self width];
361     #else
362     int mouseY = y - (int) mouse.y;
363     int mouseX = (int) mouse.x;
364     #endif
365    
366     ADBMouseMoved(mouseX, mouseY);
367     return YES;
368     }
369    
370     - (void) mouseDown: (NSEvent *) event
371     {
372     [self processMouseMove: event];
373     ADBMouseDown(0);
374     }
375    
376     - (void) mouseDragged: (NSEvent *) event
377     {
378     [self processMouseMove: event];
379     }
380    
381     - (void) mouseMoved: (NSEvent *) event
382     {
383     #if DEBUG
384     if ( ! [self mouseInView] )
385     {
386     NSLog (@"%s - Received event while outside of view", __PRETTY_FUNCTION__);
387     return;
388     }
389     #endif
390     [self processMouseMove: event];
391     }
392    
393     - (void) mouseUp: (NSEvent *) event
394     {
395     [self processMouseMove: event];
396     ADBMouseUp(0);
397     }
398    
399 nigel 1.7 #if DEBUG && ! defined(CGIMAGEREF)
400 nigel 1.1 - (void) randomise // Draw some coloured snow in the bitmap
401     {
402 nigel 1.7 unsigned char *data,
403     *pixel;
404    
405     #ifdef CGDRAWBITMAP
406     data = bitmap;
407     #endif
408     #ifdef NSBITMAP
409     data = [bitmap bitmapData];
410     #endif
411 nigel 1.1
412     for ( int i = 0; i < 1000; ++i )
413     {
414 nigel 1.7 pixel = data + (int) (numBytes * rand() / RAND_MAX);
415 nigel 1.1 *pixel = (unsigned char) (256.0 * rand() / RAND_MAX);
416     }
417     }
418     #endif
419    
420     - (void) drawRect: (NSRect) rect
421     {
422     if ( ! drawView ) // If the emulator is still being setup,
423     return; // we do not want to draw
424    
425     #if DEBUG
426     NSLog(@"In drawRect");
427 nigel 1.7 # ifndef CGIMAGEREF
428     [self randomise];
429     # endif
430 nigel 1.1 #endif
431    
432     #ifdef NSBITMAP
433     NSRectClip(rect);
434     [bitmap draw];
435     #endif
436     #ifdef CGIMAGEREF
437 nigel 1.7 cgDrawInto(rect, cgImgRep);
438 nigel 1.1 #endif
439     #ifdef CGDRAWBITMAP
440     [self CGDrawBitmap];
441     #endif
442     }
443    
444     //
445     // Extra drawing stuff
446     //
447    
448     #ifdef CGDRAWBITMAP
449 nigel 1.6 extern "C" void CGDrawBitmap(...);
450 nigel 1.1
451     - (void) CGDrawBitmap
452     {
453 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
454     graphicsPort];
455 nigel 1.1 NSRect rect = [self bounds];
456     CGRect cgRect = {
457     {rect.origin.x, rect.origin.y},
458     {rect.size.width, rect.size.height}
459     };
460    
461     CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
462    
463    
464 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
465 nigel 1.1
466     CGDrawBitmap(cgContext, cgRect, x, y, bps, spp, bpp,
467     bytesPerRow, isPlanar, hasAlpha, colourSpace, &bitmap);
468     }
469     #endif
470    
471     #ifdef CGIMAGEREF
472     void
473 nigel 1.7 cgDrawInto(NSRect rect, CGImageRef cgImgRep)
474 nigel 1.1 {
475 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
476     graphicsPort];
477 nigel 1.1 CGRect cgRect = {
478     {rect.origin.x, rect.origin.y},
479     {rect.size.width, rect.size.height}
480     };
481    
482 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
483 nigel 1.1
484 nigel 1.7 CGContextDrawImage(cgContext, cgRect, cgImgRep);
485 nigel 1.1 }
486     #endif
487    
488 nigel 1.3 @end