|
@@ -20,170 +20,171 @@
|
|
|
#import <sys/time.h> /* gettimeofday */
|
|
|
#import <sys/param.h> /* for MAXPATHLEN */
|
|
|
#import <unistd.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.
|
|
|
*/
|
|
|
|
|
|
|
|
|
/* Portions of CPS.h */
|
|
|
struct CPSProcessSerNum {
|
|
|
UInt32 lo;
|
|
|
UInt32 hi;
|
|
|
};
|
|
|
|
|
|
extern "C" OSErr CPSGetCurrentProcess(CPSProcessSerNum* psn);
|
|
|
extern "C" OSErr CPSEnableForegroundOperation(CPSProcessSerNum* psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
|
|
|
extern "C" OSErr CPSSetFrontProcess(CPSProcessSerNum* psn);
|
|
|
|
|
|
/* From Menus.h (according to Xcode Developer Documentation) */
|
|
|
extern "C" void ShowMenuBar();
|
|
|
extern "C" void HideMenuBar();
|
|
|
|
|
|
/* Disables a warning. This is needed since the method exists but has been dropped from the header, supposedly as of 10.4. */
|
|
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
|
|
@interface NSApplication(NSAppleMenu)
|
|
|
- (void)setAppleMenu:(NSMenu *)menu;
|
|
|
@end
|
|
|
#endif
|
|
|
|
|
|
|
|
|
/* Defined in ppc/param.h or i386/param.h included from sys/param.h */
|
|
|
#undef ALIGN
|
|
|
/* Defined in stdbool.h */
|
|
|
#ifndef __cplusplus
|
|
|
# ifndef __BEOS__
|
|
|
# undef bool
|
|
|
# undef false
|
|
|
# undef true
|
|
|
# endif
|
|
|
#endif
|
|
|
|
|
|
|
|
|
#include "../stdafx.h"
|
|
|
#include "../openttd.h"
|
|
|
#include "../debug.h"
|
|
|
#include "../macros.h"
|
|
|
#include "../os/macosx/splash.h"
|
|
|
#include "../variables.h"
|
|
|
#include "../gfx.h"
|
|
|
#include "cocoa_v.h"
|
|
|
#include "cocoa_keys.h"
|
|
|
#include "../blitter/factory.hpp"
|
|
|
#include "../fileio.h"
|
|
|
|
|
|
#undef Point
|
|
|
#undef Rect
|
|
|
|
|
|
/* Subclass of NSWindow to fix genie effect and support resize events */
|
|
|
@interface OTTD_QuartzWindow : NSWindow
|
|
|
- (void)miniaturize:(id)sender;
|
|
|
- (void)display;
|
|
|
- (void)setFrame:(NSRect)frameRect display:(BOOL)flag;
|
|
|
- (void)appDidHide:(NSNotification*)note;
|
|
|
- (void)appWillUnhide:(NSNotification*)note;
|
|
|
- (void)appDidUnhide:(NSNotification*)note;
|
|
|
- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag;
|
|
|
@end
|
|
|
|
|
|
/* Delegate for our NSWindow to send ask for quit on close */
|
|
|
@interface OTTD_QuartzWindowDelegate : NSObject
|
|
|
- (BOOL)windowShouldClose:(id)sender;
|
|
|
@end
|
|
|
|
|
|
@interface OTTDMain : NSObject
|
|
|
@end
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
{
|
|
|
_frame = frame;
|
|
|
}
|
|
|
@end
|
|
|
|
|
|
|
|
|
static void QZ_Draw();
|
|
|
static void QZ_UnsetVideoMode();
|
|
|
static void QZ_UpdatePalette(uint start, uint count);
|
|
|
static void QZ_WarpCursor(int x, int y);
|
|
|
static void QZ_ShowMouse();
|
|
|
static void QZ_HideMouse();
|
|
|
static void CocoaVideoFullScreen(bool full_screen);
|
|
|
|
|
|
|
|
|
static NSAutoreleasePool *_ottd_autorelease_pool;
|
|
|
static OTTDMain *_ottd_main;
|
|
|
|
|
|
|
|
|
static struct CocoaVideoData {
|
|
|
static struct VideoDriver_Cocoa::Data {
|
|
|
bool isset;
|
|
|
bool issetting;
|
|
|
|
|
|
CGDirectDisplayID display_id; /* 0 == main display (only support single display) */
|
|
|
CFDictionaryRef mode; /* current mode of the display */
|
|
|
CFDictionaryRef save_mode; /* original mode of the display */
|
|
|
CFArrayRef mode_list; /* list of available fullscreen modes */
|
|
|
CGDirectPaletteRef palette; /* palette of an 8-bit display */
|
|
|
|
|
|
uint32 device_width;
|
|
|
uint32 device_height;
|
|
|
uint32 device_bpp;
|
|
|
|
|
|
void *realpixels;
|
|
|
uint8 *pixels;
|
|
|
uint32 width;
|
|
|
uint32 height;
|
|
|
uint32 pitch;
|
|
|
bool fullscreen;
|
|
|
|
|
|
unsigned int current_mods;
|
|
|
bool tab_is_down;
|
|
|
bool emulating_right_button;
|
|
|
|
|
|
bool cursor_visible;
|
|
|
bool active;
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
uint32 tEvent;
|
|
|
#endif
|
|
|
|
|
|
OTTD_QuartzWindow *window;
|
|
|
NSQuickDrawView *qdview;
|
|
|
|
|
|
#define MAX_DIRTY_RECTS 100
|
|
|
Rect dirty_rects[MAX_DIRTY_RECTS];
|
|
|
int num_dirty_rects;
|
|
|
|
|
|
uint16 palette16[256];
|
|
|
uint32 palette32[256];
|
|
|
} _cocoa_video_data;
|
|
|
|
|
|
static bool _cocoa_video_started = false;
|
|
|
static bool _cocoa_video_dialog = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -321,97 +322,97 @@ static const VkMapping _vk_mapping[] = {
|
|
|
AS(QZ_KP4, WKC_NUM_4),
|
|
|
AS(QZ_KP5, WKC_NUM_5),
|
|
|
AS(QZ_KP6, WKC_NUM_6),
|
|
|
AS(QZ_KP7, WKC_NUM_7),
|
|
|
AS(QZ_KP8, WKC_NUM_8),
|
|
|
AS(QZ_KP9, WKC_NUM_9),
|
|
|
AS(QZ_KP_DIVIDE, WKC_NUM_DIV),
|
|
|
AS(QZ_KP_MULTIPLY, WKC_NUM_MUL),
|
|
|
AS(QZ_KP_MINUS, WKC_NUM_MINUS),
|
|
|
AS(QZ_KP_PLUS, WKC_NUM_PLUS),
|
|
|
AS(QZ_KP_ENTER, WKC_NUM_ENTER),
|
|
|
AS(QZ_KP_PERIOD, WKC_NUM_DECIMAL)
|
|
|
};
|
|
|
|
|
|
|
|
|
static uint32 QZ_MapKey(unsigned short sym)
|
|
|
{
|
|
|
const VkMapping *map;
|
|
|
uint32 key = 0;
|
|
|
|
|
|
for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
|
|
|
if (sym == map->vk_from) {
|
|
|
key = map->map_to;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (_cocoa_video_data.current_mods & NSShiftKeyMask) key |= WKC_SHIFT;
|
|
|
if (_cocoa_video_data.current_mods & NSControlKeyMask) key |= WKC_CTRL;
|
|
|
if (_cocoa_video_data.current_mods & NSAlternateKeyMask) key |= WKC_ALT;
|
|
|
if (_cocoa_video_data.current_mods & NSCommandKeyMask) key |= WKC_META;
|
|
|
|
|
|
return key << 16;
|
|
|
}
|
|
|
|
|
|
static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down)
|
|
|
{
|
|
|
switch (keycode) {
|
|
|
case QZ_UP: SB(_dirkeys, 1, 1, down); break;
|
|
|
case QZ_DOWN: SB(_dirkeys, 3, 1, down); break;
|
|
|
case QZ_LEFT: SB(_dirkeys, 0, 1, down); break;
|
|
|
case QZ_RIGHT: SB(_dirkeys, 2, 1, down); break;
|
|
|
|
|
|
case QZ_TAB: _cocoa_video_data.tab_is_down = down; break;
|
|
|
|
|
|
case QZ_RETURN:
|
|
|
case QZ_f:
|
|
|
if (down && (_cocoa_video_data.current_mods & NSCommandKeyMask)) {
|
|
|
CocoaVideoFullScreen(!_fullscreen);
|
|
|
_video_driver->ToggleFullscreen(!_fullscreen);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (down) {
|
|
|
uint32 pressed_key = QZ_MapKey(keycode) | unicode;
|
|
|
HandleKeypress(pressed_key);
|
|
|
DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key);
|
|
|
} else {
|
|
|
DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void QZ_DoUnsidedModifiers(unsigned int newMods)
|
|
|
{
|
|
|
const int mapping[] = { QZ_CAPSLOCK, QZ_LSHIFT, QZ_LCTRL, QZ_LALT, QZ_LMETA };
|
|
|
|
|
|
int i;
|
|
|
unsigned int bit;
|
|
|
|
|
|
if (_cocoa_video_data.current_mods == newMods) return;
|
|
|
|
|
|
/* Iterate through the bits, testing each against the current modifiers */
|
|
|
for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
|
|
|
unsigned int currentMask, newMask;
|
|
|
|
|
|
currentMask = _cocoa_video_data.current_mods & bit;
|
|
|
newMask = newMods & bit;
|
|
|
|
|
|
if (currentMask && currentMask != newMask) { /* modifier up event */
|
|
|
/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
|
|
|
if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, YES);
|
|
|
QZ_KeyEvent(mapping[i], 0, NO);
|
|
|
} else if (newMask && currentMask != newMask) { /* modifier down event */
|
|
|
QZ_KeyEvent(mapping[i], 0, YES);
|
|
|
/* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */
|
|
|
if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, NO);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
_cocoa_video_data.current_mods = newMods;
|
|
|
}
|
|
|
|
|
|
static void QZ_MouseMovedEvent(int x, int y)
|
|
|
{
|
|
|
if (_cursor.fix_at) {
|
|
|
int dx = x - _cursor.pos.x;
|
|
|
int dy = y - _cursor.pos.y;
|
|
@@ -1274,99 +1275,99 @@ static uint32 QZ_FadeGammaOut(OTTD_Quart
|
|
|
redTable, greenTable, blueTable
|
|
|
) != CGDisplayNoErr) {
|
|
|
CGDisplayRestoreColorSyncSettings();
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
CSleep(10);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/* Fade the display from black to normal
|
|
|
* Restore previously saved gamma values
|
|
|
*/
|
|
|
static uint32 QZ_FadeGammaIn(const OTTD_QuartzGammaTable* table)
|
|
|
{
|
|
|
CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE];
|
|
|
CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE];
|
|
|
CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE];
|
|
|
float percent;
|
|
|
int j;
|
|
|
|
|
|
memset(redTable, 0, sizeof(redTable));
|
|
|
memset(greenTable, 0, sizeof(greenTable));
|
|
|
memset(blueTable, 0, sizeof(greenTable));
|
|
|
|
|
|
for (percent = 0.0; percent <= 1.0; percent += 0.01) {
|
|
|
for (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(
|
|
|
_cocoa_video_data.display_id, QZ_GAMMA_TABLE_SIZE,
|
|
|
redTable, greenTable, blueTable
|
|
|
) != CGDisplayNoErr) {
|
|
|
CGDisplayRestoreColorSyncSettings();
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
CSleep(10);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static const char* QZ_SetVideoFullScreen(int width, int height)
|
|
|
static const char* QZ_SetVideoToggleFullscreen(int width, int height)
|
|
|
{
|
|
|
const char* errstr = "QZ_SetVideoFullScreen error";
|
|
|
const char* errstr = "QZ_SetVideoToggleFullscreen error";
|
|
|
int exact_match;
|
|
|
CFNumberRef number;
|
|
|
int bpp;
|
|
|
int gamma_error;
|
|
|
OTTD_QuartzGammaTable gamma_table;
|
|
|
NSRect screen_rect;
|
|
|
CGError error;
|
|
|
NSPoint pt;
|
|
|
|
|
|
/* Destroy any previous mode */
|
|
|
if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
|
|
|
|
|
|
/* See if requested mode exists */
|
|
|
_cocoa_video_data.mode = CGDisplayBestModeForParameters(_cocoa_video_data.display_id, 8, width, height, &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) {
|
|
|
number = (const __CFNumber*) CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayBitsPerPixel);
|
|
|
CFNumberGetValue(number, kCFNumberSInt32Type, &bpp);
|
|
|
if (bpp != 8) {
|
|
|
errstr = "Failed to find display resolution";
|
|
|
goto ERR_NO_MATCH;
|
|
|
}
|
|
|
|
|
|
number = (const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayWidth);
|
|
|
CFNumberGetValue(number, kCFNumberSInt32Type, &width);
|
|
|
|
|
|
number = (const __CFNumber*)CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayHeight);
|
|
|
CFNumberGetValue(number, kCFNumberSInt32Type, &height);
|
|
|
}
|
|
|
|
|
|
/* Fade display to zero gamma */
|
|
|
gamma_error = QZ_FadeGammaOut(&gamma_table);
|
|
|
|
|
|
/* Put up the blanking window (a window above all other windows) */
|
|
|
error = CGDisplayCapture(_cocoa_video_data.display_id);
|
|
|
|
|
|
if (CGDisplayNoErr != error) {
|
|
|
errstr = "Failed capturing display";
|
|
|
goto ERR_NO_CAPTURE;
|
|
|
}
|
|
|
|
|
|
/* Do the physical switch */
|
|
|
if (CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.mode) != CGDisplayNoErr) {
|
|
|
errstr = "Failed switching display resolution";
|
|
|
goto ERR_NO_SWITCH;
|
|
|
}
|
|
|
|
|
@@ -1662,97 +1663,97 @@ static void QZ_UpdateVideoModes()
|
|
|
_num_resolutions = j;
|
|
|
}
|
|
|
|
|
|
static void QZ_UnsetVideoMode()
|
|
|
{
|
|
|
if (_cocoa_video_data.fullscreen) {
|
|
|
/* Release fullscreen resources */
|
|
|
OTTD_QuartzGammaTable gamma_table;
|
|
|
int gamma_error;
|
|
|
NSRect screen_rect;
|
|
|
|
|
|
gamma_error = QZ_FadeGammaOut(&gamma_table);
|
|
|
|
|
|
/* Restore original screen resolution/bpp */
|
|
|
CGDisplaySwitchToMode(_cocoa_video_data.display_id, _cocoa_video_data.save_mode);
|
|
|
CGReleaseAllDisplays();
|
|
|
ShowMenuBar();
|
|
|
/* Reset the main screen's rectangle
|
|
|
* See comment in QZ_SetVideoFullscreen for why we do this
|
|
|
*/
|
|
|
screen_rect = NSMakeRect(0,0,_cocoa_video_data.device_width,_cocoa_video_data.device_height);
|
|
|
[ [ NSScreen mainScreen ] setFrame:screen_rect ];
|
|
|
|
|
|
if (!gamma_error) QZ_FadeGammaIn(&gamma_table);
|
|
|
} else {
|
|
|
/* Release window mode resources */
|
|
|
[ _cocoa_video_data.window close ];
|
|
|
_cocoa_video_data.window = nil;
|
|
|
_cocoa_video_data.qdview = nil;
|
|
|
}
|
|
|
|
|
|
free(_cocoa_video_data.pixels);
|
|
|
_cocoa_video_data.pixels = NULL;
|
|
|
|
|
|
/* Signal successful teardown */
|
|
|
_cocoa_video_data.isset = false;
|
|
|
|
|
|
QZ_ShowMouse();
|
|
|
}
|
|
|
|
|
|
|
|
|
static const char* QZ_SetVideoMode(uint width, uint height, bool fullscreen)
|
|
|
{
|
|
|
const char *ret;
|
|
|
|
|
|
_cocoa_video_data.issetting = true;
|
|
|
if (fullscreen) {
|
|
|
/* Setup full screen video */
|
|
|
ret = QZ_SetVideoFullScreen(width, height);
|
|
|
ret = QZ_SetVideoToggleFullscreen(width, height);
|
|
|
} else {
|
|
|
/* Setup windowed video */
|
|
|
ret = QZ_SetVideoWindowed(width, height);
|
|
|
}
|
|
|
_cocoa_video_data.issetting = false;
|
|
|
if (ret != NULL) return ret;
|
|
|
|
|
|
/* Signal successful completion (used internally) */
|
|
|
_cocoa_video_data.isset = true;
|
|
|
|
|
|
/* Tell the game that the resolution has changed */
|
|
|
_screen.width = _cocoa_video_data.width;
|
|
|
_screen.height = _cocoa_video_data.height;
|
|
|
_screen.pitch = _cocoa_video_data.width;
|
|
|
|
|
|
QZ_UpdateVideoModes();
|
|
|
GameSizeChanged();
|
|
|
|
|
|
QZ_InitPalette();
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
static const char* QZ_SetVideoModeAndRestoreOnFailure(uint width, uint height, bool fullscreen)
|
|
|
{
|
|
|
bool wasset = _cocoa_video_data.isset;
|
|
|
uint32 oldwidth = _cocoa_video_data.width;
|
|
|
uint32 oldheight = _cocoa_video_data.height;
|
|
|
bool oldfullscreen = _cocoa_video_data.fullscreen;
|
|
|
const char *ret;
|
|
|
|
|
|
ret = QZ_SetVideoMode(width, height, fullscreen);
|
|
|
if (ret != NULL && wasset) QZ_SetVideoMode(oldwidth, oldheight, oldfullscreen);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
static void QZ_VideoInit()
|
|
|
{
|
|
|
if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 0) error("Can't use a blitter that blits 0 bpp for normal visuals");
|
|
|
|
|
|
memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
|
|
|
|
|
|
/* Initialize the video settings; this data persists between mode switches */
|
|
|
_cocoa_video_data.display_id = kCGDirectMainDisplay;
|
|
|
_cocoa_video_data.save_mode = CGDisplayCurrentMode(_cocoa_video_data.display_id);
|
|
|
_cocoa_video_data.mode_list = CGDisplayAvailableModes(_cocoa_video_data.display_id);
|
|
|
_cocoa_video_data.palette = CGPaletteCreateDefaultColorPalette();
|
|
@@ -1925,178 +1926,171 @@ static void setupWindowMenu()
|
|
|
|
|
|
/* "Minimize" item */
|
|
|
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
|
|
|
[windowMenu addItem:menuItem];
|
|
|
[menuItem release];
|
|
|
|
|
|
/* Put menu into the menubar */
|
|
|
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
|
|
|
[windowMenuItem setSubmenu:windowMenu];
|
|
|
[[NSApp mainMenu] addItem:windowMenuItem];
|
|
|
|
|
|
/* Tell the application object that this is now the window menu */
|
|
|
[NSApp setWindowsMenu:windowMenu];
|
|
|
|
|
|
/* Finally give up our references to the objects */
|
|
|
[windowMenu release];
|
|
|
[windowMenuItem release];
|
|
|
}
|
|
|
|
|
|
static void setupApplication()
|
|
|
{
|
|
|
CPSProcessSerNum PSN;
|
|
|
|
|
|
/* Ensure the application object is initialised */
|
|
|
[NSApplication sharedApplication];
|
|
|
|
|
|
/* Tell the dock about us */
|
|
|
if (!CPSGetCurrentProcess(&PSN) &&
|
|
|
!CPSEnableForegroundOperation(&PSN, 0x03, 0x3C, 0x2C, 0x1103) &&
|
|
|
!CPSSetFrontProcess(&PSN)) {
|
|
|
[NSApplication sharedApplication];
|
|
|
}
|
|
|
|
|
|
/* Set up the menubar */
|
|
|
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
|
|
setApplicationMenu();
|
|
|
setupWindowMenu();
|
|
|
|
|
|
/* Create OTTDMain and make it the app delegate */
|
|
|
_ottd_main = [[OTTDMain alloc] init];
|
|
|
[NSApp setDelegate:_ottd_main];
|
|
|
}
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
* Video driver interface *
|
|
|
******************************************************************************/
|
|
|
|
|
|
static void CocoaVideoStop()
|
|
|
static FVideoDriver_Cocoa iFVideoDriver_Cocoa;
|
|
|
|
|
|
void VideoDriver_Cocoa::Stop()
|
|
|
{
|
|
|
if (!_cocoa_video_started) return;
|
|
|
|
|
|
if (_cocoa_video_data.isset) QZ_UnsetVideoMode();
|
|
|
|
|
|
[_ottd_main release];
|
|
|
|
|
|
_cocoa_video_started = false;
|
|
|
}
|
|
|
|
|
|
static const char *CocoaVideoStart(const char * const *parm)
|
|
|
const char *VideoDriver_Cocoa::Start(const char * const *parm)
|
|
|
{
|
|
|
const char *ret;
|
|
|
|
|
|
if (_cocoa_video_started) return "Already started";
|
|
|
_cocoa_video_started = true;
|
|
|
|
|
|
memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data));
|
|
|
|
|
|
setupApplication();
|
|
|
|
|
|
/* Don't create a window or enter fullscreen if we're just going to show a dialog. */
|
|
|
if (_cocoa_video_dialog) return NULL;
|
|
|
|
|
|
QZ_VideoInit();
|
|
|
|
|
|
ret = QZ_SetVideoMode(_cur_resolution[0], _cur_resolution[1], _fullscreen);
|
|
|
if (ret != NULL) CocoaVideoStop();
|
|
|
if (ret != NULL) VideoDriver_Cocoa::Stop();
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
static void CocoaVideoMakeDirty(int left, int top, int width, int height)
|
|
|
void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height)
|
|
|
{
|
|
|
if (_cocoa_video_data.num_dirty_rects < MAX_DIRTY_RECTS) {
|
|
|
_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].left = left;
|
|
|
_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].top = top;
|
|
|
_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].right = left + width;
|
|
|
_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].bottom = top + height;
|
|
|
}
|
|
|
_cocoa_video_data.num_dirty_rects++;
|
|
|
}
|
|
|
|
|
|
static void CocoaVideoMainLoop()
|
|
|
void VideoDriver_Cocoa::MainLoop()
|
|
|
{
|
|
|
/* Start the main event loop */
|
|
|
[NSApp run];
|
|
|
}
|
|
|
|
|
|
static bool CocoaVideoChangeRes(int w, int h)
|
|
|
bool VideoDriver_Cocoa::ChangeResolution(int w, int h)
|
|
|
{
|
|
|
const char *ret = QZ_SetVideoModeAndRestoreOnFailure((uint)w, (uint)h, _cocoa_video_data.fullscreen);
|
|
|
if (ret != NULL) {
|
|
|
DEBUG(driver, 0, "cocoa_v: CocoaVideoChangeRes failed with message: %s", ret);
|
|
|
DEBUG(driver, 0, "cocoa_v: VideoDriver_Cocoa::ChangeResolution failed with message: %s", ret);
|
|
|
}
|
|
|
|
|
|
return ret == NULL;
|
|
|
}
|
|
|
|
|
|
static void CocoaVideoFullScreen(bool full_screen)
|
|
|
void VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
|
|
|
{
|
|
|
const char *ret = QZ_SetVideoModeAndRestoreOnFailure(_cocoa_video_data.width, _cocoa_video_data.height, full_screen);
|
|
|
if (ret != NULL) {
|
|
|
DEBUG(driver, 0, "cocoa_v: CocoaVideoFullScreen failed with message: %s", ret);
|
|
|
DEBUG(driver, 0, "cocoa_v: VideoDriver_Cocoa::ToggleFullscreen failed with message: %s", ret);
|
|
|
}
|
|
|
|
|
|
_fullscreen = _cocoa_video_data.fullscreen;
|
|
|
}
|
|
|
|
|
|
const HalVideoDriver _cocoa_video_driver = {
|
|
|
CocoaVideoStart,
|
|
|
CocoaVideoStop,
|
|
|
CocoaVideoMakeDirty,
|
|
|
CocoaVideoMainLoop,
|
|
|
CocoaVideoChangeRes,
|
|
|
CocoaVideoFullScreen,
|
|
|
};
|
|
|
|
|
|
|
|
|
/* This is needed since sometimes assert is called before the videodriver is initialized */
|
|
|
void CocoaDialog(const char* title, const char* message, const char* buttonLabel)
|
|
|
{
|
|
|
bool wasstarted;
|
|
|
|
|
|
_cocoa_video_dialog = true;
|
|
|
|
|
|
wasstarted = _cocoa_video_started;
|
|
|
if (!_cocoa_video_started && CocoaVideoStart(NULL) != NULL) {
|
|
|
if (!_cocoa_video_started && VideoDriver_Cocoa::Start(NULL) != NULL) {
|
|
|
fprintf(stderr, "%s: %s\n", title, message);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
|
|
|
|
|
|
if (!wasstarted) CocoaVideoStop();
|
|
|
if (!wasstarted) VideoDriver_Cocoa::Stop();
|
|
|
|
|
|
_cocoa_video_dialog = false;
|
|
|
}
|
|
|
|
|
|
/* This is needed since OS X application bundles do not have a
|
|
|
* current directory and the data files are 'somewhere' in the bundle */
|
|
|
void cocoaSetApplicationBundleDir()
|
|
|
{
|
|
|
char tmp[MAXPATHLEN];
|
|
|
CFURLRef url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
|
|
|
if (CFURLGetFileSystemRepresentation(url, true, (unsigned char*)tmp, MAXPATHLEN)) {
|
|
|
AppendPathSeparator(tmp, lengthof(tmp));
|
|
|
_searchpaths[SP_APPLICATION_BUNDLE_DIR] = strdup(tmp);
|
|
|
} else {
|
|
|
_searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
|
|
|
}
|
|
|
|
|
|
CFRelease(url);
|
|
|
}
|
|
|
|
|
|
/* These are called from main() to prevent a _NSAutoreleaseNoPool error when
|
|
|
* exiting before the cocoa video driver has been loaded
|
|
|
*/
|
|
|
void cocoaSetupAutoreleasePool()
|
|
|
{
|
|
|
_ottd_autorelease_pool = [[NSAutoreleasePool alloc] init];
|
|
|
}
|
|
|
|
|
|
void cocoaReleaseAutoreleasePool()
|
|
|
{
|
|
|
[_ottd_autorelease_pool release];
|
|
|
}
|
|
|
|
|
|
#endif /* WITH_COCOA */
|