src/video/cocoa/fullscreen.mm
branchNewGRF_ports
changeset 6871 5a9dc001e1ad
child 6872 1c4a4a609f85
equal deleted inserted replaced
6870:ca3fd1fbe311 6871:5a9dc001e1ad
       
     1 /* $Id$ */
       
     2 
       
     3 /******************************************************************************
       
     4  *                             Cocoa video driver                             *
       
     5  * Known things left to do:                                                   *
       
     6  *  Scale&copy the old pixel buffer to the new one when switching resolution. *
       
     7  ******************************************************************************/
       
     8 
       
     9 #ifdef WITH_COCOA
       
    10 
       
    11 #define MAC_OS_X_VERSION_MIN_REQUIRED    MAC_OS_X_VERSION_10_3
       
    12 #include <AvailabilityMacros.h>
       
    13 
       
    14 #import <Cocoa/Cocoa.h>
       
    15 #import <sys/time.h> /* gettimeofday */
       
    16 #import <sys/param.h> /* for MAXPATHLEN */
       
    17 #import <unistd.h>
       
    18 
       
    19 /**
       
    20  * Important notice regarding all modifications!!!!!!!
       
    21  * There are certain limitations because the file is objective C++.
       
    22  * gdb has limitations.
       
    23  * C++ and objective C code can't be joined in all cases (classes stuff).
       
    24  * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information.
       
    25  */
       
    26 
       
    27 
       
    28 /* From Menus.h (according to Xcode Developer Documentation) */
       
    29 extern "C" void ShowMenuBar();
       
    30 extern "C" void HideMenuBar();
       
    31 
       
    32 /* Defined in stdbool.h */
       
    33 #ifndef __cplusplus
       
    34 # ifndef __BEOS__
       
    35 #  undef bool
       
    36 #  undef false
       
    37 #  undef true
       
    38 # endif
       
    39 #endif
       
    40 
       
    41 
       
    42 #include "../../stdafx.h"
       
    43 #include "../../debug.h"
       
    44 #include "../../variables.h"
       
    45 #include "cocoa_v.h"
       
    46 
       
    47 #undef Point
       
    48 #undef Rect
       
    49 
       
    50 
       
    51 /* Structure for rez switch gamma fades
       
    52  * We can hide the monitor flicker by setting the gamma tables to 0
       
    53  */
       
    54 #define QZ_GAMMA_TABLE_SIZE 256
       
    55 
       
    56 struct OTTD_QuartzGammaTable {
       
    57 	CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
       
    58 	CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
       
    59 	CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
       
    60 };
       
    61 
       
    62 /* Add methods to get at private members of NSScreen.
       
    63  * Since there is a bug in Apple's screen switching code that does not update
       
    64  * this variable when switching to fullscreen, we'll set it manually (but only
       
    65  * for the main screen).
       
    66  */
       
    67 @interface NSScreen (NSScreenAccess)
       
    68 	- (void) setFrame:(NSRect)frame;
       
    69 @end
       
    70 
       
    71 @implementation NSScreen (NSScreenAccess)
       
    72 - (void) setFrame:(NSRect)frame;
       
    73 {
       
    74 	_frame = frame;
       
    75 }
       
    76 @end
       
    77 
       
    78 
       
    79 class FullscreenSubdriver: public CocoaSubdriver {
       
    80 	int                display_width;
       
    81 	int                display_height;
       
    82 	int                display_depth;
       
    83 	int                screen_pitch;
       
    84 	void*              screen_buffer;
       
    85 	void*              pixel_buffer;
       
    86 
       
    87 	CGDirectDisplayID  display_id;         /* 0 == main display (only support single display) */
       
    88 	CFDictionaryRef    cur_mode;           /* current mode of the display */
       
    89 	CFDictionaryRef    save_mode;          /* original mode of the display */
       
    90 	CGDirectPaletteRef palette;            /* palette of an 8-bit display */
       
    91 
       
    92 	#define MAX_DIRTY_RECTS 100
       
    93 	Rect dirty_rects[MAX_DIRTY_RECTS];
       
    94 	int num_dirty_rects;
       
    95 
       
    96 
       
    97 	/* Gamma functions to try to hide the flash from a rez switch
       
    98 	 * Fade the display from normal to black
       
    99 	 * Save gamma tables for fade back to normal
       
   100 	 */
       
   101 	uint32 FadeGammaOut(OTTD_QuartzGammaTable* table)
       
   102 	{
       
   103 		CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
       
   104 		CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
       
   105 		CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
       
   106 		float percent;
       
   107 		int j;
       
   108 		unsigned int actual;
       
   109 
       
   110 		if (CGGetDisplayTransferByTable(
       
   111 					display_id, QZ_GAMMA_TABLE_SIZE,
       
   112 					table->red, table->green, table->blue, &actual
       
   113 				) != CGDisplayNoErr ||
       
   114 				actual != QZ_GAMMA_TABLE_SIZE) {
       
   115 			return 1;
       
   116 		}
       
   117 
       
   118 		memcpy(redTable,   table->red,   sizeof(redTable));
       
   119 		memcpy(greenTable, table->green, sizeof(greenTable));
       
   120 		memcpy(blueTable,  table->blue,  sizeof(greenTable));
       
   121 
       
   122 		for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
       
   123 			for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
       
   124 				redTable[j]   = redTable[j]   * percent;
       
   125 				greenTable[j] = greenTable[j] * percent;
       
   126 				blueTable[j]  = blueTable[j]  * percent;
       
   127 			}
       
   128 
       
   129 			if (CGSetDisplayTransferByTable(
       
   130 						display_id, QZ_GAMMA_TABLE_SIZE,
       
   131 						redTable, greenTable, blueTable
       
   132 					) != CGDisplayNoErr) {
       
   133 				CGDisplayRestoreColorSyncSettings();
       
   134 				return 1;
       
   135 			}
       
   136 
       
   137 			CSleep(10);
       
   138 		}
       
   139 
       
   140 		return 0;
       
   141 	}
       
   142 
       
   143 	/* Fade the display from black to normal
       
   144 	 * Restore previously saved gamma values
       
   145 	 */
       
   146 	uint32 FadeGammaIn(const OTTD_QuartzGammaTable* table)
       
   147 	{
       
   148 		CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
       
   149 		CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
       
   150 		CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
       
   151 		float percent;
       
   152 		int j;
       
   153 
       
   154 		memset(redTable, 0, sizeof(redTable));
       
   155 		memset(greenTable, 0, sizeof(greenTable));
       
   156 		memset(blueTable, 0, sizeof(greenTable));
       
   157 
       
   158 		for (percent = 0.0; percent <= 1.0; percent += 0.01) {
       
   159 			for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
       
   160 				redTable[j]   = table->red[j]   * percent;
       
   161 				greenTable[j] = table->green[j] * percent;
       
   162 				blueTable[j]  = table->blue[j]  * percent;
       
   163 			}
       
   164 
       
   165 			if (CGSetDisplayTransferByTable(
       
   166 						display_id, QZ_GAMMA_TABLE_SIZE,
       
   167 						redTable, greenTable, blueTable
       
   168 					) != CGDisplayNoErr) {
       
   169 				CGDisplayRestoreColorSyncSettings();
       
   170 				return 1;
       
   171 			}
       
   172 
       
   173 			CSleep(10);
       
   174 		}
       
   175 
       
   176 		return 0;
       
   177 	}
       
   178 
       
   179 	/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
       
   180 	void WaitForVerticalBlank()
       
   181 	{
       
   182 		/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
       
   183 		double refreshRate;
       
   184 		double linesPerSecond;
       
   185 		double target;
       
   186 		double position;
       
   187 		double adjustment;
       
   188 		CFNumberRef refreshRateCFNumber;
       
   189 
       
   190 		refreshRateCFNumber = (const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayRefreshRate);
       
   191 		if (refreshRateCFNumber == NULL) return;
       
   192 
       
   193 		if (CFNumberGetValue(refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) == 0)
       
   194 			return;
       
   195 
       
   196 		if (refreshRate == 0) return;
       
   197 
       
   198 		linesPerSecond = refreshRate * display_height;
       
   199 		target = display_height;
       
   200 
       
   201 		/* Figure out the first delay so we start off about right */
       
   202 		position = CGDisplayBeamPosition(display_id);
       
   203 		if (position > target) position = 0;
       
   204 
       
   205 		adjustment = (target - position) / linesPerSecond;
       
   206 
       
   207 		CSleep((uint32)(adjustment * 1000));
       
   208 	}
       
   209 
       
   210 
       
   211 	bool SetVideoMode(int w, int h)
       
   212 	{
       
   213 		int exact_match;
       
   214 		CFNumberRef number;
       
   215 		int bpp;
       
   216 		int gamma_error;
       
   217 		OTTD_QuartzGammaTable gamma_table;
       
   218 		NSRect screen_rect;
       
   219 		CGError error;
       
   220 		NSPoint pt;
       
   221 
       
   222 		/* Destroy any previous mode */
       
   223 		if (pixel_buffer != NULL) {
       
   224 			free(pixel_buffer);
       
   225 			pixel_buffer = NULL;
       
   226 		}
       
   227 
       
   228 		/* See if requested mode exists */
       
   229 		cur_mode = CGDisplayBestModeForParameters(display_id, display_depth, w, h, &exact_match);
       
   230 
       
   231 		/* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */
       
   232 		if (!exact_match) {
       
   233 			number = (const __CFNumber*) CFDictionaryGetValue(cur_mode, kCGDisplayBitsPerPixel);
       
   234 			CFNumberGetValue(number, kCFNumberSInt32Type, &bpp);
       
   235 			if (bpp != display_depth) {
       
   236 				DEBUG(driver, 0, "Failed to find display resolution");
       
   237 				goto ERR_NO_MATCH;
       
   238 			}
       
   239 
       
   240 			number = (const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayWidth);
       
   241 			CFNumberGetValue(number, kCFNumberSInt32Type, &w);
       
   242 
       
   243 			number = (const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayHeight);
       
   244 			CFNumberGetValue(number, kCFNumberSInt32Type, &h);
       
   245 		}
       
   246 
       
   247 		/* Fade display to zero gamma */
       
   248 		gamma_error = FadeGammaOut(&gamma_table);
       
   249 
       
   250 		/* Put up the blanking window (a window above all other windows) */
       
   251 		error = CGDisplayCapture(display_id);
       
   252 
       
   253 		if (CGDisplayNoErr != error) {
       
   254 			DEBUG(driver, 0, "Failed capturing display");
       
   255 			goto ERR_NO_CAPTURE;
       
   256 		}
       
   257 
       
   258 		/* Do the physical switch */
       
   259 		if (CGDisplaySwitchToMode(display_id, cur_mode) != CGDisplayNoErr) {
       
   260 			DEBUG(driver, 0, "Failed switching display resolution");
       
   261 			goto ERR_NO_SWITCH;
       
   262 		}
       
   263 
       
   264 		screen_buffer = CGDisplayBaseAddress(display_id);
       
   265 		screen_pitch  = CGDisplayBytesPerRow(display_id);
       
   266 
       
   267 		display_width = CGDisplayPixelsWide(display_id);
       
   268 		display_height = CGDisplayPixelsHigh(display_id);
       
   269 
       
   270 		/* Setup double-buffer emulation */
       
   271 		pixel_buffer = malloc(display_width * display_height * display_depth / 8);
       
   272 		if (pixel_buffer == NULL) {
       
   273 			DEBUG(driver, 0, "Failed to allocate memory for double buffering");
       
   274 			goto ERR_DOUBLEBUF;
       
   275 		}
       
   276 
       
   277 		if (display_depth == 8 && !CGDisplayCanSetPalette(display_id)) {
       
   278 			DEBUG(driver, 0, "Not an indexed display mode.");
       
   279 			goto ERR_NOT_INDEXED;
       
   280 		}
       
   281 
       
   282 		/* If we don't hide menu bar, it will get events and interrupt the program */
       
   283 		HideMenuBar();
       
   284 
       
   285 		/* Fade the display to original gamma */
       
   286 		if (!gamma_error) FadeGammaIn(&gamma_table);
       
   287 
       
   288 		/* There is a bug in Cocoa where NSScreen doesn't synchronize
       
   289 		 * with CGDirectDisplay, so the main screen's frame is wrong.
       
   290 		 * As a result, coordinate translation produces incorrect results.
       
   291 		 * We can hack around this bug by setting the screen rect ourselves.
       
   292 		 * This hack should be removed if/when the bug is fixed.
       
   293 		*/
       
   294 		screen_rect = NSMakeRect(0, 0, display_width, display_height);
       
   295 		[ [ NSScreen mainScreen ] setFrame:screen_rect ];
       
   296 
       
   297 
       
   298 		pt = [ NSEvent mouseLocation ];
       
   299 		pt.y = display_height - pt.y;
       
   300 		if (MouseIsInsideView(&pt)) QZ_HideMouse();
       
   301 
       
   302 		UpdatePalette(0, 256);
       
   303 
       
   304 		return true;
       
   305 
       
   306 		/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
       
   307 ERR_NOT_INDEXED:
       
   308 		free(pixel_buffer);
       
   309 		pixel_buffer = NULL;
       
   310 ERR_DOUBLEBUF:
       
   311 		CGDisplaySwitchToMode(display_id, save_mode);
       
   312 ERR_NO_SWITCH:
       
   313 		CGReleaseAllDisplays();
       
   314 ERR_NO_CAPTURE:
       
   315 		if (!gamma_error) FadeGammaIn(&gamma_table);
       
   316 ERR_NO_MATCH:
       
   317 		display_width = 0;
       
   318 		display_height = 0;
       
   319 
       
   320 		return false;
       
   321 	}
       
   322 
       
   323 	void RestoreVideoMode()
       
   324 	{
       
   325 		/* Release fullscreen resources */
       
   326 		OTTD_QuartzGammaTable gamma_table;
       
   327 		int gamma_error;
       
   328 		NSRect screen_rect;
       
   329 
       
   330 		gamma_error = FadeGammaOut(&gamma_table);
       
   331 
       
   332 		/* Restore original screen resolution/bpp */
       
   333 		CGDisplaySwitchToMode(display_id, save_mode);
       
   334 		CGReleaseAllDisplays();
       
   335 		ShowMenuBar();
       
   336 		/* Reset the main screen's rectangle
       
   337 		 * See comment in SetVideoMode for why we do this
       
   338 		 */
       
   339 		screen_rect = NSMakeRect(0, 0, CGDisplayPixelsWide(display_id), CGDisplayPixelsHigh(display_id));
       
   340 		[ [ NSScreen mainScreen ] setFrame:screen_rect ];
       
   341 
       
   342 		QZ_ShowMouse();
       
   343 
       
   344 		/* Destroy the pixel buffer */
       
   345 		if (pixel_buffer != NULL) {
       
   346 			free(pixel_buffer);
       
   347 			pixel_buffer = NULL;
       
   348 		}
       
   349 
       
   350 		if (!gamma_error) FadeGammaIn(&gamma_table);
       
   351 
       
   352 		display_width = 0;
       
   353 		display_height = 0;
       
   354 	}
       
   355 
       
   356 public:
       
   357 	FullscreenSubdriver(int bpp)
       
   358 	{
       
   359 		if (bpp != 8 && bpp != 32) {
       
   360 			error("Cocoa: This video driver only supports 8 and 32 bpp blitters.");
       
   361 		}
       
   362 
       
   363 		/* Initialize the video settings; this data persists between mode switches */
       
   364 		display_id = kCGDirectMainDisplay;
       
   365 		save_mode  = CGDisplayCurrentMode(display_id);
       
   366 
       
   367 		if (bpp == 8) palette = CGPaletteCreateDefaultColorPalette();
       
   368 
       
   369 		display_width  = 0;
       
   370 		display_height = 0;
       
   371 		display_depth  = bpp;
       
   372 		pixel_buffer   = NULL;
       
   373 
       
   374 		num_dirty_rects = MAX_DIRTY_RECTS;
       
   375 	}
       
   376 
       
   377 	virtual ~FullscreenSubdriver()
       
   378 	{
       
   379 		RestoreVideoMode();
       
   380 	}
       
   381 
       
   382 	virtual void Draw()
       
   383 	{
       
   384 		const uint8* src   = (uint8*) pixel_buffer;
       
   385 		uint8* dst         = (uint8*) screen_buffer;
       
   386 		uint pitch         = screen_pitch;
       
   387 		uint width         = display_width;
       
   388 		uint num_dirty     = num_dirty_rects;
       
   389 		uint bytesperpixel = display_depth / 8;
       
   390 		uint i;
       
   391 
       
   392 		/* Check if we need to do anything */
       
   393 		if (num_dirty == 0) return;
       
   394 
       
   395 		if (num_dirty >= MAX_DIRTY_RECTS) {
       
   396 			num_dirty = 1;
       
   397 			dirty_rects[0].left   = 0;
       
   398 			dirty_rects[0].top    = 0;
       
   399 			dirty_rects[0].right  = display_width;
       
   400 			dirty_rects[0].bottom = display_height;
       
   401 		}
       
   402 
       
   403 		WaitForVerticalBlank();
       
   404 		/* Build the region of dirty rectangles */
       
   405 		for (i = 0; i < num_dirty; i++) {
       
   406 			uint y      = dirty_rects[i].top;
       
   407 			uint left   = dirty_rects[i].left;
       
   408 			uint length = dirty_rects[i].right - left;
       
   409 			uint bottom = dirty_rects[i].bottom;
       
   410 
       
   411 			for (; y < bottom; y++) {
       
   412 				memcpy(dst + y * pitch + left * bytesperpixel, src + y * width * bytesperpixel + left * bytesperpixel, length * bytesperpixel);
       
   413 			}
       
   414 		}
       
   415 
       
   416 		num_dirty_rects = 0;
       
   417 	}
       
   418 
       
   419 	virtual void MakeDirty(int left, int top, int width, int height)
       
   420 	{
       
   421 		if (num_dirty_rects < MAX_DIRTY_RECTS) {
       
   422 			dirty_rects[num_dirty_rects].left = left;
       
   423 			dirty_rects[num_dirty_rects].top = top;
       
   424 			dirty_rects[num_dirty_rects].right = left + width;
       
   425 			dirty_rects[num_dirty_rects].bottom = top + height;
       
   426 		}
       
   427 		num_dirty_rects++;
       
   428 	}
       
   429 
       
   430 	virtual void UpdatePalette(uint first_color, uint num_colors)
       
   431 	{
       
   432 		CGTableCount  index;
       
   433 		CGDeviceColor color;
       
   434 
       
   435 		if (display_depth != 8)
       
   436 			return;
       
   437 
       
   438 		for (index = first_color; index < first_color+num_colors; index++) {
       
   439 			/* Clamp colors between 0.0 and 1.0 */
       
   440 			color.red   = _cur_palette[index].r / 255.0;
       
   441 			color.blue  = _cur_palette[index].b / 255.0;
       
   442 			color.green = _cur_palette[index].g / 255.0;
       
   443 
       
   444 			CGPaletteSetColorAtIndex(palette, color, index);
       
   445 		}
       
   446 
       
   447 		CGDisplaySetPalette(display_id, palette);
       
   448 	}
       
   449 
       
   450 	virtual uint ListModes(OTTDPoint* modes, uint max_modes)
       
   451 	{
       
   452 		CFArrayRef mode_list;
       
   453 		CFIndex num_modes;
       
   454 		CFIndex i;
       
   455 		uint count = 0;
       
   456 
       
   457 		mode_list  = CGDisplayAvailableModes(display_id);
       
   458 		num_modes = CFArrayGetCount(mode_list);
       
   459 
       
   460 		/* Build list of modes with the requested bpp */
       
   461 		for (i = 0; i < num_modes && count < max_modes; i++) {
       
   462 			CFDictionaryRef onemode;
       
   463 			CFNumberRef     number;
       
   464 			int bpp;
       
   465 			int intvalue;
       
   466 			bool hasMode;
       
   467 			uint16 width, height;
       
   468 
       
   469 			onemode = (const __CFDictionary*)CFArrayGetValueAtIndex(mode_list, i);
       
   470 			number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayBitsPerPixel);
       
   471 			CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
       
   472 
       
   473 			if (bpp != display_depth) continue;
       
   474 
       
   475 			number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayWidth);
       
   476 			CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
       
   477 			width = (uint16)intvalue;
       
   478 
       
   479 			number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayHeight);
       
   480 			CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue);
       
   481 			height = (uint16)intvalue;
       
   482 
       
   483 			/* Check if mode is already in the list */
       
   484 			{
       
   485 				uint i;
       
   486 				hasMode = false;
       
   487 				for (i = 0; i < count; i++) {
       
   488 					if (modes[i].x == width &&  modes[i].y == height) {
       
   489 						hasMode = true;
       
   490 						break;
       
   491 					}
       
   492 				}
       
   493 			}
       
   494 
       
   495 			if (hasMode) continue;
       
   496 
       
   497 			/* Add mode to the list */
       
   498 			modes[count].x = width;
       
   499 			modes[count].y = height;
       
   500 			count++;
       
   501 		}
       
   502 
       
   503 		/* Sort list smallest to largest */
       
   504 		{
       
   505 			uint i, j;
       
   506 			for (i = 0; i < count; i++) {
       
   507 				for (j = 0; j < count-1; j++) {
       
   508 					if (modes[j].x > modes[j + 1].x || (
       
   509 						modes[j].x == modes[j + 1].x &&
       
   510 						modes[j].y >  modes[j + 1].y
       
   511 						)) {
       
   512 						uint tmpw = modes[j].x;
       
   513 						uint tmph = modes[j].y;
       
   514 
       
   515 						modes[j].x = modes[j + 1].x;
       
   516 						modes[j].y = modes[j + 1].y;
       
   517 
       
   518 						modes[j + 1].x = tmpw;
       
   519 						modes[j + 1].y = tmph;
       
   520 					}
       
   521 				}
       
   522 			}
       
   523 		}
       
   524 
       
   525 		return count;
       
   526 	}
       
   527 
       
   528 	virtual bool ChangeResolution(int w, int h)
       
   529 	{
       
   530 		int old_width  = display_width;
       
   531 		int old_height = display_height;
       
   532 
       
   533 		if (SetVideoMode(w, h))
       
   534 			return true;
       
   535 
       
   536 		if (old_width != 0 && old_height != 0)
       
   537 			SetVideoMode(old_width, old_height);
       
   538 
       
   539 		return false;
       
   540 	}
       
   541 
       
   542 	virtual bool IsFullscreen()
       
   543 	{
       
   544 		return true;
       
   545 	}
       
   546 
       
   547 	virtual int GetWidth()
       
   548 	{
       
   549 		return display_width;
       
   550 	}
       
   551 
       
   552 	virtual int GetHeight()
       
   553 	{
       
   554 		return display_height;
       
   555 	}
       
   556 
       
   557 	virtual void *GetPixelBuffer()
       
   558 	{
       
   559 		return pixel_buffer;
       
   560 	}
       
   561 
       
   562 	/*
       
   563 		Convert local coordinate to window server (CoreGraphics) coordinate.
       
   564 		In fullscreen mode this just means copying the coords.
       
   565 	*/
       
   566 	virtual CGPoint PrivateLocalToCG(NSPoint* p)
       
   567 	{
       
   568 		CGPoint cgp;
       
   569 
       
   570 		cgp.x = p->x;
       
   571 		cgp.y = p->y;
       
   572 
       
   573 		return cgp;
       
   574 	}
       
   575 
       
   576 	virtual NSPoint GetMouseLocation(NSEvent *event)
       
   577 	{
       
   578 		NSPoint pt;
       
   579 
       
   580 		pt = [ NSEvent mouseLocation ];
       
   581 		pt.y = display_height - pt.y;
       
   582 
       
   583 		return pt;
       
   584 	}
       
   585 
       
   586 	virtual bool MouseIsInsideView(NSPoint *pt)
       
   587 	{
       
   588 		return pt->x >= 0 && pt->y >= 0 && pt->x < display_width && pt->y < display_height;
       
   589 	}
       
   590 
       
   591 	virtual bool IsActive()
       
   592 	{
       
   593 		return true;
       
   594 	}
       
   595 };
       
   596 
       
   597 CocoaSubdriver *QZ_CreateFullscreenSubdriver(int width, int height, int bpp)
       
   598 {
       
   599 	FullscreenSubdriver *ret;
       
   600 
       
   601 	ret = new FullscreenSubdriver(bpp);
       
   602 
       
   603 	if (!ret->ChangeResolution(width, height)) {
       
   604 		delete ret;
       
   605 		return NULL;
       
   606 	}
       
   607 
       
   608 	return ret;
       
   609 }
       
   610 
       
   611 #endif /* WITH_COCOA */