ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/video_macosx.mm
Revision: 1.4
Committed: 2002-06-05T10:11:40Z (22 years ago) by nigel
Branch: MAIN
Changes since 1.3: +87 -37 lines
Log Message:
Sequencing changes in init_screen(), removed some global vars and functions,
assorted tidyup, big changes to video_switch_to_mode()

File Contents

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