diff options
-rw-r--r-- | config.lib | 2 | ||||
-rw-r--r-- | source.list | 1 | ||||
-rw-r--r-- | src/video/cocoa/cocoa_v.h | 2 | ||||
-rw-r--r-- | src/video/cocoa/cocoa_v.mm | 55 | ||||
-rw-r--r-- | src/video/cocoa/fullscreen.mm | 523 |
5 files changed, 8 insertions, 575 deletions
diff --git a/config.lib b/config.lib index 8a5a4b3f3..5226d84af 100644 --- a/config.lib +++ b/config.lib @@ -1652,7 +1652,7 @@ make_cflags_and_ldflags() { if [ "$with_cocoa" != "0" ]; then CFLAGS="$CFLAGS -DWITH_COCOA" - LIBS="$LIBS -F$osx_sdk_path/System/Library/Frameworks -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox" + LIBS="$LIBS -F$osx_sdk_path/System/Library/Frameworks -framework Cocoa -framework AudioUnit -framework AudioToolbox" if [ "$enable_cocoa_quartz" != "0" ]; then CFLAGS="$CFLAGS -DENABLE_COCOA_QUARTZ" diff --git a/source.list b/source.list index a4780f2ef..0143bd952 100644 --- a/source.list +++ b/source.list @@ -1171,7 +1171,6 @@ sound/null_s.cpp #if COCOA video/cocoa/cocoa_v.mm video/cocoa/event.mm - video/cocoa/fullscreen.mm video/cocoa/wnd_quartz.mm music/cocoa_m.cpp sound/cocoa_s.cpp diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h index 74cdc6946..ee8c29c85 100644 --- a/src/video/cocoa/cocoa_v.h +++ b/src/video/cocoa/cocoa_v.h @@ -189,8 +189,6 @@ public: extern CocoaSubdriver *_cocoa_subdriver; -CocoaSubdriver *QZ_CreateFullscreenSubdriver(int width, int height, int bpp); - #ifdef ENABLE_COCOA_QUARTZ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 CocoaSubdriver *QZ_CreateWindowQuartzSubdriver(int width, int height, int bpp); diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 0bda21d25..678fc75be 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -414,37 +414,18 @@ static CocoaSubdriver *QZ_CreateWindowSubdriver(int width, int height, int bpp) */ static CocoaSubdriver *QZ_CreateSubdriver(int width, int height, int bpp, bool fullscreen, bool fallback) { - CocoaSubdriver *ret = NULL; - /* OSX 10.7 allows to toggle fullscreen mode differently */ - if (MacOSVersionIsAtLeast(10, 7, 0)) { - ret = QZ_CreateWindowSubdriver(width, height, bpp); - if (ret != NULL && fullscreen) ret->ToggleFullscreen(); - } -#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) - else { - ret = fullscreen ? QZ_CreateFullscreenSubdriver(width, height, bpp) : QZ_CreateWindowSubdriver(width, height, bpp); - } -#endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) */ + CocoaSubdriver *ret = QZ_CreateWindowSubdriver(width, height, bpp); + if (ret != nullptr && fullscreen) ret->ToggleFullscreen(); - if (ret != NULL) return ret; - if (!fallback) return NULL; + if (ret != nullptr) return ret; + if (!fallback) return nullptr; /* Try again in 640x480 windowed */ DEBUG(driver, 0, "Setting video mode failed, falling back to 640x480 windowed mode."); ret = QZ_CreateWindowSubdriver(640, 480, bpp); - if (ret != NULL) return ret; - -#if defined(_DEBUG) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) - /* This Fullscreen mode crashes on OSX 10.7 */ - if (!MacOSVersionIsAtLeast(10, 7, 0)) { - /* Try fullscreen too when in debug mode */ - DEBUG(driver, 0, "Setting video mode failed, falling back to 640x480 fullscreen mode."); - ret = QZ_CreateFullscreenSubdriver(640, 480, bpp); - if (ret != NULL) return ret; - } -#endif /* defined(_DEBUG) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) */ + if (ret != nullptr) return ret; - return NULL; + return nullptr; } @@ -555,29 +536,7 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen) { assert(_cocoa_subdriver != NULL); - /* For 10.7 and later, we try to toggle using the quartz subdriver. */ - if (_cocoa_subdriver->ToggleFullscreen()) return true; - - bool oldfs = _cocoa_subdriver->IsFullscreen(); - if (full_screen != oldfs) { - int width = _cocoa_subdriver->GetWidth(); - int height = _cocoa_subdriver->GetHeight(); - int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - - delete _cocoa_subdriver; - _cocoa_subdriver = NULL; - - _cocoa_subdriver = QZ_CreateSubdriver(width, height, bpp, full_screen, false); - if (_cocoa_subdriver == NULL) { - _cocoa_subdriver = QZ_CreateSubdriver(width, height, bpp, oldfs, true); - if (_cocoa_subdriver == NULL) error("Cocoa: Failed to create subdriver"); - } - } - - QZ_GameSizeChanged(); - QZ_UpdateVideoModes(); - - return _cocoa_subdriver->IsFullscreen() == full_screen; + return _cocoa_subdriver->ToggleFullscreen(); } /** diff --git a/src/video/cocoa/fullscreen.mm b/src/video/cocoa/fullscreen.mm deleted file mode 100644 index ae4353868..000000000 --- a/src/video/cocoa/fullscreen.mm +++ /dev/null @@ -1,523 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. - */ - -/****************************************************************************** - * Cocoa video driver * - * Known things left to do: * - * Scale© the old pixel buffer to the new one when switching resolution. * - ******************************************************************************/ - -#ifdef WITH_COCOA - -#include "../../stdafx.h" - -#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) - -#define Rect OTTDRect -#define Point OTTDPoint -#import <Cocoa/Cocoa.h> -#undef Rect -#undef Point - -#include "../../debug.h" -#include "../../core/geometry_type.hpp" -#include "../../core/sort_func.hpp" -#include "cocoa_v.h" -#include "../../gfx_func.h" -#include "../../thread.h" -#include "../../os/macosx/macos.h" - -/** - * Important notice regarding all modifications!!!!!!! - * There are certain limitations because the file is objective C++. - * gdb has limitations. - * C++ and objective C code can't be joined in all cases (classes stuff). - * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. - */ - - -/* From Menus.h (according to Xcode Developer Documentation) */ -extern "C" void ShowMenuBar(); -extern "C" void HideMenuBar(); - - -/* Structure for rez switch gamma fades - * We can hide the monitor flicker by setting the gamma tables to 0 - */ -#define QZ_GAMMA_TABLE_SIZE 256 - -struct OTTD_QuartzGammaTable { - CGGammaValue red[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue green[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue blue[QZ_GAMMA_TABLE_SIZE]; -}; - -/* Add methods to get at private members of NSScreen. - * Since there is a bug in Apple's screen switching code that does not update - * this variable when switching to fullscreen, we'll set it manually (but only - * for the main screen). - */ -@interface NSScreen (NSScreenAccess) - - (void) setFrame:(NSRect)frame; -@end - -@implementation NSScreen (NSScreenAccess) -- (void) setFrame:(NSRect)frame -{ -/* The 64 bits libraries don't seem to know about _frame, so this hack won't work. */ -#ifndef __LP64__ - _frame = frame; -#endif -} -@end - -class FullscreenSubdriver : public CocoaSubdriver { - CGDirectDisplayID display_id; ///< 0 == main display (only support single display) - CFDictionaryRef cur_mode; ///< current mode of the display - CFDictionaryRef save_mode; ///< original mode of the display - CGDirectPaletteRef palette; ///< palette of an 8-bit display - - - /* Gamma functions to try to hide the flash from a res switch - * Fade the display from normal to black - * Save gamma tables for fade back to normal - */ - uint32 FadeGammaOut(OTTD_QuartzGammaTable *table) - { - CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE]; - - unsigned int actual; - if (CGGetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, table->red, table->green, table->blue, &actual) != CGDisplayNoErr - || actual != QZ_GAMMA_TABLE_SIZE) { - return 1; - } - - memcpy(redTable, table->red, sizeof(redTable)); - memcpy(greenTable, table->green, sizeof(greenTable)); - memcpy(blueTable, table->blue, sizeof(greenTable)); - - for (float percent = 1.0; percent >= 0.0; percent -= 0.01) { - for (int j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { - redTable[j] = redTable[j] * percent; - greenTable[j] = greenTable[j] * percent; - blueTable[j] = blueTable[j] * percent; - } - - if (CGSetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, redTable, greenTable, blueTable) != CGDisplayNoErr) { - CGDisplayRestoreColorSyncSettings(); - return 1; - } - - CSleep(10); - } - - return 0; - } - - /* Fade the display from black to normal - * Restore previously saved gamma values - */ - uint32 FadeGammaIn(const OTTD_QuartzGammaTable *table) - { - CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE]; - CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE]; - - memset(redTable, 0, sizeof(redTable)); - memset(greenTable, 0, sizeof(greenTable)); - memset(blueTable, 0, sizeof(greenTable)); - - for (float percent = 0.0; percent <= 1.0; percent += 0.01) { - for (int j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { - redTable[j] = table->red[j] * percent; - greenTable[j] = table->green[j] * percent; - blueTable[j] = table->blue[j] * percent; - } - - if (CGSetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, redTable, greenTable, blueTable) != CGDisplayNoErr) { - CGDisplayRestoreColorSyncSettings(); - return 1; - } - - CSleep(10); - } - - return 0; - } - - /** Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */ - void WaitForVerticalBlank() - { - /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */ - - CFNumberRef refreshRateCFNumber = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayRefreshRate); - if (refreshRateCFNumber == NULL) return; - - double refreshRate; - if (CFNumberGetValue(refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) == 0) return; - - if (refreshRate == 0) return; - - double linesPerSecond = refreshRate * this->device_height; - double target = this->device_height; - - /* Figure out the first delay so we start off about right */ - double position = CGDisplayBeamPosition(this->display_id); - if (position > target) position = 0; - - double adjustment = (target - position) / linesPerSecond; - - CSleep((uint32)adjustment * 1000); - } - - - bool SetVideoMode(int w, int h, int bpp) - { - /* Define this variables at the top (against coding style) because - * otherwise GCC 4.2 barfs at the goto's jumping over variable initialization. */ - NSRect screen_rect; - int gamma_error; - NSPoint mouseLocation; - - /* Destroy any previous mode */ - if (this->pixel_buffer != NULL) { - free(this->pixel_buffer); - this->pixel_buffer = NULL; - } - - /* See if requested mode exists */ - boolean_t exact_match; - this->cur_mode = CGDisplayBestModeForParameters(this->display_id, bpp, w, h, &exact_match); - - /* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */ - if (!exact_match) { - int act_bpp; - CFNumberRef number = (const __CFNumber*) CFDictionaryGetValue(this->cur_mode, kCGDisplayBitsPerPixel); - CFNumberGetValue(number, kCFNumberSInt32Type, &act_bpp); - if (act_bpp != bpp) { - DEBUG(driver, 0, "Failed to find display resolution"); - goto ERR_NO_MATCH; - } - - number = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayWidth); - CFNumberGetValue(number, kCFNumberSInt32Type, &w); - - number = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayHeight); - CFNumberGetValue(number, kCFNumberSInt32Type, &h); - } - - /* Capture the main screen */ - CGDisplayCapture(this->display_id); - - /* Store the mouse coordinates relative to the total screen */ - mouseLocation = [ NSEvent mouseLocation ]; - mouseLocation.x /= this->device_width; - mouseLocation.y /= this->device_height; - - /* Fade display to zero gamma */ - OTTD_QuartzGammaTable gamma_table; - gamma_error = this->FadeGammaOut(&gamma_table); - - /* Put up the blanking window (a window above all other windows) */ - if (CGDisplayCapture(this->display_id) != CGDisplayNoErr ) { - DEBUG(driver, 0, "Failed capturing display"); - goto ERR_NO_CAPTURE; - } - - /* Do the physical switch */ - if (CGDisplaySwitchToMode(this->display_id, this->cur_mode) != CGDisplayNoErr) { - DEBUG(driver, 0, "Failed switching display resolution"); - goto ERR_NO_SWITCH; - } - - /* Since CGDisplayBaseAddress and CGDisplayBytesPerRow are no longer available on 10.7, - * disable until a replacement can be found. */ - if (MacOSVersionIsAtLeast(10, 7, 0)) { - this->window_buffer = NULL; - this->window_pitch = 0; - } else { -#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) - this->window_buffer = CGDisplayBaseAddress(this->display_id); - this->window_pitch = CGDisplayBytesPerRow(this->display_id); -#endif - } - - this->device_width = CGDisplayPixelsWide(this->display_id); - this->device_height = CGDisplayPixelsHigh(this->display_id); - this->device_depth = bpp; - - /* Setup double-buffer emulation */ - this->pixel_buffer = malloc(this->device_width * this->device_height * this->device_depth / 8); - if (this->pixel_buffer == NULL) { - DEBUG(driver, 0, "Failed to allocate memory for double buffering"); - goto ERR_DOUBLEBUF; - } - - if (this->device_depth == 8 && !CGDisplayCanSetPalette(this->display_id)) { - DEBUG(driver, 0, "Not an indexed display mode."); - goto ERR_NOT_INDEXED; - } - - /* If we don't hide menu bar, it will get events and interrupt the program */ - HideMenuBar(); - - /* Hide the OS cursor */ - CGDisplayHideCursor(this->display_id); - - /* Fade the display to original gamma */ - if (!gamma_error) FadeGammaIn(&gamma_table); - - /* There is a bug in Cocoa where NSScreen doesn't synchronize - * with CGDirectDisplay, so the main screen's frame is wrong. - * As a result, coordinate translation produces incorrect results. - * We can hack around this bug by setting the screen rect ourselves. - * This hack should be removed if/when the bug is fixed. - */ - screen_rect = NSMakeRect(0, 0, this->device_width, this->device_height); - [ [ NSScreen mainScreen ] setFrame:screen_rect ]; - - this->UpdatePalette(0, 256); - - /* Move the mouse cursor to approx. the same location */ - CGPoint display_mouseLocation; - display_mouseLocation.x = mouseLocation.x * this->device_width; - display_mouseLocation.y = this->device_height - (mouseLocation.y * this->device_height); - - _cursor.in_window = true; - - CGDisplayMoveCursorToPoint(this->display_id, display_mouseLocation); - - return true; - - /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ -ERR_NOT_INDEXED: - free(this->pixel_buffer); - this->pixel_buffer = NULL; -ERR_DOUBLEBUF: - CGDisplaySwitchToMode(this->display_id, this->save_mode); -ERR_NO_SWITCH: - CGReleaseAllDisplays(); -ERR_NO_CAPTURE: - if (!gamma_error) this->FadeGammaIn(&gamma_table); -ERR_NO_MATCH: - this->device_width = 0; - this->device_height = 0; - - return false; - } - - void RestoreVideoMode() - { - /* Release fullscreen resources */ - OTTD_QuartzGammaTable gamma_table; - int gamma_error = this->FadeGammaOut(&gamma_table); - - /* Restore original screen resolution/bpp */ - CGDisplaySwitchToMode(this->display_id, this->save_mode); - - CGReleaseAllDisplays(); - - /* Bring back the cursor */ - CGDisplayShowCursor(this->display_id); - - ShowMenuBar(); - - /* Reset the main screen's rectangle - * See comment in SetVideoMode for why we do this */ - NSRect screen_rect = NSMakeRect(0, 0, CGDisplayPixelsWide(this->display_id), CGDisplayPixelsHigh(this->display_id)); - [ [ NSScreen mainScreen ] setFrame:screen_rect ]; - - /* Destroy the pixel buffer */ - if (this->pixel_buffer != NULL) { - free(this->pixel_buffer); - this->pixel_buffer = NULL; - } - - if (!gamma_error) this->FadeGammaIn(&gamma_table); - - this->device_width = CGDisplayPixelsWide(this->display_id); - this->device_height = CGDisplayPixelsHigh(this->display_id); - } - -public: - FullscreenSubdriver() - { - /* Initialize the video settings; this data persists between mode switches */ - this->display_id = kCGDirectMainDisplay; - this->save_mode = CGDisplayCurrentMode(this->display_id); - - this->palette = CGPaletteCreateDefaultColorPalette(); - - this->device_width = CGDisplayPixelsWide(this->display_id); - this->device_height = CGDisplayPixelsHigh(this->display_id); - this->device_depth = 0; - this->pixel_buffer = NULL; - - this->num_dirty_rects = MAX_DIRTY_RECTS; - } - - virtual ~FullscreenSubdriver() - { - this->RestoreVideoMode(); - } - - virtual void Draw(bool force_update) - { - const uint8 *src = (uint8 *)this->pixel_buffer; - uint8 *dst = (uint8 *)this->window_buffer; - uint pitch = this->window_pitch; - uint width = this->device_width; - uint num_dirty = this->num_dirty_rects; - uint bytesperpixel = this->device_depth / 8; - - /* Check if we need to do anything */ - if (num_dirty == 0) return; - - if (num_dirty >= MAX_DIRTY_RECTS) { - num_dirty = 1; - this->dirty_rects[0].left = 0; - this->dirty_rects[0].top = 0; - this->dirty_rects[0].right = this->device_width; - this->dirty_rects[0].bottom = this->device_height; - } - - WaitForVerticalBlank(); - /* Build the region of dirty rectangles */ - for (uint i = 0; i < num_dirty; i++) { - uint y = this->dirty_rects[i].top; - uint left = this->dirty_rects[i].left; - uint length = this->dirty_rects[i].right - left; - uint bottom = this->dirty_rects[i].bottom; - - for (; y < bottom; y++) { - memcpy(dst + y * pitch + left * bytesperpixel, src + y * width * bytesperpixel + left * bytesperpixel, length * bytesperpixel); - } - } - - this->num_dirty_rects = 0; - } - - virtual void MakeDirty(int left, int top, int width, int height) - { - if (this->num_dirty_rects < MAX_DIRTY_RECTS) { - this->dirty_rects[this->num_dirty_rects].left = left; - this->dirty_rects[this->num_dirty_rects].top = top; - this->dirty_rects[this->num_dirty_rects].right = left + width; - this->dirty_rects[this->num_dirty_rects].bottom = top + height; - } - this->num_dirty_rects++; - } - - virtual void UpdatePalette(uint first_color, uint num_colors) - { - if (this->device_depth != 8) return; - - for (uint32_t index = first_color; index < first_color + num_colors; index++) { - /* Clamp colors between 0.0 and 1.0 */ - CGDeviceColor color; - color.red = _cur_palette.palette[index].r / 255.0; - color.blue = _cur_palette.palette[index].b / 255.0; - color.green = _cur_palette.palette[index].g / 255.0; - - CGPaletteSetColorAtIndex(this->palette, color, index); - } - - CGDisplaySetPalette(this->display_id, this->palette); - } - - virtual uint ListModes(OTTD_Point *modes, uint max_modes) - { - return QZ_ListModes(modes, max_modes, this->display_id, this->device_depth); - } - - virtual bool ChangeResolution(int w, int h, int bpp) - { - int old_width = this->device_width; - int old_height = this->device_height; - int old_bpp = this->device_depth; - - if (bpp != 8 && bpp != 32) error("Cocoa: This video driver only supports 8 and 32 bpp blitters."); - - if (SetVideoMode(w, h, bpp)) return true; - if (old_width != 0 && old_height != 0) SetVideoMode(old_width, old_height, old_bpp); - - return false; - } - - virtual bool IsFullscreen() - { - return true; - } - - virtual int GetWidth() - { - return this->device_width; - } - - virtual int GetHeight() - { - return this->device_height; - } - - virtual void *GetPixelBuffer() - { - return this->pixel_buffer; - } - - /* - * Convert local coordinate to window server (CoreGraphics) coordinate. - * In fullscreen mode this just means copying the coords. - */ - virtual CGPoint PrivateLocalToCG(NSPoint *p) - { - return CGPointMake(p->x, p->y); - } - - virtual NSPoint GetMouseLocation(NSEvent *event) - { - NSPoint pt = [ NSEvent mouseLocation ]; - pt.y = this->device_height - pt.y; - - return pt; - } - - virtual bool MouseIsInsideView(NSPoint *pt) - { - return pt->x >= 0 && pt->y >= 0 && pt->x < this->device_width && pt->y < this->device_height; - } - - virtual bool IsActive() - { - return true; - } -}; - -CocoaSubdriver *QZ_CreateFullscreenSubdriver(int width, int height, int bpp) -{ - /* OSX 10.7 doesn't support this way of the fullscreen driver. If we end up here - * OpenTTD was compiled without SDK 10.7 available and - and thus we don't support - * fullscreen mode in OSX 10.7 or higher, as necessary elements for this way have - * been removed from the API. - */ - if (MacOSVersionIsAtLeast(10, 7, 0)) { - return NULL; - } - - FullscreenSubdriver *ret = new FullscreenSubdriver(); - - if (!ret->ChangeResolution(width, height, bpp)) { - delete ret; - return NULL; - } - - return ret; -} - -#endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) */ -#endif /* WITH_COCOA */ |