ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/video_macosx.mm
(Generate patch)

Comparing BasiliskII/src/MacOSX/video_macosx.mm (file contents):
Revision 1.1 by nigel, 2002-03-16T04:00:35Z vs.
Revision 1.15 by gbeauche, 2005-01-30T21:42:13Z

# Line 4 | Line 4
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
7 > *  Basilisk II (C) 1997-2005 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
# Line 37 | Line 37
37   #include "video_macosx.h"
38  
39   #define DEBUG 0
40 + #define VERBOSE 0
41   #include "debug.h"
42  
43 + #ifdef NSBITMAP
44 + #import <AppKit/NSBitmapImageRep.h>
45 + #endif
46 +
47 + #import <Foundation/NSString.h>                         // Needed for NSLog(@"")
48 + #import "misc_macosx.h"                                         // WarningSheet() prototype
49 +
50  
51  
52   // Global variables
# Line 46 | Line 54 | uint8          display_type = DISPLAY_WINDOW,  //
54                          frame_skip;    
55   uint16          init_width  = MIN_WIDTH,                // as well as this code
56                          init_height = MIN_HEIGHT,
57 <                        init_depth  = 32,
50 <                        screen_height = MIN_HEIGHT;             // Used by processMouseMove
57 >                        init_depth  = 32;
58  
59                  EmulatorView    *output = nil;          // Set by [EmulatorView init]
60                  NSWindow                *the_win = nil;         // Set by [Emulator awakeFromNib]
54 static  void                    *the_buffer = NULL;
55
56
57 #import <Foundation/NSString.h>                         // Needed for NSLog(@"")
58
59 #ifdef CGIMAGEREF
60 static CGImageRef               imageRef = nil;
61 #endif
62
63 #ifdef NSBITMAP
64 #import <AppKit/NSBitmapImageRep.h>
65
66 static NSBitmapImageRep *bitmap = nil;
67 #endif
68
69 // These record changes we made in setting full screen mode
70 CGDirectDisplayID       theDisplay   = NULL;
71 CFDictionaryRef         originalMode = NULL,
72                                        newMode = NULL;
73
74
75
76 // Prototypes
77
78 static void add_mode                    (const uint16 width, const uint16 height,
79                                                                 const uint32 resolution_id,
80                                                                 const uint32 bytes_per_row,
81                                                                 const video_depth depth);
82 static void add_standard_modes  (const video_depth depth);
83
84 static bool video_open  (const video_mode &mode);
85 static void video_close (void);
86
61  
62 + static  BOOL                    singleDisplay = YES;
63  
64   /*
65   *  Utility functions
66   */
67  
68 < uint8 bits_from_depth(const video_depth depth)
68 > static uint8
69 > bits_from_depth(const video_depth depth)
70   {
71          int bits = 1 << depth;
72   //      if (bits == 16)
# Line 100 | Line 76 | uint8 bits_from_depth(const video_depth
76          return bits;
77   }
78  
79 < char *
79 > static char *
80   colours_from_depth(const video_depth depth)
81   {
82          switch ( depth )
# Line 116 | Line 92 | colours_from_depth(const video_depth dep
92          return "illegal colour depth";
93   }
94  
95 < char *
95 > static char *
96   colours_from_depth(const uint16 depth)
97   {
98          return colours_from_depth(DepthModeForPixelDepth(depth) );
# Line 125 | Line 101 | colours_from_depth(const uint16 depth)
101   bool
102   parse_screen_prefs(const char *mode_str)
103   {
104 +        if ( ! mode_str )
105 +        {
106 +                // No screen pref was found. Supply a default:
107 +                mode_str = "win/512/384";
108 +        }
109 +
110          if (sscanf(mode_str, "win/%hd/%hd/%hd",
111                                  &init_width, &init_height, &init_depth) == 3)
112                  display_type = DISPLAY_WINDOW;
# Line 147 | Line 129 | parse_screen_prefs(const char *mode_str)
129          return true;
130   }
131  
132 + // Supported video modes
133 + static vector<video_mode> VideoModes;
134 +
135  
136   // Add mode to list of supported modes
137   static void
138   add_mode(const uint16 width, const uint16 height,
139                   const uint32 resolution_id, const uint32 bytes_per_row,
140 +                 const uint32 user_data,
141                   const video_depth depth)
142   {
143 +        vector<video_mode>::const_iterator      i,
144 +                                                                                end = VideoModes.end();
145 +
146 +        for (i = VideoModes.begin(); i != end; ++i)
147 +                if ( i->x == width && i->y == height &&
148 +                         i->bytes_per_row == bytes_per_row && i->depth == depth )
149 +                {
150 +                        D(NSLog(@"Duplicate mode (%hdx%hdx%ld, ID %02x, new ID %02x)\n",
151 +                                                width, height, depth, i->resolution_id, resolution_id));
152 +                        return;
153 +                }
154 +
155          video_mode mode;
156 +
157          mode.x = width;
158          mode.y = height;
159          mode.resolution_id = resolution_id;
160          mode.bytes_per_row = bytes_per_row;
161 +        mode.user_data = user_data;
162          mode.depth = depth;
163  
164 <        D(bug("Added video mode: w=%ld  h=%ld  d=%ld(%d bits)\n",
164 >        D(bug("Added video mode: w=%d  h=%d  d=%d(%d bits)\n",
165                                  width, height, depth, bits_from_depth(depth) ));
166  
167          VideoModes.push_back(mode);
# Line 170 | Line 170 | add_mode(const uint16 width, const uint1
170   // Add standard list of windowed modes for given color depth
171   static void add_standard_modes(const video_depth depth)
172   {
173 <        D(bug("add_standard_modes: depth=%ld(%d bits)\n",
173 >        D(bug("add_standard_modes: depth=%d(%d bits)\n",
174                                                  depth, bits_from_depth(depth) ));
175  
176 <        add_mode(512,  384,  0x80, TrivialBytesPerRow(512,  depth), depth);
177 <        add_mode(640,  480,  0x81, TrivialBytesPerRow(640,  depth), depth);
178 <        add_mode(800,  600,  0x82, TrivialBytesPerRow(800,  depth), depth);
179 <        add_mode(832,  624,  0x83, TrivialBytesPerRow(832,  depth), depth);
180 <        add_mode(1024, 768,  0x84, TrivialBytesPerRow(1024, depth), depth);
181 <        add_mode(1152, 768,  0x85, TrivialBytesPerRow(1152, depth), depth);
182 <        add_mode(1152, 870,  0x86, TrivialBytesPerRow(1152, depth), depth);
183 <        add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), depth);
184 <        add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), depth);
176 >        add_mode(512,  384,  0x80, TrivialBytesPerRow(512,  depth), 0, depth);
177 >        add_mode(640,  480,  0x81, TrivialBytesPerRow(640,  depth), 0, depth);
178 >        add_mode(800,  600,  0x82, TrivialBytesPerRow(800,  depth), 0, depth);
179 >        add_mode(832,  624,  0x83, TrivialBytesPerRow(832,  depth), 0, depth);
180 >        add_mode(1024, 768,  0x84, TrivialBytesPerRow(1024, depth), 0, depth);
181 >        add_mode(1152, 768,  0x85, TrivialBytesPerRow(1152, depth), 0, depth);
182 >        add_mode(1152, 870,  0x86, TrivialBytesPerRow(1152, depth), 0, depth);
183 >        add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), 0, depth);
184 >        add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), 0, depth);
185   }
186  
187   // Helper function to get a 32bit int from a dictionary
188   static int32 getCFint32 (CFDictionaryRef dict, CFStringRef key)
189   {
190 <        int32           val = 0;
191 <        CFNumberRef     ref = CFDictionaryGetValue(dict, key);
190 >        CFNumberRef     ref = (CFNumberRef) CFDictionaryGetValue(dict, key);
191 >
192 >        if ( ref )
193 >        {
194 >                int32   val;
195 >
196 >                if ( CFNumberGetValue(ref, kCFNumberSInt32Type, &val) )
197 >                        return val;
198 >                else
199 >                        NSLog(@"getCFint32() - Failed to get the value %@", key);
200 >        }
201 >        else
202 >                NSLog(@"getCFint32() - Failed to get a 32bit int for %@", key);
203 >
204 >        return 0;
205 > }
206 >
207 > // Nasty hack. Under 10.1, CGDisplayAvailableModes() does not provide bytes per row,
208 > // and the emulator doesn't like setting the bytes per row after the screen,
209 > // so we use a lot of magic numbers here.
210 > // This will probably fail on some video hardware.
211 > // I have tested on my G4 PowerBook 400 and G3 PowerBook Series 292
212 >
213 > static int
214 > CGBytesPerRow(const uint16 width, const video_depth depth)
215 > {
216 >        if ( depth == VDEPTH_8BIT )
217 >                switch ( width )
218 >                {
219 >                        case 640:
220 >                        case 720:       return 768;
221 >                        case 800:
222 >                        case 896:       return 1024;
223 >                        case 1152:      return 1280;
224 >                }
225  
226 <        if ( ref && CFNumberGetValue(ref, kCFNumberSInt32Type, &val) )
227 <                if ( ! val )
228 <                        NSLog(@"getCFint32() - Logic error - Got a value of 0");
226 >        if ( width == 720  && depth == VDEPTH_16BIT)    return 1536;
227 >        if ( width == 720  && depth == VDEPTH_32BIT)    return 3072;
228 >        if ( width == 800  && depth == VDEPTH_16BIT)    return 1792;
229 >        if ( width == 800  && depth == VDEPTH_32BIT)    return 3328;
230  
231 <        return val;
231 >        return TrivialBytesPerRow(width, depth);
232   }
233  
234   static bool add_CGDirectDisplay_modes()
# Line 209 | Line 243 | static bool add_CGDirectDisplay_modes()
243  
244          err = CGGetActiveDisplayList(kMaxDisplays, displays, &n);
245          if ( err != CGDisplayNoErr )
246 <                return false;
246 >                n = 1, displays[n] = kCGDirectMainDisplay;
247 >
248 >        if ( n > 1 )
249 >                singleDisplay = NO;
250  
251          for ( CGDisplayCount dc = 0; dc < n; ++dc )
252          {
253                  CGDirectDisplayID       d = displays[dc];
254                  CFArrayRef                      m = CGDisplayAvailableModes(d);
255  
256 <                if ( m == NULL )                                        // Store the current display mode
256 >                if ( ! m )                                      // Store the current display mode
257                          add_mode(CGDisplayPixelsWide(d),
258                                           CGDisplayPixelsHigh(d),
259                                           res_id++, CGDisplayBytesPerRow(d),
260 +                                         (const uint32) d,
261                                           DepthModeForPixelDepth(CGDisplayBitsPerPixel(d)));
262                  else
263                  {
# Line 227 | Line 265 | static bool add_CGDirectDisplay_modes()
265  
266                          for ( CFIndex mc = 0; mc < nModes; ++mc )
267                          {
268 <                                CFDictionaryRef modeSpec = CFArrayGetValueAtIndex(m, mc);
268 >                                CFDictionaryRef modeSpec = (CFDictionaryRef)
269 >                                                                                        CFArrayGetValueAtIndex(m, mc);
270  
271                                  int32   bpp    = getCFint32(modeSpec, kCGDisplayBitsPerPixel);
272                                  int32   height = getCFint32(modeSpec, kCGDisplayHeight);
234                                int32   mode   = getCFint32(modeSpec, kCGDisplayMode);
273                                  int32   width  = getCFint32(modeSpec, kCGDisplayWidth);
274 + #ifdef MAC_OS_X_VERSION_10_2
275 +                                int32   bytes  = getCFint32(modeSpec, kCGDisplayBytesPerRow);
276 + #else
277 +                                int32   bytes  = 0;
278 + #endif
279                                  video_depth     depth = DepthModeForPixelDepth(bpp);
280  
281                                  if ( ! bpp || ! height || ! width )
# Line 241 | Line 284 | static bool add_CGDirectDisplay_modes()
284                                                          mc, dc);
285                                          return false;
286                                  }
287 < #if DEBUG
287 > #if VERBOSE
288                                  else
289                                          NSLog(@"Display %ld, spec = %@", d, modeSpec);
290   #endif
291  
292 <                                add_mode(width, height, res_id,
293 <                                                 TrivialBytesPerRow(width, depth), depth);
292 >                                if ( ! bytes )
293 >                                {
294 >                                        NSLog(@"Could not get bytes per row, guessing");
295 >                                        bytes = CGBytesPerRow(width, depth);
296 >                                }
297  
298                                  if ( ! oldRes )
299                                          oldRes = width * height;
# Line 257 | Line 303 | static bool add_CGDirectDisplay_modes()
303                                                  oldRes = width * height;
304                                                  ++res_id;
305                                          }
306 +
307 +                                add_mode(width, height, res_id, bytes, (const uint32) d, depth);
308                          }
309                  }
310          }
# Line 264 | Line 312 | static bool add_CGDirectDisplay_modes()
312          return true;
313   }
314  
315 + #ifdef CG_USE_ALPHA
316 + // memset() by long instead of byte
317 +
318 + static void memsetl (long *buffer, long pattern, size_t length)
319 + {
320 +        long    *buf = (long *) buffer,
321 +                        *end = buf + length/4;
322 +
323 +        while ( ++buf < end )
324 +                *buf = pattern;
325 + }
326 +
327 + // Sets the alpha channel in a image to full on, except for the corners
328 +
329 + static void mask_buffer (void *buffer, size_t width, size_t size)
330 + {
331 +        long    *bufl = (long *) buffer;
332 +        char    *bufc = (char *) buffer;
333 +
334 +
335 +        memsetl(bufl, 0xFF000000, size);
336 +
337 +
338 +        // Round upper-left corner
339 +                                   *bufl = 0, *bufc+4 = 0;                                      // XXXXX
340 +        bufc += width, *bufc++ = 0, *bufc++ = 0, *bufc++ = 0;   // XXX
341 +        bufc += width, *bufc++ = 0, *bufc = 0;                                  // XX
342 +        bufc += width, *bufc = 0;                                                               // X
343 +        bufc += width, *bufc = 0;                                                               // X
344 +
345 +
346 +        NSLog(@"Masked buffer");
347 + }
348 + #endif
349 +
350 + // monitor_desc subclass for Mac OS X displays
351 +
352 + class OSX_monitor : public monitor_desc
353 + {
354 +        public:
355 +                OSX_monitor(const vector<video_mode>    &available_modes,
356 +                                        video_depth                                     default_depth,
357 +                                        uint32                                          default_id);
358 +
359 +                virtual void set_palette(uint8 *pal, int num);
360 +                virtual void switch_to_current_mode(void);
361 +
362 +                                void set_mac_frame_buffer(const video_mode mode);
363 +
364 +                                void video_close(void);
365 +                                bool video_open (const video_mode &mode);
366 +
367 +
368 +        private:
369 +                bool init_opengl(const video_mode &mode);
370 +                bool init_screen(      video_mode &mode);
371 +                bool init_window(const video_mode &mode);
372 +
373 +
374 + #ifdef CGIMAGEREF
375 +                CGColorSpaceRef         colourSpace;
376 +                uint8                           *colourTable;
377 +                CGImageRef                      imageRef;
378 +                CGDataProviderRef       provider;
379 +                short                           x, y, bpp, depth, bpr;
380 + #endif
381 + #ifdef NSBITMAP
382 +                NSBitmapImageRep        *bitmap;
383 + #endif
384 +                void                            *the_buffer;
385 +
386 +
387 +                // These record changes we made in setting full screen mode,
388 +                // so that we can set the display back as it was again.
389 +                CGDirectDisplayID       theDisplay;
390 +                CFDictionaryRef         originalMode,
391 +                                                        newMode;
392 + };
393 +
394 +
395 + OSX_monitor :: OSX_monitor (const       vector<video_mode>      &available_modes,
396 +                                                                        video_depth                     default_depth,
397 +                                                                        uint32                          default_id)
398 +                        : monitor_desc (available_modes, default_depth, default_id)
399 + {
400 + #ifdef CGIMAGEREF
401 +        colourSpace = nil;
402 +        colourTable = (uint8 *) malloc(256 * 3);
403 +        imageRef = nil;
404 +        provider = nil;
405 + #endif
406 + #ifdef NSBITMAP
407 +        bitmap = nil;
408 + #endif
409 +        newMode = originalMode = nil;
410 +        the_buffer = NULL;
411 +        theDisplay = nil;
412 + };
413 +
414 + // Should also have a destructor which does
415 + //#ifdef CGIMAGEREF
416 + //      free(colourTable);
417 + //#endif
418 +
419 +
420   // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
421 < static void set_mac_frame_buffer(video_depth depth)
421 > void
422 > OSX_monitor::set_mac_frame_buffer(const video_mode mode)
423   {
424   #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
425 <        switch ( depth )
425 >        switch ( mode.depth )
426          {
427          //      case VDEPTH_15BIT:
428                  case VDEPTH_16BIT: MacFrameLayout = FLAYOUT_HOST_555; break;
# Line 276 | Line 430 | static void set_mac_frame_buffer(video_d
430                  case VDEPTH_32BIT: MacFrameLayout = FLAYOUT_HOST_888; break;
431                  default                  : MacFrameLayout = FLAYOUT_DIRECT;
432          }
433 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
433 >        set_mac_frame_base(MacFrameBaseMac);
434  
435          // Set variables used by UAE memory banking
436 <        MacFrameBaseHost = the_buffer;
437 <        MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y;
436 >        MacFrameBaseHost = (uint8 *) the_buffer;
437 >        MacFrameSize = mode.bytes_per_row * mode.y;
438          InitFrameBufferMapping();
439   #else
440 <        VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer);
440 >        set_mac_frame_base((unsigned int)Host2MacAddr((uint8 *)the_buffer));
441   #endif
442 <        D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base));
442 >        D(bug("mac_frame_base = %08x\n", get_mac_frame_base()));
443   }
444  
445 < void resizeWinBy(const short deltaX, const short deltaY)
445 > static void
446 > resizeWinBy(const short deltaX, const short deltaY)
447   {
448          NSRect  rect = [the_win frame];
449  
# Line 300 | Line 455 | void resizeWinBy(const short deltaX, con
455  
456          D(bug(", new x=%g, y=%g\n", rect.size.width, rect.size.height));
457  
458 <        [the_win setFrame: rect display: YES];
458 >        [the_win setFrame: rect display: YES animate: YES];
459 >        [the_win center];
460          rect = [the_win frame];
461   }
462  
# Line 316 | Line 472 | void resizeWinTo(const uint16 newWidth,
472   }
473  
474   // Open window
475 < static bool init_window(const video_mode &mode)
475 > bool
476 > OSX_monitor::init_window(const video_mode &mode)
477   {
478 < #ifdef CGIMAGEREF
322 <        CGColorSpaceRef         colourSpace;
323 <        CGDataProviderRef       provider;
324 < #endif
325 <        short                           bitsPer, samplesPer;    // How big is each Pixel?
326 <        int                                     the_buffer_size;
327 <
328 <        D(bug("init_window: depth=%ld(%d bits)\n",
478 >        D(bug("init_window: depth=%d(%d bits)\n",
479                          mode.depth, bits_from_depth(mode.depth) ));
480  
481  
# Line 333 | Line 483 | static bool init_window(const video_mode
483          ADBSetRelMouseMode(false);
484  
485  
486 <        // Open window
487 <        if (the_win == NULL)
486 >        // Is the window open?
487 >        if ( ! the_win )
488          {
489                  ErrorAlert(STR_OPEN_WINDOW_ERR);
490                  return false;
# Line 343 | Line 493 | static bool init_window(const video_mode
493  
494  
495          // Create frame buffer ("height + 2" for safety)
496 <        the_buffer_size = mode.bytes_per_row * (mode.y + 2);
496 >        int the_buffer_size = mode.bytes_per_row * (mode.y + 2);
497 >
498          the_buffer = calloc(the_buffer_size, 1);
499 <        if (the_buffer == NULL)
499 >        if ( ! the_buffer )
500          {
501                  NSLog(@"calloc(%d) failed", the_buffer_size);
502                  ErrorAlert(STR_NO_MEM_ERR);
# Line 354 | Line 505 | static bool init_window(const video_mode
505          D(bug("the_buffer = %p\n", the_buffer));
506  
507  
508 <        if ( mode.depth == VDEPTH_1BIT )
509 <                bitsPer = 1;
359 <        else
360 <                bitsPer = 8;
361 <
362 <        if ( mode.depth == VDEPTH_32BIT )
363 <                samplesPer = 3;
364 <        else
365 <                samplesPer = 1;
508 >        unsigned char *offsetBuffer = (unsigned char *) the_buffer;
509 >        offsetBuffer += 1;              // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
510  
511   #ifdef CGIMAGEREF
512          switch ( mode.depth )
513          {
514 <                //case VDEPTH_1BIT:     colourSpace = CGColorSpaceCreateDeviceMono(); break
515 <                case VDEPTH_8BIT:       colourSpace = CGColorSpaceCreateDeviceGray(); break;
516 <                case VDEPTH_32BIT:      colourSpace = CGColorSpaceCreateDeviceRGB();  break;
517 <                default:                        colourSpace = NULL;
514 >                case VDEPTH_1BIT:       bpp = 1; break;
515 >                case VDEPTH_2BIT:       bpp = 2; break;
516 >                case VDEPTH_4BIT:       bpp = 4; break;
517 >                case VDEPTH_8BIT:       bpp = 8; break;
518 >                case VDEPTH_16BIT:      bpp = 5; break;
519 >                case VDEPTH_32BIT:      bpp = 8; break;
520 >        }
521 >
522 >        x = mode.x, y = mode.y, depth = bits_from_depth(mode.depth), bpr = mode.bytes_per_row;
523 >
524 >        colourSpace = CGColorSpaceCreateDeviceRGB();
525 >
526 >        if ( mode.depth < VDEPTH_16BIT )
527 >        {
528 >                CGColorSpaceRef oldColourSpace = colourSpace;
529 >
530 >                colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, colourTable);
531 >
532 >                CGColorSpaceRelease(oldColourSpace);
533          }
534  
535          if ( ! colourSpace )
# Line 386 | Line 545 | static bool init_window(const video_mode
545                  ErrorAlert("Could not create CGDataProvider from buffer data");
546                  return false;
547          }
548 <        imageRef = CGImageCreate(mode.x,
549 <                                                         mode.y,
550 <                                                         bitsPer,
551 <                                                         bits_from_depth(mode.depth),
552 <                                                         mode.bytes_per_row,
394 <                                                         colourSpace,
548 >
549 >        imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace,
550 >  #ifdef CG_USE_ALPHA
551 >                                                         kCGImageAlphaPremultipliedFirst,
552 >  #else
553                                                           kCGImageAlphaNoneSkipFirst,
554 +  #endif
555                                                           provider,
556 <                                                         NULL,  // colourMap
557 <                                                         NO,    // shouldInterpolate
556 >                                                         NULL,  // colourMap translation table
557 >                                                         NO,    // shouldInterpolate colours?
558                                                           kCGRenderingIntentDefault);
559          if ( ! imageRef )
560          {
561                  ErrorAlert("Could not create CGImage from CGDataProvider");
562                  return false;
563          }
405        CGDataProviderRelease(provider);
406        CGColorSpaceRelease(colourSpace);
564  
565          [output readyToDraw: imageRef
566 <                         imageWidth: mode.x
567 <                        imageHeight: mode.y];
568 < #else
569 <        unsigned char *offsetBuffer = the_buffer;
570 <        offsetBuffer += 1;      // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
566 >                                 bitmap: offsetBuffer
567 >                         imageWidth: x
568 >                        imageHeight: y];
569 >
570 >
571 >  #ifdef CG_USE_ALPHA
572 >        mask_buffer(the_buffer, x, the_buffer_size);
573 >
574 > /* Create an image mask with this call? */
575 > //CG_EXTERN CGImageRef
576 > //CGImageMaskCreate(size_t width, size_t height, size_t bitsPerComponent,
577 > //                                      size_t bitsPerPixel, size_t bytesPerRow,
578 > //                                      CGDataProviderRef provider, const float decode[], bool shouldInterpolate);
579 >  #endif
580 >
581 >        return true;
582 > #endif
583 >
584 >
585 > #ifndef CGIMAGEREF
586 >        short   bitsPer, samplesPer;    // How big is each Pixel?
587 >
588 >        if ( mode.depth == VDEPTH_1BIT )
589 >                bitsPer = 1;
590 >        else
591 >                bitsPer = 8;
592 >
593 >        if ( mode.depth == VDEPTH_32BIT )
594 >                samplesPer = 3;
595 >        else
596 >                samplesPer = 1;
597   #endif
598  
599 +
600   #ifdef NSBITMAP
601          bitmap = [NSBitmapImageRep alloc];
602          bitmap = [bitmap initWithBitmapDataPlanes: (unsigned char **) &offsetBuffer
# Line 426 | Line 610 | static bool init_window(const video_mode
610                                                                    bytesPerRow: mode.bytes_per_row
611                                                                   bitsPerPixel: bits_from_depth(mode.depth)];
612  
613 <    if ( bitmap == nil )
613 >    if ( ! bitmap )
614          {
615                  ErrorAlert("Could not allocate an NSBitmapImageRep");
616                  return false;
# Line 449 | Line 633 | static bool init_window(const video_mode
633                             hasAlpha: NO];
634   #endif
635  
452        // Set VideoMonitor
453        VideoMonitor.mode = mode;
454        set_mac_frame_buffer(mode.depth);
455
636          return true;
637   }
638  
639   #import <AppKit/NSEvent.h>
640 + #import <Carbon/Carbon.h>
641 + #import "NNThread.h"
642  
643 < // How do I include this file?
644 < // #import <Carbon/HIToolbox/Menus.h>
463 < extern "C" void HideMenuBar(),
464 <                                ShowMenuBar();
465 <
466 < static bool init_screen(const video_mode &mode)
643 > bool
644 > OSX_monitor::init_screen(video_mode &mode)
645   {
646          // Set absolute mouse mode
647          ADBSetRelMouseMode(false);
648  
649 +        // Display stored by add_CGDirectDisplay_modes()
650 +        theDisplay = (CGDirectDisplayID) mode.user_data;
651  
472        theDisplay = kCGDirectMainDisplay;      // For now
652          originalMode = CGDisplayCurrentMode(theDisplay);
653 +        if ( ! originalMode )
654 +        {
655 +                ErrorSheet(@"Could not get current mode of display", the_win);
656 +                return false;
657 +        }
658  
659 +        D(NSLog(@"About to call CGDisplayBestModeForParameters()"));
660          newMode = CGDisplayBestModeForParameters(theDisplay,
661                                                                                           bits_from_depth(mode.depth),
662                                                                                                          mode.x, mode.y, NULL);
663 <        if ( NULL == newMode )
663 >        if ( ! newMode )
664          {
665 <                ErrorAlert("Could not find a matching screen mode");
665 >                ErrorSheet(@"Could not find a matching screen mode", the_win);
666                  return false;
667          }
668  
669 <        [the_win miniaturize: nil];
670 < //      [the_win setLevel: CGShieldingWindowLevel()];
671 <        the_win = nil;
669 > //      This sometimes takes ages to return after the window is genied,
670 > //      so for now we leave it onscreen
671 > //      [the_win miniaturize: nil];
672  
673 <        HideMenuBar();
674 <
675 <        CGDisplayCapture(theDisplay);
673 >        D(NSLog(@"About to call CGDisplayCapture()"));
674 >        if ( CGDisplayCapture(theDisplay) != CGDisplayNoErr )
675 >        {
676 > //              [the_win deminiaturize: nil];
677 >                ErrorSheet(@"Could not capture display", the_win);
678 >                return false;
679 >        }
680  
681 +        D(NSLog(@"About to call CGDisplaySwitchToMode()"));
682          if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr )
683          {
684 <                ErrorAlert("Could not switch to matching screen mode");
684 >                CGDisplayRelease(theDisplay);
685 > //              [the_win deminiaturize: nil];
686 >                ErrorSheet(@"Could not switch to matching screen mode", the_win);
687                  return false;
688          }
689  
498        CGDisplayHideCursor(theDisplay);
499
690          the_buffer = CGDisplayBaseAddress(theDisplay);
691 <        if ( the_buffer == NULL )
691 >        if ( ! the_buffer )
692          {
693 <                ErrorAlert("Could not get base address of screen");
693 >                CGDisplaySwitchToMode(theDisplay, originalMode);
694 >                CGDisplayRelease(theDisplay);
695 > //              [the_win deminiaturize: nil];
696 >                ErrorSheet(@"Could not get base address of screen", the_win);
697                  return false;
698          }
699  
700 <        screen_height = mode.y;         // For mouse co-ordinate flipping
700 >        if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) )
701 >        {
702 >                D(bug("Bytes per row (%d) doesn't match current (%ld)\n",
703 >                                mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay)));
704 >                mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay);
705 >        }
706 >
707 >        HideMenuBar();
708  
709 <        // Send emulated mouse to current location
709 >        if ( singleDisplay )
710 >        {
711 >                CGDisplayHideCursor(theDisplay);
712  
713 <        NSPoint mouse = [NSEvent mouseLocation];
512 <        ADBMouseMoved((int)mouse.x, screen_height - (int)mouse.y);
713 >                [output startedFullScreen: theDisplay];
714  
715 <        // Set VideoMonitor
716 <        VideoMonitor.mode = mode;
717 <        set_mac_frame_buffer(mode.depth);
715 >                // Send emulated mouse to current location
716 >                [output fullscreenMouseMove];
717 >        }
718 >        else
719 >        {
720 >                // Should set up something to hide the cursor when it enters theDisplay?
721 >        }
722  
723          return true;
724   }
725  
726  
727 < static bool init_opengl(const video_mode &mode)
727 > bool
728 > OSX_monitor::init_opengl(const video_mode &mode)
729   {
730          ErrorAlert("Sorry. OpenGL mode is not implemented yet");
731          return false;
# Line 528 | Line 734 | static bool init_opengl(const video_mode
734   /*
735   *  Initialization
736   */
737 + static bool
738 + monitor_init(const video_mode &init_mode)
739 + {
740 +        OSX_monitor     *monitor;
741 +        BOOL            success;
742 +
743 +        monitor = new OSX_monitor(VideoModes, init_mode.depth,
744 +                                                                                  init_mode.resolution_id);
745 +        success = monitor->video_open(init_mode);
746 +
747 +        if ( success )
748 +        {
749 +                monitor->set_mac_frame_buffer(init_mode);
750 +                VideoMonitors.push_back(monitor);
751 +                return YES;
752 +        }
753 +
754 +        return NO;
755 + }
756  
757   bool VideoInit(bool classic)
758   {
# Line 548 | Line 773 | bool VideoInit(bool classic)
773  
774          // Construct list of supported modes
775          if (classic)
776 <                add_mode(512, 342, 0x80, 64, VDEPTH_1BIT);
776 >                add_mode(512, 342, 0x80, 64, 0, VDEPTH_1BIT);
777          else
778                  switch ( display_type )
779                  {
# Line 562 | Line 787 | bool VideoInit(bool classic)
787                          case DISPLAY_OPENGL:
788                                  // Same as window depths and sizes?
789                          case DISPLAY_WINDOW:
790 <                                //add_standard_modes(VDEPTH_1BIT);
791 <                                //add_standard_modes(VDEPTH_8BIT);
792 <                                //add_standard_modes(VDEPTH_16BIT);
790 > #ifdef CGIMAGEREF
791 >                                add_standard_modes(VDEPTH_1BIT);
792 >                                add_standard_modes(VDEPTH_2BIT);
793 >                                add_standard_modes(VDEPTH_4BIT);
794 >                                add_standard_modes(VDEPTH_8BIT);
795 >                                add_standard_modes(VDEPTH_16BIT);
796 > #endif
797                                  add_standard_modes(VDEPTH_32BIT);
798                                  break;
799                  }
800  
801 <        video_init_depth_list();
801 > //      video_init_depth_list();                Now done in monitor_desc constructor?
802  
803   #if DEBUG
804          bug("Available video modes:\n");
# Line 579 | Line 808 | bool VideoInit(bool classic)
808                                                                                  colours_from_depth(i->depth));
809   #endif
810  
811 <        D(bug("VideoInit: width=%hd height=%hd depth=%ld\n",
811 >        D(bug("VideoInit: width=%hd height=%hd depth=%d\n",
812                                                  init_width, init_height, init_depth));
813  
814          // Find requested default mode and open display
# Line 589 | Line 818 | bool VideoInit(bool classic)
818                  std::vector<video_mode>::const_iterator i, end = VideoModes.end();
819                  for (i = VideoModes.begin(); i != end; ++i)
820                  {
821 <                        D(bug("VideoInit: w=%ld h=%ld d=%ld\n",
821 >                        D(bug("VideoInit: w=%d h=%d d=%d\n",
822                                          i->x, i->y, bits_from_depth(i->depth)));
823                          if (i->x == init_width && i->y == init_height
824                                          && bits_from_depth(i->depth) == init_depth)
825 <                                return video_open(*i);
825 >                                return monitor_init(*i);
826                  }
827          }
828  
# Line 603 | Line 832 | bool VideoInit(bool classic)
832                          colours_from_depth(init_depth), "Using lowest resolution");
833          WarningAlert(str);
834  
835 <        return video_open(VideoModes[0]);
835 >        return monitor_init(VideoModes[0]);
836   }
837  
838  
839   // Open display for specified mode
840 < static bool video_open(const video_mode &mode)
840 > bool
841 > OSX_monitor::video_open(const video_mode &mode)
842   {
843 <        D(bug("video_open: width=%ld  height=%ld  depth=%ld  bytes_per_row=%ld\n",
843 >        D(bug("video_open: width=%d  height=%d  depth=%d  bytes_per_row=%d\n",
844                          mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row));
845  
846          // Open display
847 <        switch ( display_type ) {
848 <                case DISPLAY_WINDOW:
849 <                        if ( ! init_window(mode) )
850 <                                return false;
851 <                        break;
622 <
623 <                case DISPLAY_SCREEN:
624 <                        if ( ! init_screen(mode) )
625 <                                return false;
626 <                        break;
627 <
628 <                case DISPLAY_OPENGL:
629 <                        if ( ! init_opengl(mode) )
630 <                                return false;
631 <                        break;
847 >        switch ( display_type )
848 >        {
849 >                case DISPLAY_WINDOW:    return init_window(mode);
850 >                case DISPLAY_SCREEN:    return init_screen((video_mode &)mode);
851 >                case DISPLAY_OPENGL:    return init_opengl(mode);
852          }
853  
854 <        return true;
854 >        return false;
855   }
856  
857  
858 < static void video_close()
858 > void
859 > OSX_monitor::video_close()
860   {
861          D(bug("video_close()\n"));
862  
# Line 647 | Line 868 | static void video_close()
868                          // Free frame buffer stuff
869   #ifdef CGIMAGEREF
870                          CGImageRelease(imageRef);
871 +                        CGColorSpaceRelease(colourSpace);
872 +                        CGDataProviderRelease(provider);
873   #endif
874   #ifdef NSBITMAP
875                          [bitmap release];
# Line 658 | Line 881 | static void video_close()
881                  case DISPLAY_SCREEN:
882                          if ( theDisplay && originalMode )
883                          {
884 <                                //CGDisplayShowCursor(theDisplay);
884 >                                if ( singleDisplay )
885 >                                        CGDisplayShowCursor(theDisplay);
886 >                                ShowMenuBar();
887                                  CGDisplaySwitchToMode(theDisplay, originalMode);
888                                  CGDisplayRelease(theDisplay);
889 <                                ShowMenuBar();
889 >                                //[the_win deminiaturize: nil];
890                          }
891                          break;
892  
# Line 677 | Line 902 | static void video_close()
902  
903   void VideoExit(void)
904   {
905 <        video_close();
905 >        // Close displays
906 >        vector<monitor_desc *>::iterator        i, end;
907 >
908 >        end = VideoMonitors.end();
909 >
910 >        for (i = VideoMonitors.begin(); i != end; ++i)
911 >                dynamic_cast<OSX_monitor *>(*i)->video_close();
912 >
913 >        VideoMonitors.clear();
914 >        VideoModes.clear();
915   }
916  
917  
# Line 685 | Line 919 | void VideoExit(void)
919   *  Set palette
920   */
921  
922 < void video_set_palette(uint8 *pal, int num)
922 > void
923 > OSX_monitor::set_palette(uint8 *pal, int num)
924   {
925 <        if ( FULLSCREEN && CGDisplayCanSetPalette(theDisplay)
926 <                                        && ! IsDirectMode(VideoMonitor.mode) )
925 >        if ( [output isFullScreen] && CGDisplayCanSetPalette(theDisplay)
926 >                                                                && ! IsDirectMode(get_current_mode()) )
927          {
928                  CGDirectPaletteRef      CGpal;
929                  CGDisplayErr            err;
# Line 700 | Line 935 | void video_set_palette(uint8 *pal, int n
935                          NSLog(@"Failed to set palette, error = %d", err);
936                  CGPaletteRelease(CGpal);
937          }
938 +
939 + #ifdef CGIMAGEREF
940 +        if ( display_type != DISPLAY_WINDOW )
941 +                return;
942 +
943 +        // To change the palette, we have to regenerate
944 +        // the CGImageRef with the new colour space.
945 +
946 +        CGImageRef                      oldImageRef = imageRef;
947 +        CGColorSpaceRef         oldColourSpace = colourSpace;
948 +
949 +        colourSpace = CGColorSpaceCreateDeviceRGB();
950 +
951 +        if ( depth < 16 )
952 +        {
953 +                CGColorSpaceRef         tempColourSpace = colourSpace;
954 +
955 +                colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, pal);
956 +                CGColorSpaceRelease(tempColourSpace);
957 +        }
958 +
959 +        if ( ! colourSpace )
960 +        {
961 +                ErrorAlert("No valid colour space");
962 +                return;
963 +        }
964 +
965 +        imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace,
966 +  #ifdef CG_USE_ALPHA
967 +                                                         kCGImageAlphaPremultipliedFirst,
968 +  #else
969 +                                                         kCGImageAlphaNoneSkipFirst,
970 +  #endif
971 +                                                         provider,
972 +                                                         NULL,  // colourMap translation table
973 +                                                         NO,    // shouldInterpolate colours?
974 +                                                         kCGRenderingIntentDefault);
975 +        if ( ! imageRef )
976 +        {
977 +                ErrorAlert("Could not create CGImage from CGDataProvider");
978 +                return;
979 +        }
980 +
981 +        unsigned char *offsetBuffer = (unsigned char *) the_buffer;
982 +        offsetBuffer += 1;              // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
983 +
984 +        [output readyToDraw: imageRef
985 +                                 bitmap: offsetBuffer
986 +                         imageWidth: x
987 +                        imageHeight: y];
988 +
989 +        CGColorSpaceRelease(oldColourSpace);
990 +        CGImageRelease(oldImageRef);
991 + #endif
992   }
993  
994  
# Line 707 | Line 996 | void video_set_palette(uint8 *pal, int n
996   *  Switch video mode
997   */
998  
999 < void video_switch_to_mode(const video_mode &mode)
999 > void
1000 > OSX_monitor::switch_to_current_mode(void)
1001   {
1002 <        // Close and reopen display
1003 <        video_close();
1004 <        if (!video_open(mode))
1002 >        video_mode      mode = get_current_mode();
1003 >        char            *failure = NULL;
1004 >
1005 >
1006 >        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));
1007 >        
1008 >        if ( display_type == DISPLAY_SCREEN && originalMode )
1009 >        {
1010 >                D(NSLog(@"About to call CGDisplayBestModeForParameters()"));
1011 >                newMode = CGDisplayBestModeForParameters(theDisplay,
1012 >                                                                                                 bits_from_depth(mode.depth),
1013 >                                                                                                                mode.x, mode.y, NULL);
1014 >                if ( ! newMode )
1015 >                        failure = "Could not find a matching screen mode";
1016 >                else
1017 >                {
1018 >                        D(NSLog(@"About to call CGDisplaySwitchToMode()"));
1019 >                        if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr )
1020 >                                failure = "Could not switch to matching screen mode";
1021 >                }
1022 >
1023 >                // For mouse event processing: update screen height
1024 >                [output startedFullScreen: theDisplay];
1025 >
1026 >                if ( ! failure &&
1027 >                        mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) )
1028 >                {
1029 >                        D(bug("Bytes per row (%d) doesn't match current (%ld)\n",
1030 >                                        mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay)));
1031 >                        mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay);
1032 >                }
1033 >
1034 >                if ( ! failure &&
1035 >                         ! ( the_buffer = CGDisplayBaseAddress(theDisplay) ) )
1036 >                        failure = "Could not get base address of screen";
1037 >
1038 >        }
1039 > #ifdef CGIMAGEREF
1040 >        // Clean up the old CGImageRef stuff
1041 >        else if ( display_type == DISPLAY_WINDOW && imageRef )
1042          {
1043 +                CGImageRef                      oldImageRef             = imageRef;
1044 +                CGColorSpaceRef         oldColourSpace  = colourSpace;
1045 +                CGDataProviderRef       oldProvider             = provider;
1046 +                void                            *oldBuffer              = the_buffer;
1047 +
1048 +                if ( video_open(mode) )
1049 +                {
1050 +                        CGImageRelease(oldImageRef);
1051 +                        CGColorSpaceRelease(oldColourSpace);
1052 +                        CGDataProviderRelease(oldProvider);
1053 +                        free(oldBuffer);
1054 +                }
1055 +                else
1056 +                        failure = "Could not video_open() requested mode";
1057 +        }
1058 + #endif
1059 +        else if ( ! video_open(mode) )
1060 +                failure = "Could not video_open() requested mode";
1061 +
1062 +        if ( ! failure && display_type == DISPLAY_SCREEN )
1063 +        {
1064 +                // Whenever we change screen resolution, the MacOS mouse starts
1065 +                // up in the top left corner. Send real mouse to that location
1066 + //              if ( CGDisplayMoveCursorToPoint(theDisplay, CGPointMake(15,15))
1067 + //                                                                                                              == CGDisplayNoErr )
1068 + //              {
1069 +                        //
1070 +                        [output fullscreenMouseMove];
1071 + //              }
1072 + //              else
1073 + //                      failure = "Could move (jump) cursor on screen";
1074 +        }
1075 +
1076 +        if ( failure )
1077 +        {
1078 +                NSLog(@"In switch_to_current_mode():");
1079 +                NSLog(@"%s.", failure);
1080 +                video_close();
1081                  if ( display_type == DISPLAY_SCREEN )
1082                          ErrorAlert("Cannot switch screen to selected video mode");
1083                  else
1084                          ErrorAlert(STR_OPEN_WINDOW_ERR);
1085                  QuitEmulator();
1086          }
1087 +        else
1088 +                set_mac_frame_buffer(mode);
1089   }
1090  
1091   /*
# Line 744 | Line 1111 | void VideoInterrupt(void)
1111   void VideoRefresh(void)
1112   {
1113   }
1114 +
1115 +
1116 +
1117 + // Deal with a memory access signal referring to the screen.
1118 + // For now, just ignore
1119 + bool Screen_fault_handler(char *a, char *b)
1120 + {
1121 + //      NSLog(@"Got a screen fault %lx %lx", a, b);
1122 + //      [output setNeedsDisplay: YES];
1123 +        return YES;
1124 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines