32 |
|
#include <cpu_emulation.h> |
33 |
|
#include <main.h> |
34 |
|
#include "macos_util_macosx.h" |
35 |
– |
#include "main_macosx.h" |
35 |
|
#include <prefs.h> |
36 |
|
#include <user_strings.h> |
37 |
|
#include "video_macosx.h" |
39 |
|
#define DEBUG 0 |
40 |
|
#include "debug.h" |
41 |
|
|
42 |
+ |
#ifdef NSBITMAP |
43 |
+ |
#import <AppKit/NSBitmapImageRep.h> |
44 |
+ |
#endif |
45 |
+ |
|
46 |
|
#import <Foundation/NSString.h> // Needed for NSLog(@"") |
47 |
|
#import "misc_macosx.h" // WarningSheet() prototype |
48 |
|
|
57 |
|
|
58 |
|
EmulatorView *output = nil; // Set by [EmulatorView init] |
59 |
|
NSWindow *the_win = nil; // Set by [Emulator awakeFromNib] |
57 |
– |
static void *the_buffer = NULL; |
58 |
– |
|
59 |
– |
|
60 |
– |
#ifdef CGIMAGEREF |
61 |
– |
static CGImageRef imageRef = nil; |
62 |
– |
#endif |
63 |
– |
|
64 |
– |
#ifdef NSBITMAP |
65 |
– |
#import <AppKit/NSBitmapImageRep.h> |
66 |
– |
|
67 |
– |
static NSBitmapImageRep *bitmap = nil; |
68 |
– |
#endif |
69 |
– |
|
70 |
– |
// These record changes we made in setting full screen mode |
71 |
– |
static CGDirectDisplayID theDisplay = NULL; |
72 |
– |
static CFDictionaryRef originalMode = NULL, |
73 |
– |
newMode = NULL; |
74 |
– |
static BOOL singleDisplay = YES; |
75 |
– |
|
76 |
– |
|
77 |
– |
// Prototypes |
78 |
– |
|
79 |
– |
static bool video_open (const video_mode &mode); |
80 |
– |
static void video_close (void); |
81 |
– |
|
60 |
|
|
61 |
+ |
static BOOL singleDisplay = YES; |
62 |
|
|
63 |
|
/* |
64 |
|
* Utility functions |
122 |
|
return true; |
123 |
|
} |
124 |
|
|
125 |
+ |
// Supported video modes |
126 |
+ |
static vector<video_mode> VideoModes; |
127 |
+ |
|
128 |
|
|
129 |
|
// Add mode to list of supported modes |
130 |
|
static void |
131 |
|
add_mode(const uint16 width, const uint16 height, |
132 |
|
const uint32 resolution_id, const uint32 bytes_per_row, |
133 |
+ |
const uint32 user_data, |
134 |
|
const video_depth depth) |
135 |
|
{ |
136 |
|
vector<video_mode>::const_iterator i, |
151 |
|
mode.y = height; |
152 |
|
mode.resolution_id = resolution_id; |
153 |
|
mode.bytes_per_row = bytes_per_row; |
154 |
+ |
mode.user_data = user_data; |
155 |
|
mode.depth = depth; |
156 |
|
|
157 |
|
D(bug("Added video mode: w=%d h=%d d=%d(%d bits)\n", |
166 |
|
D(bug("add_standard_modes: depth=%d(%d bits)\n", |
167 |
|
depth, bits_from_depth(depth) )); |
168 |
|
|
169 |
< |
add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth); |
170 |
< |
add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth); |
171 |
< |
add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth); |
172 |
< |
add_mode(832, 624, 0x83, TrivialBytesPerRow(832, depth), depth); |
173 |
< |
add_mode(1024, 768, 0x84, TrivialBytesPerRow(1024, depth), depth); |
174 |
< |
add_mode(1152, 768, 0x85, TrivialBytesPerRow(1152, depth), depth); |
175 |
< |
add_mode(1152, 870, 0x86, TrivialBytesPerRow(1152, depth), depth); |
176 |
< |
add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), depth); |
177 |
< |
add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), depth); |
169 |
> |
add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), 0, depth); |
170 |
> |
add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), 0, depth); |
171 |
> |
add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), 0, depth); |
172 |
> |
add_mode(832, 624, 0x83, TrivialBytesPerRow(832, depth), 0, depth); |
173 |
> |
add_mode(1024, 768, 0x84, TrivialBytesPerRow(1024, depth), 0, depth); |
174 |
> |
add_mode(1152, 768, 0x85, TrivialBytesPerRow(1152, depth), 0, depth); |
175 |
> |
add_mode(1152, 870, 0x86, TrivialBytesPerRow(1152, depth), 0, depth); |
176 |
> |
add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), 0, depth); |
177 |
> |
add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), 0, depth); |
178 |
|
} |
179 |
|
|
180 |
|
// Helper function to get a 32bit int from a dictionary |
197 |
|
return 0; |
198 |
|
} |
199 |
|
|
200 |
+ |
// Nasty hack. CGDisplayAvailableModes() does not provide bytes per row, |
201 |
+ |
// and the emulator doesn't like setting the bytes per row after the screen, |
202 |
+ |
// so we use a lot of magic numbers here. |
203 |
+ |
// This will probably fail on some video hardware. |
204 |
+ |
// I have tested on my G4 PowerBook 400 and G3 PowerBook Series 292 |
205 |
+ |
|
206 |
+ |
static int |
207 |
+ |
CGBytesPerRow(const uint16 width, const video_depth depth) |
208 |
+ |
{ |
209 |
+ |
if ( depth == VDEPTH_8BIT ) |
210 |
+ |
switch ( width ) |
211 |
+ |
{ |
212 |
+ |
case 640: |
213 |
+ |
case 720: return 768; |
214 |
+ |
case 800: |
215 |
+ |
case 896: return 1024; |
216 |
+ |
case 1152: return 1280; |
217 |
+ |
} |
218 |
+ |
|
219 |
+ |
if ( width == 720 && depth == VDEPTH_16BIT) return 1536; |
220 |
+ |
if ( width == 720 && depth == VDEPTH_32BIT) return 3072; |
221 |
+ |
if ( width == 800 && depth == VDEPTH_16BIT) return 1792; |
222 |
+ |
if ( width == 800 && depth == VDEPTH_32BIT) return 3328; |
223 |
+ |
|
224 |
+ |
return TrivialBytesPerRow(width, depth); |
225 |
+ |
} |
226 |
+ |
|
227 |
|
static bool add_CGDirectDisplay_modes() |
228 |
|
{ |
229 |
|
#define kMaxDisplays 8 |
250 |
|
add_mode(CGDisplayPixelsWide(d), |
251 |
|
CGDisplayPixelsHigh(d), |
252 |
|
res_id++, CGDisplayBytesPerRow(d), |
253 |
+ |
(const uint32) d, |
254 |
|
DepthModeForPixelDepth(CGDisplayBitsPerPixel(d))); |
255 |
|
else |
256 |
|
{ |
285 |
|
++res_id; |
286 |
|
} |
287 |
|
|
288 |
< |
add_mode(width, height, res_id, 0, depth); |
288 |
> |
add_mode(width, height, res_id, |
289 |
> |
CGBytesPerRow(width, depth), (const uint32) d, depth); |
290 |
|
} |
291 |
|
} |
292 |
|
} |
294 |
|
return true; |
295 |
|
} |
296 |
|
|
297 |
+ |
|
298 |
+ |
// monitor_desc subclass for Mac OS X displays |
299 |
+ |
|
300 |
+ |
class OSX_monitor : public monitor_desc |
301 |
+ |
{ |
302 |
+ |
public: |
303 |
+ |
OSX_monitor(const vector<video_mode> &available_modes, |
304 |
+ |
video_depth default_depth, |
305 |
+ |
uint32 default_id); |
306 |
+ |
|
307 |
+ |
virtual void set_palette(uint8 *pal, int num); |
308 |
+ |
virtual void switch_to_current_mode(void); |
309 |
+ |
|
310 |
+ |
void set_mac_frame_buffer(const video_mode mode); |
311 |
+ |
|
312 |
+ |
void video_close(void); |
313 |
+ |
bool video_open (const video_mode &mode); |
314 |
+ |
|
315 |
+ |
|
316 |
+ |
private: |
317 |
+ |
bool init_opengl(const video_mode &mode); |
318 |
+ |
bool init_screen( video_mode &mode); |
319 |
+ |
bool init_window(const video_mode &mode); |
320 |
+ |
|
321 |
+ |
|
322 |
+ |
#ifdef CGIMAGEREF |
323 |
+ |
CGImageRef imageRef; |
324 |
+ |
#endif |
325 |
+ |
#ifdef NSBITMAP |
326 |
+ |
NSBitmapImageRep *bitmap; |
327 |
+ |
#endif |
328 |
+ |
void *the_buffer; |
329 |
+ |
|
330 |
+ |
|
331 |
+ |
// These record changes we made in setting full screen mode, |
332 |
+ |
// so that we can set the display back as it was again. |
333 |
+ |
CGDirectDisplayID theDisplay; |
334 |
+ |
CFDictionaryRef originalMode, |
335 |
+ |
newMode; |
336 |
+ |
}; |
337 |
+ |
|
338 |
+ |
|
339 |
+ |
OSX_monitor :: OSX_monitor (const vector<video_mode> &available_modes, |
340 |
+ |
video_depth default_depth, |
341 |
+ |
uint32 default_id) |
342 |
+ |
: monitor_desc (available_modes, default_depth, default_id) |
343 |
+ |
{ |
344 |
+ |
#ifdef CGIMAGEREF |
345 |
+ |
imageRef = nil; |
346 |
+ |
#endif |
347 |
+ |
#ifdef NSBITMAP |
348 |
+ |
bitmap = nil; |
349 |
+ |
#endif |
350 |
+ |
newMode = originalMode = nil; |
351 |
+ |
the_buffer = NULL; |
352 |
+ |
theDisplay = nil; |
353 |
+ |
}; |
354 |
+ |
|
355 |
+ |
|
356 |
|
// Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) |
357 |
< |
static void set_mac_frame_buffer(const video_depth depth) |
357 |
> |
void |
358 |
> |
OSX_monitor::set_mac_frame_buffer(const video_mode mode) |
359 |
|
{ |
360 |
|
#if !REAL_ADDRESSING && !DIRECT_ADDRESSING |
361 |
< |
switch ( depth ) |
361 |
> |
switch ( mode.depth ) |
362 |
|
{ |
363 |
|
// case VDEPTH_15BIT: |
364 |
|
case VDEPTH_16BIT: MacFrameLayout = FLAYOUT_HOST_555; break; |
366 |
|
case VDEPTH_32BIT: MacFrameLayout = FLAYOUT_HOST_888; break; |
367 |
|
default : MacFrameLayout = FLAYOUT_DIRECT; |
368 |
|
} |
369 |
< |
VideoMonitor.mac_frame_base = MacFrameBaseMac; |
369 |
> |
set_mac_frame_base(MacFrameBaseMac); |
370 |
|
|
371 |
|
// Set variables used by UAE memory banking |
372 |
|
MacFrameBaseHost = the_buffer; |
373 |
< |
MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; |
373 |
> |
MacFrameSize = mode.bytes_per_row * mode.y; |
374 |
|
InitFrameBufferMapping(); |
375 |
|
#else |
376 |
< |
VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); |
376 |
> |
set_mac_frame_base(Host2MacAddr(the_buffer)); |
377 |
|
#endif |
378 |
< |
D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base)); |
378 |
> |
D(bug("mac_frame_base = %08x\n", get_mac_frame_base())); |
379 |
|
} |
380 |
|
|
381 |
|
static void |
407 |
|
} |
408 |
|
|
409 |
|
// Open window |
410 |
< |
static bool init_window(const video_mode &mode) |
410 |
> |
bool |
411 |
> |
OSX_monitor::init_window(const video_mode &mode) |
412 |
|
{ |
413 |
|
#ifdef CGIMAGEREF |
414 |
|
CGColorSpaceRef colourSpace; |
541 |
|
hasAlpha: NO]; |
542 |
|
#endif |
543 |
|
|
470 |
– |
// Set VideoMonitor |
471 |
– |
VideoMonitor.mode = mode; |
472 |
– |
set_mac_frame_buffer(mode.depth); |
473 |
– |
|
544 |
|
return true; |
545 |
|
} |
546 |
|
|
547 |
|
#import <AppKit/NSEvent.h> |
548 |
|
#import <Carbon/Carbon.h> |
549 |
+ |
#import "NNThread.h" |
550 |
|
|
551 |
< |
static bool init_screen(video_mode &mode) |
551 |
> |
bool |
552 |
> |
OSX_monitor::init_screen(video_mode &mode) |
553 |
|
{ |
554 |
|
// Set absolute mouse mode |
555 |
|
ADBSetRelMouseMode(false); |
556 |
|
|
557 |
< |
theDisplay = kCGDirectMainDisplay; // For now |
557 |
> |
// Display stored by add_CGDirectDisplay_modes() |
558 |
> |
theDisplay = (CGDirectDisplayID) mode.user_data; |
559 |
|
|
560 |
|
originalMode = CGDisplayCurrentMode(theDisplay); |
561 |
|
if ( ! originalMode ) |
586 |
|
return false; |
587 |
|
} |
588 |
|
|
516 |
– |
[output startedFullScreen: theDisplay]; // For mouse event processing |
517 |
– |
|
589 |
|
D(NSLog(@"About to call CGDisplaySwitchToMode()")); |
590 |
|
if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr ) |
591 |
|
{ |
595 |
|
return false; |
596 |
|
} |
597 |
|
|
598 |
+ |
// For mouse event processing: update screen height |
599 |
+ |
[output startedFullScreen: theDisplay]; |
600 |
+ |
|
601 |
+ |
the_buffer = CGDisplayBaseAddress(theDisplay); |
602 |
+ |
if ( ! the_buffer ) |
603 |
+ |
{ |
604 |
+ |
CGDisplaySwitchToMode(theDisplay, originalMode); |
605 |
+ |
CGDisplayRelease(theDisplay); |
606 |
+ |
// [the_win deminiaturize: nil]; |
607 |
+ |
ErrorSheet(@"Could not get base address of screen", the_win); |
608 |
+ |
return false; |
609 |
+ |
} |
610 |
+ |
NSLog(@"Starting full screen mode, height = %d", |
611 |
+ |
CGDisplayPixelsHigh(theDisplay)); |
612 |
+ |
[output startedFullScreen: theDisplay]; // For mouse event processing |
613 |
+ |
|
614 |
|
if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) ) |
615 |
|
{ |
616 |
|
D(bug("Bytes per row (%d) doesn't match current (%ld)\n", |
632 |
|
ErrorSheet(@"Could move (jump) cursor on screen", the_win); |
633 |
|
return false; |
634 |
|
} |
635 |
+ |
|
636 |
+ |
// Send emulated mouse to current location |
637 |
+ |
// [output performSelector: @selector(processMouseMove:) |
638 |
+ |
// withObject: nil |
639 |
+ |
// afterDelay: 7.0]; |
640 |
+ |
// NNTimer *moveMouse = [[NNTimer new] retain]; |
641 |
+ |
// [moveMouse perform: @selector(processMouseMove:) |
642 |
+ |
// of: output |
643 |
+ |
// after: 3 |
644 |
+ |
// units: NNseconds]; |
645 |
|
} |
646 |
|
else |
647 |
|
{ |
648 |
|
// Should set up something to hide the cursor when it enters theDisplay? |
649 |
|
} |
650 |
|
|
554 |
– |
the_buffer = CGDisplayBaseAddress(theDisplay); |
555 |
– |
if ( ! the_buffer ) |
556 |
– |
{ |
557 |
– |
video_close(); |
558 |
– |
ErrorSheet(@"Could not get base address of screen", the_win); |
559 |
– |
return false; |
560 |
– |
} |
561 |
– |
|
562 |
– |
// Set VideoMonitor |
563 |
– |
VideoMonitor.mode = mode; |
564 |
– |
set_mac_frame_buffer(mode.depth); |
565 |
– |
|
566 |
– |
|
651 |
|
return true; |
652 |
|
} |
653 |
|
|
654 |
< |
static bool init_opengl(const video_mode &mode) |
654 |
> |
|
655 |
> |
bool |
656 |
> |
OSX_monitor::init_opengl(const video_mode &mode) |
657 |
|
{ |
658 |
|
ErrorAlert("Sorry. OpenGL mode is not implemented yet"); |
659 |
|
return false; |
662 |
|
/* |
663 |
|
* Initialization |
664 |
|
*/ |
665 |
+ |
static bool |
666 |
+ |
monitor_init(const video_mode &init_mode) |
667 |
+ |
{ |
668 |
+ |
OSX_monitor *monitor; |
669 |
+ |
BOOL success; |
670 |
+ |
|
671 |
+ |
monitor = new OSX_monitor(VideoModes, init_mode.depth, |
672 |
+ |
init_mode.resolution_id); |
673 |
+ |
success = monitor->video_open(init_mode); |
674 |
+ |
|
675 |
+ |
if ( success ) |
676 |
+ |
{ |
677 |
+ |
monitor->set_mac_frame_buffer(init_mode); |
678 |
+ |
VideoMonitors.push_back(monitor); |
679 |
+ |
return YES; |
680 |
+ |
} |
681 |
+ |
|
682 |
+ |
return NO; |
683 |
+ |
} |
684 |
|
|
685 |
|
bool VideoInit(bool classic) |
686 |
|
{ |
701 |
|
|
702 |
|
// Construct list of supported modes |
703 |
|
if (classic) |
704 |
< |
add_mode(512, 342, 0x80, 64, VDEPTH_1BIT); |
704 |
> |
add_mode(512, 342, 0x80, 64, 0, VDEPTH_1BIT); |
705 |
|
else |
706 |
|
switch ( display_type ) |
707 |
|
{ |
722 |
|
break; |
723 |
|
} |
724 |
|
|
725 |
< |
video_init_depth_list(); |
725 |
> |
// video_init_depth_list(); Now done in monitor_desc constructor? |
726 |
|
|
727 |
|
#if DEBUG |
728 |
|
bug("Available video modes:\n"); |
746 |
|
i->x, i->y, bits_from_depth(i->depth))); |
747 |
|
if (i->x == init_width && i->y == init_height |
748 |
|
&& bits_from_depth(i->depth) == init_depth) |
749 |
< |
return video_open(*i); |
749 |
> |
return monitor_init(*i); |
750 |
|
} |
751 |
|
} |
752 |
|
|
756 |
|
colours_from_depth(init_depth), "Using lowest resolution"); |
757 |
|
WarningAlert(str); |
758 |
|
|
759 |
< |
return video_open(VideoModes[0]); |
759 |
> |
return monitor_init(VideoModes[0]); |
760 |
|
} |
761 |
|
|
762 |
|
|
763 |
|
// Open display for specified mode |
764 |
< |
static bool video_open(const video_mode &mode) |
764 |
> |
bool |
765 |
> |
OSX_monitor::video_open(const video_mode &mode) |
766 |
|
{ |
767 |
|
D(bug("video_open: width=%d height=%d depth=%d bytes_per_row=%d\n", |
768 |
|
mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row)); |
779 |
|
} |
780 |
|
|
781 |
|
|
782 |
< |
static void video_close() |
782 |
> |
void |
783 |
> |
OSX_monitor::video_close() |
784 |
|
{ |
785 |
|
D(bug("video_close()\n")); |
786 |
|
|
824 |
|
|
825 |
|
void VideoExit(void) |
826 |
|
{ |
827 |
< |
video_close(); |
827 |
> |
// Close displays |
828 |
> |
vector<monitor_desc *>::iterator i, end; |
829 |
> |
|
830 |
> |
end = VideoMonitors.end(); |
831 |
> |
|
832 |
> |
for (i = VideoMonitors.begin(); i != end; ++i) |
833 |
> |
dynamic_cast<OSX_monitor *>(*i)->video_close(); |
834 |
|
} |
835 |
|
|
836 |
|
|
838 |
|
* Set palette |
839 |
|
*/ |
840 |
|
|
841 |
< |
void video_set_palette(uint8 *pal, int num) |
841 |
> |
void |
842 |
> |
OSX_monitor::set_palette(uint8 *pal, int num) |
843 |
|
{ |
844 |
|
if ( [output isFullScreen] && CGDisplayCanSetPalette(theDisplay) |
845 |
< |
&& ! IsDirectMode(VideoMonitor.mode) ) |
845 |
> |
&& ! IsDirectMode(get_current_mode()) ) |
846 |
|
{ |
847 |
|
CGDirectPaletteRef CGpal; |
848 |
|
CGDisplayErr err; |
861 |
|
* Switch video mode |
862 |
|
*/ |
863 |
|
|
864 |
< |
void video_switch_to_mode(const video_mode &mode) |
864 |
> |
void |
865 |
> |
OSX_monitor::switch_to_current_mode(void) |
866 |
|
{ |
867 |
+ |
video_mode mode = get_current_mode(); |
868 |
|
char *failure = NULL; |
869 |
|
|
870 |
|
|
871 |
|
D(bug("switch_to_current_mode(): width=%d height=%d depth=%d bytes_per_row=%d\n", mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row)); |
872 |
< |
|
872 |
> |
|
873 |
|
if ( display_type == DISPLAY_SCREEN && originalMode ) |
874 |
|
{ |
875 |
|
D(NSLog(@"About to call CGDisplayBestModeForParameters()")); |
885 |
|
failure = "Could not switch to matching screen mode"; |
886 |
|
} |
887 |
|
|
888 |
+ |
// For mouse event processing: update screen height |
889 |
+ |
[output startedFullScreen: theDisplay]; |
890 |
+ |
|
891 |
|
if ( ! failure && |
892 |
|
mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) ) |
893 |
|
{ |
894 |
|
D(bug("Bytes per row (%d) doesn't match current (%ld)\n", |
895 |
|
mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay))); |
896 |
< |
((video_mode &)mode).bytes_per_row |
778 |
< |
= CGDisplayBytesPerRow(theDisplay); |
896 |
> |
mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay); |
897 |
|
} |
898 |
|
|
899 |
|
if ( ! failure && |
918 |
|
QuitEmulator(); |
919 |
|
} |
920 |
|
else |
921 |
< |
set_mac_frame_buffer(mode.depth); |
921 |
> |
set_mac_frame_buffer(mode); |
922 |
|
} |
923 |
|
|
924 |
|
/* |