ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/video_macosx.mm
Revision: 1.3
Committed: 2002-05-30T12:43:32Z (22 years ago) by nigel
Branch: MAIN
Changes since 1.2: +84 -59 lines
Log Message:
Removed duplicate modes, new way of checking fullscreen mode, use sheets
instead of panels for warnings & errors

File Contents

# User Rev Content
1 nigel 1.1 /*
2 nigel 1.3 * $Id: video_macosx.mm,v 1.2 2002/04/05 12:15:34 nigel Exp $
3 nigel 1.1 *
4     * video_macosx.mm - Interface between Basilisk II and Cocoa windowing.
5     * Based on video_amiga.cpp and video_x.cpp
6     *
7     * Basilisk II (C) 1997-2002 Christian Bauer
8     *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License as published by
11     * the Free Software Foundation; either version 2 of the License, or
12     * (at your option) any later version.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22     */
23    
24    
25     #include "sysdeps.h"
26    
27     #ifdef HAVE_PTHREADS
28     # include <pthread.h>
29     #endif
30    
31     #include <adb.h>
32     #include <cpu_emulation.h>
33     #include <main.h>
34     #include "macos_util_macosx.h"
35     #include <prefs.h>
36     #include <user_strings.h>
37     #include "video_macosx.h"
38    
39     #define DEBUG 0
40     #include "debug.h"
41    
42 nigel 1.3 #import <Foundation/NSString.h> // Needed for NSLog(@"")
43     #import "misc_macosx.h" // WarningSheet() prototype
44    
45 nigel 1.1
46    
47     // Global variables
48     uint8 display_type = DISPLAY_WINDOW, // These are used by PrefsEditor
49     frame_skip;
50     uint16 init_width = MIN_WIDTH, // as well as this code
51     init_height = MIN_HEIGHT,
52     init_depth = 32,
53 nigel 1.3 screen_height = 0; // Used by processMouseMove:
54 nigel 1.1
55     EmulatorView *output = nil; // Set by [EmulatorView init]
56     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 nigel 1.3 static CGDirectDisplayID theDisplay = NULL;
72     static CFDictionaryRef originalMode = NULL,
73     newMode = NULL;
74 nigel 1.1
75    
76    
77     // Prototypes
78    
79     static void add_mode (const uint16 width, const uint16 height,
80     const uint32 resolution_id,
81     const uint32 bytes_per_row,
82     const video_depth depth);
83     static void add_standard_modes (const video_depth depth);
84    
85     static bool video_open (const video_mode &mode);
86     static void video_close (void);
87    
88    
89    
90     /*
91     * Utility functions
92     */
93    
94     uint8 bits_from_depth(const video_depth depth)
95     {
96     int bits = 1 << depth;
97     // if (bits == 16)
98     // bits = 15;
99     // else if (bits == 32)
100     // bits = 24;
101     return bits;
102     }
103    
104     char *
105     colours_from_depth(const video_depth depth)
106     {
107     switch ( depth )
108     {
109     case VDEPTH_1BIT : return "Monochrome";
110     case VDEPTH_2BIT : return "4 colours";
111     case VDEPTH_4BIT : return "16 colours";
112     case VDEPTH_8BIT : return "256 colours";
113     case VDEPTH_16BIT: return "Thousands of colours";
114     case VDEPTH_32BIT: return "Millions of colours";
115     }
116    
117     return "illegal colour depth";
118     }
119    
120     char *
121     colours_from_depth(const uint16 depth)
122     {
123     return colours_from_depth(DepthModeForPixelDepth(depth) );
124     }
125    
126     bool
127     parse_screen_prefs(const char *mode_str)
128     {
129     if (sscanf(mode_str, "win/%hd/%hd/%hd",
130     &init_width, &init_height, &init_depth) == 3)
131     display_type = DISPLAY_WINDOW;
132     else if (sscanf(mode_str, "win/%hd/%hd", &init_width, &init_height) == 2)
133     display_type = DISPLAY_WINDOW;
134     else if (strcmp(mode_str, "full") == 0)
135     display_type = DISPLAY_SCREEN;
136     else if (sscanf(mode_str, "full/%hd/%hd/%hd",
137     &init_width, &init_height, &init_depth) == 3)
138     display_type = DISPLAY_SCREEN;
139     else if (sscanf(mode_str, "full/%hd/%hd", &init_width, &init_height) == 2)
140     display_type = DISPLAY_SCREEN;
141     else if (sscanf(mode_str, "opengl/%hd/%hd/%hd",
142     &init_width, &init_height, &init_depth) == 3)
143     display_type = DISPLAY_OPENGL;
144     else if (sscanf(mode_str, "opengl/%hd/%hd", &init_width, &init_height) == 2)
145     display_type = DISPLAY_OPENGL;
146     else return false;
147    
148     return true;
149     }
150    
151    
152     // Add mode to list of supported modes
153     static void
154     add_mode(const uint16 width, const uint16 height,
155     const uint32 resolution_id, const uint32 bytes_per_row,
156     const video_depth depth)
157     {
158 nigel 1.3 vector<video_mode>::const_iterator i,
159     end = VideoModes.end();
160    
161     for (i = VideoModes.begin(); i != end; ++i)
162     if ( i->x == width && i->y == height &&
163     i->bytes_per_row == bytes_per_row && i->depth == depth )
164     {
165     D(NSLog(@"Duplicate mode (%hdx%hdx%ld, ID %02x, new ID %02x)\n",
166     width, height, depth, i->resolution_id, resolution_id));
167     return;
168     }
169    
170 nigel 1.1 video_mode mode;
171 nigel 1.3
172 nigel 1.1 mode.x = width;
173     mode.y = height;
174     mode.resolution_id = resolution_id;
175     mode.bytes_per_row = bytes_per_row;
176     mode.depth = depth;
177    
178 nigel 1.3 D(bug("Added video mode: w=%d h=%d d=%d(%d bits)\n",
179 nigel 1.1 width, height, depth, bits_from_depth(depth) ));
180    
181     VideoModes.push_back(mode);
182     }
183    
184     // Add standard list of windowed modes for given color depth
185     static void add_standard_modes(const video_depth depth)
186     {
187 nigel 1.3 D(bug("add_standard_modes: depth=%d(%d bits)\n",
188 nigel 1.1 depth, bits_from_depth(depth) ));
189    
190     add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
191     add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
192     add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
193     add_mode(832, 624, 0x83, TrivialBytesPerRow(832, depth), depth);
194     add_mode(1024, 768, 0x84, TrivialBytesPerRow(1024, depth), depth);
195     add_mode(1152, 768, 0x85, TrivialBytesPerRow(1152, depth), depth);
196     add_mode(1152, 870, 0x86, TrivialBytesPerRow(1152, depth), depth);
197     add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), depth);
198     add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), depth);
199     }
200    
201     // Helper function to get a 32bit int from a dictionary
202     static int32 getCFint32 (CFDictionaryRef dict, CFStringRef key)
203     {
204     CFNumberRef ref = CFDictionaryGetValue(dict, key);
205    
206 nigel 1.2 if ( ref )
207     {
208     int32 val;
209    
210     if ( CFNumberGetValue(ref, kCFNumberSInt32Type, &val) )
211     return val;
212     else
213     NSLog(@"getCFint32() - Failed to get the value %@", key);
214     }
215     else
216     NSLog(@"getCFint32() - Failed to get a 32bit int for %@", key);
217 nigel 1.1
218 nigel 1.2 return 0;
219 nigel 1.1 }
220    
221     static bool add_CGDirectDisplay_modes()
222     {
223     #define kMaxDisplays 8
224     CGDirectDisplayID displays[kMaxDisplays];
225     CGDisplayErr err;
226     CGDisplayCount n;
227     int32 oldRes = 0,
228     res_id = 0x80;
229    
230    
231     err = CGGetActiveDisplayList(kMaxDisplays, displays, &n);
232     if ( err != CGDisplayNoErr )
233 nigel 1.3 n = 1, displays[n] = kCGDirectMainDisplay;
234 nigel 1.1
235     for ( CGDisplayCount dc = 0; dc < n; ++dc )
236     {
237     CGDirectDisplayID d = displays[dc];
238     CFArrayRef m = CGDisplayAvailableModes(d);
239    
240     if ( m == NULL ) // Store the current display mode
241     add_mode(CGDisplayPixelsWide(d),
242     CGDisplayPixelsHigh(d),
243     res_id++, CGDisplayBytesPerRow(d),
244     DepthModeForPixelDepth(CGDisplayBitsPerPixel(d)));
245     else
246     {
247     CFIndex nModes = CFArrayGetCount(m);
248    
249     for ( CFIndex mc = 0; mc < nModes; ++mc )
250     {
251     CFDictionaryRef modeSpec = CFArrayGetValueAtIndex(m, mc);
252    
253     int32 bpp = getCFint32(modeSpec, kCGDisplayBitsPerPixel);
254     int32 height = getCFint32(modeSpec, kCGDisplayHeight);
255     int32 width = getCFint32(modeSpec, kCGDisplayWidth);
256     video_depth depth = DepthModeForPixelDepth(bpp);
257    
258     if ( ! bpp || ! height || ! width )
259     {
260     NSLog(@"Could not get details of mode %d, display %d",
261     mc, dc);
262     return false;
263     }
264 nigel 1.3 #if VERBOSE
265 nigel 1.1 else
266     NSLog(@"Display %ld, spec = %@", d, modeSpec);
267     #endif
268    
269     if ( ! oldRes )
270     oldRes = width * height;
271     else
272     if ( oldRes != width * height )
273     {
274     oldRes = width * height;
275     ++res_id;
276     }
277 nigel 1.3
278     add_mode(width, height, res_id, 0, depth);
279 nigel 1.1 }
280     }
281     }
282    
283     return true;
284     }
285    
286     // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
287 nigel 1.3 static void set_mac_frame_buffer(const video_depth depth)
288 nigel 1.1 {
289     #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
290     switch ( depth )
291     {
292     // case VDEPTH_15BIT:
293     case VDEPTH_16BIT: MacFrameLayout = FLAYOUT_HOST_555; break;
294     // case VDEPTH_24BIT:
295     case VDEPTH_32BIT: MacFrameLayout = FLAYOUT_HOST_888; break;
296     default : MacFrameLayout = FLAYOUT_DIRECT;
297     }
298     VideoMonitor.mac_frame_base = MacFrameBaseMac;
299    
300     // Set variables used by UAE memory banking
301     MacFrameBaseHost = the_buffer;
302     MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y;
303     InitFrameBufferMapping();
304     #else
305     VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer);
306     #endif
307     D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base));
308     }
309    
310     void resizeWinBy(const short deltaX, const short deltaY)
311     {
312     NSRect rect = [the_win frame];
313    
314     D(bug("resizeWinBy(%d,%d) - ", deltaX, deltaY));
315     D(bug("old x=%g, y=%g", rect.size.width, rect.size.height));
316    
317     rect.size.width += deltaX;
318     rect.size.height += deltaY;
319    
320     D(bug(", new x=%g, y=%g\n", rect.size.width, rect.size.height));
321    
322     [the_win setFrame: rect display: YES];
323     rect = [the_win frame];
324     }
325    
326     void resizeWinTo(const uint16 newWidth, const uint16 newHeight)
327     {
328     int deltaX = newWidth - [output width],
329     deltaY = newHeight - [output height];
330    
331     D(bug("resizeWinTo(%d,%d)\n", newWidth, newHeight));
332    
333     if ( deltaX || deltaY )
334     resizeWinBy(deltaX, deltaY);
335     }
336    
337     // Open window
338     static bool init_window(const video_mode &mode)
339     {
340     #ifdef CGIMAGEREF
341     CGColorSpaceRef colourSpace;
342     CGDataProviderRef provider;
343     #endif
344     short bitsPer, samplesPer; // How big is each Pixel?
345     int the_buffer_size;
346    
347 nigel 1.3 D(bug("init_window: depth=%d(%d bits)\n",
348 nigel 1.1 mode.depth, bits_from_depth(mode.depth) ));
349    
350    
351     // Set absolute mouse mode
352     ADBSetRelMouseMode(false);
353    
354    
355     // Open window
356     if (the_win == NULL)
357     {
358     ErrorAlert(STR_OPEN_WINDOW_ERR);
359     return false;
360     }
361     resizeWinTo(mode.x, mode.y);
362    
363    
364     // Create frame buffer ("height + 2" for safety)
365     the_buffer_size = mode.bytes_per_row * (mode.y + 2);
366     the_buffer = calloc(the_buffer_size, 1);
367     if (the_buffer == NULL)
368     {
369     NSLog(@"calloc(%d) failed", the_buffer_size);
370     ErrorAlert(STR_NO_MEM_ERR);
371     return false;
372     }
373     D(bug("the_buffer = %p\n", the_buffer));
374    
375    
376     if ( mode.depth == VDEPTH_1BIT )
377     bitsPer = 1;
378     else
379     bitsPer = 8;
380    
381     if ( mode.depth == VDEPTH_32BIT )
382     samplesPer = 3;
383     else
384     samplesPer = 1;
385    
386     #ifdef CGIMAGEREF
387     switch ( mode.depth )
388     {
389     //case VDEPTH_1BIT: colourSpace = CGColorSpaceCreateDeviceMono(); break
390     case VDEPTH_8BIT: colourSpace = CGColorSpaceCreateDeviceGray(); break;
391     case VDEPTH_32BIT: colourSpace = CGColorSpaceCreateDeviceRGB(); break;
392     default: colourSpace = NULL;
393     }
394    
395     if ( ! colourSpace )
396     {
397     ErrorAlert("No valid colour space");
398     return false;
399     }
400    
401     provider = CGDataProviderCreateWithData(NULL, the_buffer,
402     the_buffer_size, NULL);
403     if ( ! provider )
404     {
405     ErrorAlert("Could not create CGDataProvider from buffer data");
406     return false;
407     }
408     imageRef = CGImageCreate(mode.x,
409     mode.y,
410     bitsPer,
411     bits_from_depth(mode.depth),
412     mode.bytes_per_row,
413     colourSpace,
414     kCGImageAlphaNoneSkipFirst,
415     provider,
416     NULL, // colourMap
417     NO, // shouldInterpolate
418     kCGRenderingIntentDefault);
419     if ( ! imageRef )
420     {
421     ErrorAlert("Could not create CGImage from CGDataProvider");
422     return false;
423     }
424     CGDataProviderRelease(provider);
425     CGColorSpaceRelease(colourSpace);
426    
427     [output readyToDraw: imageRef
428     imageWidth: mode.x
429     imageHeight: mode.y];
430     #else
431     unsigned char *offsetBuffer = the_buffer;
432     offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
433     #endif
434    
435     #ifdef NSBITMAP
436     bitmap = [NSBitmapImageRep alloc];
437     bitmap = [bitmap initWithBitmapDataPlanes: (unsigned char **) &offsetBuffer
438     pixelsWide: mode.x
439     pixelsHigh: mode.y
440     bitsPerSample: bitsPer
441     samplesPerPixel: samplesPer
442     hasAlpha: NO
443     isPlanar: NO
444     colorSpaceName: NSCalibratedRGBColorSpace
445     bytesPerRow: mode.bytes_per_row
446     bitsPerPixel: bits_from_depth(mode.depth)];
447    
448     if ( bitmap == nil )
449     {
450     ErrorAlert("Could not allocate an NSBitmapImageRep");
451     return false;
452     }
453    
454     [output readyToDraw: bitmap
455     imageWidth: mode.x
456     imageHeight: mode.y];
457     #endif
458    
459     #ifdef CGDRAWBITMAP
460     [output readyToDraw: offsetBuffer
461     width: mode.x
462     height: mode.y
463     bps: bitsPer
464     spp: samplesPer
465     bpp: bits_from_depth(mode.depth)
466     bpr: mode.bytes_per_row
467     isPlanar: NO
468     hasAlpha: NO];
469     #endif
470    
471     // Set VideoMonitor
472     VideoMonitor.mode = mode;
473     set_mac_frame_buffer(mode.depth);
474    
475     return true;
476     }
477    
478     #import <AppKit/NSEvent.h>
479 nigel 1.3 #import <Carbon/Carbon.h>
480 nigel 1.1
481 nigel 1.3 static bool init_screen(video_mode &mode)
482 nigel 1.1 {
483     // Set absolute mouse mode
484     ADBSetRelMouseMode(false);
485    
486 nigel 1.3 theDisplay = kCGDirectMainDisplay; // For now
487 nigel 1.1
488     originalMode = CGDisplayCurrentMode(theDisplay);
489 nigel 1.3 if ( nil == originalMode )
490     {
491     ErrorSheet(@"Could not get current mode of display", the_win);
492     return false;
493     }
494 nigel 1.1
495 nigel 1.3 D(NSLog(@"About to call CGDisplayBestModeForParameters()"));
496 nigel 1.1 newMode = CGDisplayBestModeForParameters(theDisplay,
497     bits_from_depth(mode.depth),
498     mode.x, mode.y, NULL);
499     if ( NULL == newMode )
500     {
501 nigel 1.3 ErrorSheet(@"Could not find a matching screen mode", the_win);
502 nigel 1.1 return false;
503     }
504    
505 nigel 1.3 // This sometimes takes ages to return after the window is genied,
506     // so for now we leave it onscreen
507     // [the_win miniaturize: nil];
508 nigel 1.1
509 nigel 1.3 D(NSLog(@"About to call CGDisplayCapture()"));
510     if ( CGDisplayCapture(theDisplay) != CGDisplayNoErr )
511     {
512     // [the_win deminiaturize: nil];
513     ErrorSheet(@"Could not capture display", the_win);
514     return false;
515     }
516 nigel 1.1
517 nigel 1.3 // Set screen height for mouse co-ordinate flipping
518     if ( ! screen_height )
519     screen_height = CGDisplayPixelsHigh(theDisplay);
520 nigel 1.1
521 nigel 1.3 D(NSLog(@"About to call CGDisplaySwitchToMode()"));
522 nigel 1.1 if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr )
523     {
524 nigel 1.3 // [the_win deminiaturize: nil];
525     ErrorSheet(@"Could not switch to matching screen mode", the_win);
526 nigel 1.1 return false;
527     }
528    
529 nigel 1.3 if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) )
530     {
531     D(bug("Bytes per row (%d) doesn't match current (%ld)\n",
532     mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay)));
533     mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay);
534     }
535    
536     HideMenuBar();
537 nigel 1.1 CGDisplayHideCursor(theDisplay);
538    
539     the_buffer = CGDisplayBaseAddress(theDisplay);
540     if ( the_buffer == NULL )
541     {
542 nigel 1.3 video_close();
543     ErrorSheet(@"Could not get base address of screen", the_win);
544 nigel 1.1 return false;
545     }
546    
547     // Send emulated mouse to current location
548     NSPoint mouse = [NSEvent mouseLocation];
549     ADBMouseMoved((int)mouse.x, screen_height - (int)mouse.y);
550 nigel 1.3 //[output performSelector: @selector(processMouseMove:)
551     // withObject: nil
552     // afterDelay: 10.0];
553 nigel 1.1
554     // Set VideoMonitor
555     VideoMonitor.mode = mode;
556     set_mac_frame_buffer(mode.depth);
557    
558 nigel 1.3 [output startedFullScreen]; // For [Controller sendEvent:]
559    
560 nigel 1.1 return true;
561     }
562    
563     static bool init_opengl(const video_mode &mode)
564     {
565     ErrorAlert("Sorry. OpenGL mode is not implemented yet");
566     return false;
567     }
568    
569     /*
570     * Initialization
571     */
572    
573     bool VideoInit(bool classic)
574     {
575     // Read frame skip prefs
576     frame_skip = PrefsFindInt32("frameskip");
577     if (frame_skip == 0)
578     frame_skip = 1;
579    
580     // Get screen mode from preferences
581     const char *mode_str;
582     if (classic)
583     mode_str = "win/512/342";
584     else
585     mode_str = PrefsFindString("screen");
586    
587     // Determine display_type and init_width, height & depth
588     parse_screen_prefs(mode_str);
589    
590     // Construct list of supported modes
591     if (classic)
592     add_mode(512, 342, 0x80, 64, VDEPTH_1BIT);
593     else
594     switch ( display_type )
595     {
596     case DISPLAY_SCREEN:
597     if ( ! add_CGDirectDisplay_modes() )
598     {
599     ErrorAlert("Unable to get list of displays for full screen mode");
600     return false;
601     }
602     break;
603     case DISPLAY_OPENGL:
604     // Same as window depths and sizes?
605     case DISPLAY_WINDOW:
606     //add_standard_modes(VDEPTH_1BIT);
607     //add_standard_modes(VDEPTH_8BIT);
608     //add_standard_modes(VDEPTH_16BIT);
609     add_standard_modes(VDEPTH_32BIT);
610     break;
611     }
612    
613     video_init_depth_list();
614    
615     #if DEBUG
616     bug("Available video modes:\n");
617     vector<video_mode>::const_iterator i, end = VideoModes.end();
618     for (i = VideoModes.begin(); i != end; ++i)
619     bug(" %dx%d (ID %02x), %s\n", i->x, i->y, i->resolution_id,
620     colours_from_depth(i->depth));
621     #endif
622    
623 nigel 1.3 D(bug("VideoInit: width=%hd height=%hd depth=%d\n",
624 nigel 1.1 init_width, init_height, init_depth));
625    
626     // Find requested default mode and open display
627     if (VideoModes.size() > 0)
628     {
629     // Find mode with specified dimensions
630     std::vector<video_mode>::const_iterator i, end = VideoModes.end();
631     for (i = VideoModes.begin(); i != end; ++i)
632     {
633 nigel 1.3 D(bug("VideoInit: w=%d h=%d d=%d\n",
634 nigel 1.1 i->x, i->y, bits_from_depth(i->depth)));
635     if (i->x == init_width && i->y == init_height
636     && bits_from_depth(i->depth) == init_depth)
637     return video_open(*i);
638     }
639     }
640    
641     char str[150];
642     sprintf(str, "Cannot open selected video mode\r(%hd x %hd, %s).\r%s",
643     init_width, init_height,
644     colours_from_depth(init_depth), "Using lowest resolution");
645     WarningAlert(str);
646    
647     return video_open(VideoModes[0]);
648     }
649    
650    
651     // Open display for specified mode
652     static bool video_open(const video_mode &mode)
653     {
654 nigel 1.3 D(bug("video_open: width=%d height=%d depth=%d bytes_per_row=%d\n",
655 nigel 1.1 mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row));
656    
657     // Open display
658 nigel 1.3 switch ( display_type )
659     {
660     case DISPLAY_WINDOW: return init_window(mode);
661     case DISPLAY_SCREEN: return init_screen((video_mode &)mode);
662     case DISPLAY_OPENGL: return init_opengl(mode);
663 nigel 1.1 }
664    
665 nigel 1.3 return false;
666 nigel 1.1 }
667    
668    
669     static void video_close()
670     {
671     D(bug("video_close()\n"));
672    
673     switch ( display_type ) {
674     case DISPLAY_WINDOW:
675     // Stop redraw thread
676     [output disableDrawing];
677    
678     // Free frame buffer stuff
679     #ifdef CGIMAGEREF
680     CGImageRelease(imageRef);
681     #endif
682     #ifdef NSBITMAP
683     [bitmap release];
684     #endif
685     free(the_buffer);
686    
687     break;
688    
689     case DISPLAY_SCREEN:
690     if ( theDisplay && originalMode )
691     {
692 nigel 1.3 CGDisplayShowCursor(theDisplay);
693     ShowMenuBar();
694 nigel 1.1 CGDisplaySwitchToMode(theDisplay, originalMode);
695     CGDisplayRelease(theDisplay);
696 nigel 1.3 //[the_win deminiaturize: nil];
697 nigel 1.1 }
698     break;
699    
700     case DISPLAY_OPENGL:
701     break;
702     }
703     }
704    
705    
706     /*
707     * Deinitialization
708     */
709    
710     void VideoExit(void)
711     {
712     video_close();
713     }
714    
715    
716     /*
717     * Set palette
718     */
719    
720     void video_set_palette(uint8 *pal, int num)
721     {
722 nigel 1.3 if ( [output isFullScreen] && CGDisplayCanSetPalette(theDisplay)
723     && ! IsDirectMode(VideoMonitor.mode) )
724 nigel 1.1 {
725     CGDirectPaletteRef CGpal;
726     CGDisplayErr err;
727    
728    
729     CGpal = CGPaletteCreateWithByteSamples((CGDeviceByteColor *)pal, num);
730     err = CGDisplaySetPalette(theDisplay, CGpal);
731     if ( err != noErr )
732     NSLog(@"Failed to set palette, error = %d", err);
733     CGPaletteRelease(CGpal);
734     }
735     }
736    
737    
738     /*
739     * Switch video mode
740     */
741    
742     void video_switch_to_mode(const video_mode &mode)
743     {
744     // Close and reopen display
745     video_close();
746     if (!video_open(mode))
747     {
748     if ( display_type == DISPLAY_SCREEN )
749     ErrorAlert("Cannot switch screen to selected video mode");
750     else
751     ErrorAlert(STR_OPEN_WINDOW_ERR);
752     QuitEmulator();
753     }
754     }
755    
756     /*
757     * Close down full-screen mode
758     * (if bringing up error alerts is unsafe while in full-screen mode)
759     */
760    
761     void VideoQuitFullScreen(void)
762     {
763     }
764    
765    
766     /*
767     * Mac VBL interrupt
768     */
769    
770     void VideoInterrupt(void)
771     {
772     }
773    
774    
775     // This function is called on non-threaded platforms from a timer interrupt
776     void VideoRefresh(void)
777     {
778     }