2005-12-11 10:25:27 +00:00
/ * $ Id $ * /
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Cocoa video driver *
* Known things left to do : *
* Nothing at the moment . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
# ifdef WITH_COCOA
# import < Cocoa / Cocoa . h >
# import < sys / time . h > / * gettimeofday * /
# import < sys / param . h > / * for MAXPATHLEN * /
# import < unistd . h >
/ * Portions of CPS . h * /
2006-02-18 17:27:06 +00:00
typedef struct CPSProcessSerNum {
UInt32 lo ;
UInt32 hi ;
2005-12-10 11:16:45 +00:00
} CPSProcessSerNum ;
2006-02-18 17:27:06 +00:00
extern OSErr CPSGetCurrentProcess ( CPSProcessSerNum * psn ) ;
extern OSErr CPSEnableForegroundOperation ( CPSProcessSerNum * psn , UInt32 _arg2 , UInt32 _arg3 , UInt32 _arg4 , UInt32 _arg5 ) ;
extern OSErr CPSSetFrontProcess ( CPSProcessSerNum * psn ) ;
2005-12-10 11:16:45 +00:00
/ * From Menus . h ( according to Xcode Developer Documentation ) * /
extern void ShowMenuBar ( void ) ;
extern void HideMenuBar ( void ) ;
/ * Disables a warning . This is needed since the method exists but has been dropped from the header , supposedly as of 10.4 . * /
2005-12-10 23:03:59 +00:00
# if ( MAC_OS _X _VERSION _MAX _ALLOWED >= MAC_OS _X _VERSION _10 _4 )
2005-12-10 11:16:45 +00:00
@ interface NSApplication ( NSAppleMenu )
- ( void ) setAppleMenu : ( NSMenu * ) menu ;
@ end
2005-12-10 23:03:59 +00:00
# endif
2005-12-10 11:16:45 +00:00
/ * 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 "../functions.h"
# include "../gfx.h"
# include "../macros.h"
# include "../sdl.h"
# include "../window.h"
# include "../network.h"
# include "../variables.h"
# include "../os/macosx/splash.h"
# include "cocoa_v.h"
2006-02-18 16:20:50 +00:00
# include "cocoa_keys.h"
2005-12-10 11:16:45 +00:00
# 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
2006-02-18 17:27:06 +00:00
/ * Structure for rez switch gamma fades
* We can hide the monitor flicker by setting the gamma tables to 0
* /
2005-12-10 11:16:45 +00:00
# define QZ_GAMMA _TABLE _SIZE 256
typedef struct {
CGGammaValue red [ QZ_GAMMA _TABLE _SIZE ] ;
CGGammaValue green [ QZ_GAMMA _TABLE _SIZE ] ;
CGGammaValue blue [ QZ_GAMMA _TABLE _SIZE ] ;
} OTTD_QuartzGammaTable ;
2006-02-18 17:27:06 +00:00
/ * 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 ) .
* /
2005-12-10 11:16:45 +00:00
@ interface NSScreen ( NSScreenAccess )
2006-02-18 17:27:06 +00:00
- ( void ) setFrame : ( NSRect ) frame ;
2005-12-10 11:16:45 +00:00
@ end
@ implementation NSScreen ( NSScreenAccess )
- ( void ) setFrame : ( NSRect ) frame ;
{
_frame = frame ;
}
@ end
static void QZ_Draw ( void ) ;
2006-02-18 17:27:06 +00:00
static void QZ_UnsetVideoMode ( void ) ;
2005-12-10 11:16:45 +00:00
static void QZ_UpdatePalette ( uint start , uint count ) ;
2006-02-18 17:27:06 +00:00
static void QZ_WarpCursor ( int x , int y ) ;
static void QZ_ShowMouse ( void ) ;
static void QZ_HideMouse ( void ) ;
2005-12-10 11:16:45 +00:00
static void CocoaVideoFullScreen ( bool full_screen ) ;
static NSAutoreleasePool * _ottd _autorelease _pool ;
static OTTDMain * _ottd _main ;
static struct CocoaVideoData {
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
OTTDRect dirty_rects [ MAX_DIRTY _RECTS ] ;
int num_dirty _rects ;
uint16 palette16 [ 256 ] ;
uint32 palette32 [ 256 ] ;
} _cocoa _video _data ;
2006-01-06 21:27:44 +00:00
static bool _cocoa _video _started = false ;
static bool _cocoa _video _dialog = false ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Game loop and accessories *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
static uint32 GetTick ( void )
{
struct timeval tim ;
gettimeofday ( & tim , NULL ) ;
return tim . tv_usec / 1000 + tim . tv_sec * 1000 ;
}
static void QZ_CheckPaletteAnim ( void )
{
if ( _pal _last _dirty ! = -1 ) {
QZ_UpdatePalette ( _pal _first _dirty , _pal _last _dirty - _pal _first _dirty + 1 ) ;
_pal _last _dirty = -1 ;
}
}
extern void DoExitSave ( void ) ;
static void QZ_AskQuit ( void )
{
if ( _game _mode = = GM_MENU ) { // do not ask to quit on the main screen
_exit _game = true ;
} else if ( _patches . autosave_on _exit ) {
DoExitSave ( ) ;
_exit _game = true ;
2006-02-18 17:27:06 +00:00
} else {
2005-12-10 11:16:45 +00:00
AskExitGame ( ) ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
}
typedef struct VkMapping {
unsigned short vk_from ;
byte map_to ;
} VkMapping ;
# define AS ( x , z ) { x , z }
static const VkMapping _vk _mapping [ ] = {
2006-02-18 17:27:06 +00:00
AS ( QZ_BACKQUOTE , WKC_BACKQUOTE ) , // key left of ' 1 '
AS ( QZ_BACKQUOTE2 , WKC_BACKQUOTE ) , // some keyboards have it on another scancode
2006-01-09 21:14:56 +00:00
2005-12-10 11:16:45 +00:00
// Pageup stuff + up / down
// AM ( SDLK_PAGEUP , SDLK_PAGEDOWN , WKC_PAGEUP , WKC_PAGEDOWN ) , <= === Does this include HOME / END ?
2006-02-18 17:27:06 +00:00
AS ( QZ_PAGEUP , WKC_PAGEUP ) ,
AS ( QZ_PAGEDOWN , WKC_PAGEDOWN ) ,
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
AS ( QZ_UP , WKC_UP ) ,
AS ( QZ_DOWN , WKC_DOWN ) ,
AS ( QZ_LEFT , WKC_LEFT ) ,
AS ( QZ_RIGHT , WKC_RIGHT ) ,
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
AS ( QZ_HOME , WKC_HOME ) ,
AS ( QZ_END , WKC_END ) ,
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
AS ( QZ_INSERT , WKC_INSERT ) ,
AS ( QZ_DELETE , WKC_DELETE ) ,
2005-12-10 11:16:45 +00:00
// Letters . QZ_ [ a - z ] is not in numerical order so we can ' t use AM ( . . . )
2006-02-18 17:27:06 +00:00
AS ( QZ_a , ' A ' ) ,
AS ( QZ_b , ' B ' ) ,
AS ( QZ_c , ' C ' ) ,
AS ( QZ_d , ' D ' ) ,
AS ( QZ_e , ' E ' ) ,
AS ( QZ_f , ' F ' ) ,
AS ( QZ_g , ' G ' ) ,
AS ( QZ_h , ' H ' ) ,
AS ( QZ_i , ' I ' ) ,
AS ( QZ_j , ' J ' ) ,
AS ( QZ_k , ' K ' ) ,
AS ( QZ_l , ' L ' ) ,
AS ( QZ_m , ' M ' ) ,
AS ( QZ_n , ' N ' ) ,
AS ( QZ_o , ' O ' ) ,
AS ( QZ_p , ' P ' ) ,
AS ( QZ_q , ' Q ' ) ,
AS ( QZ_r , ' R ' ) ,
AS ( QZ_s , ' S ' ) ,
AS ( QZ_t , ' T ' ) ,
AS ( QZ_u , ' U ' ) ,
AS ( QZ_v , ' V ' ) ,
AS ( QZ_w , ' W ' ) ,
AS ( QZ_x , ' X ' ) ,
AS ( QZ_y , ' Y ' ) ,
AS ( QZ_z , ' Z ' ) ,
2005-12-10 11:16:45 +00:00
// Same thing for digits
2006-02-18 17:27:06 +00:00
AS ( QZ_0 , ' 0 ' ) ,
AS ( QZ_1 , ' 1 ' ) ,
AS ( QZ_2 , ' 2 ' ) ,
AS ( QZ_3 , ' 3 ' ) ,
AS ( QZ_4 , ' 4 ' ) ,
AS ( QZ_5 , ' 5 ' ) ,
AS ( QZ_6 , ' 6 ' ) ,
AS ( QZ_7 , ' 7 ' ) ,
AS ( QZ_8 , ' 8 ' ) ,
AS ( QZ_9 , ' 9 ' ) ,
AS ( QZ_ESCAPE , WKC_ESC ) ,
AS ( QZ_PAUSE , WKC_PAUSE ) ,
AS ( QZ_BACKSPACE , WKC_BACKSPACE ) ,
AS ( QZ_SPACE , WKC_SPACE ) ,
AS ( QZ_RETURN , WKC_RETURN ) ,
AS ( QZ_TAB , WKC_TAB ) ,
2005-12-10 11:16:45 +00:00
// Function keys
2006-02-18 17:27:06 +00:00
AS ( QZ_F1 , WKC_F1 ) ,
AS ( QZ_F2 , WKC_F2 ) ,
AS ( QZ_F3 , WKC_F3 ) ,
AS ( QZ_F4 , WKC_F4 ) ,
AS ( QZ_F5 , WKC_F5 ) ,
AS ( QZ_F6 , WKC_F6 ) ,
AS ( QZ_F7 , WKC_F7 ) ,
AS ( QZ_F8 , WKC_F8 ) ,
AS ( QZ_F9 , WKC_F9 ) ,
AS ( QZ_F10 , WKC_F10 ) ,
AS ( QZ_F11 , WKC_F11 ) ,
AS ( QZ_F12 , WKC_F12 ) ,
2005-12-10 11:16:45 +00:00
// Numeric part .
2006-02-18 17:27:06 +00:00
AS ( QZ_KP0 , WKC_NUM _0 ) ,
AS ( QZ_KP1 , WKC_NUM _1 ) ,
AS ( QZ_KP2 , WKC_NUM _2 ) ,
AS ( QZ_KP3 , WKC_NUM _3 ) ,
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 )
2005-12-10 11:16:45 +00:00
} ;
static uint32 QZ_MapKey ( unsigned short sym )
{
const VkMapping * map ;
uint32 key = 0 ;
for ( map = _vk _mapping ; map ! = endof ( _vk _mapping ) ; + + map ) {
2006-02-18 17:27:06 +00:00
if ( sym = = map -> vk_from ) {
2005-12-10 11:16:45 +00:00
key = map -> map_to ;
break ;
}
}
2006-02-18 17:27:06 +00:00
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 ;
2005-12-10 11:16:45 +00:00
return key < < 16 ;
}
static void QZ_KeyEvent ( unsigned short keycode , unsigned short unicode , BOOL down )
{
2006-02-18 17:27:06 +00:00
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 ;
2005-12-10 11:16:45 +00:00
case QZ_RETURN :
case QZ_f :
2006-02-18 17:27:06 +00:00
if ( down && (
( _cocoa _video _data . current_mods & NSControlKeyMask ) ||
( _cocoa _video _data . current_mods & NSCommandKeyMask )
) ) {
2005-12-10 11:16:45 +00:00
CocoaVideoFullScreen ( ! _fullscreen ) ;
2006-02-18 17:27:06 +00:00
}
break ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
if ( down ) {
2005-12-10 11:16:45 +00:00
_pressed _key = QZ_MapKey ( keycode ) | unicode ;
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 ) ;
}
}
2006-02-18 17:27:06 +00:00
static void QZ_DoUnsidedModifiers ( unsigned int newMods )
{
2005-12-10 11:16:45 +00:00
const int mapping [ ] = { QZ_CAPSLOCK , QZ_LSHIFT , QZ_LCTRL , QZ_LALT , QZ_LMETA } ;
int i ;
int bit ;
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . current_mods = = newMods ) return ;
2005-12-10 11:16:45 +00:00
/ * 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 ;
2006-02-18 17:27:06 +00:00
if ( currentMask && currentMask ! = newMask ) { / * modifier up event * /
2005-12-10 11:16:45 +00:00
/ * If this was Caps Lock , we need some additional voodoo to make SDL happy ( is this needed in ottd ? ) * /
2006-02-18 17:27:06 +00:00
if ( bit = = NSAlphaShiftKeyMask ) QZ_KeyEvent ( mapping [ i ] , 0 , YES ) ;
2005-12-10 11:16:45 +00:00
QZ_KeyEvent ( mapping [ i ] , 0 , NO ) ;
2006-02-18 17:27:06 +00:00
} else if ( newMask && currentMask ! = newMask ) { / * modifier down event * /
2005-12-10 11:16:45 +00:00
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 ? ) * /
2006-02-18 17:27:06 +00:00
if ( bit = = NSAlphaShiftKeyMask ) QZ_KeyEvent ( mapping [ i ] , 0 , NO ) ;
2005-12-10 11:16:45 +00:00
}
}
_cocoa _video _data . current_mods = newMods ;
}
static void QZ_MouseMovedEvent ( int x , int y )
{
if ( _cursor . fix_at ) {
2006-02-18 17:27:06 +00:00
int dx = x - _cursor . pos . x ;
int dy = y - _cursor . pos . y ;
2005-12-10 11:16:45 +00:00
if ( dx ! = 0 || dy ! = 0 ) {
_cursor . delta . x + = dx ;
_cursor . delta . y + = dy ;
QZ_WarpCursor ( _cursor . pos . x , _cursor . pos . y ) ;
}
} else {
_cursor . delta . x = x - _cursor . pos . x ;
_cursor . delta . y = y - _cursor . pos . y ;
_cursor . pos . x = x ;
_cursor . pos . y = y ;
_cursor . dirty = true ;
}
}
2006-02-18 17:27:06 +00:00
void QZ_MouseButtonEvent ( int button , BOOL down )
2005-12-10 11:16:45 +00:00
{
2006-02-18 17:27:06 +00:00
switch ( button ) {
2005-12-10 11:16:45 +00:00
case 0 :
2006-02-18 17:27:06 +00:00
if ( down ) {
2005-12-10 11:16:45 +00:00
_left _button _down = true ;
} else {
_left _button _down = false ;
_left _button _clicked = false ;
}
break ;
2006-02-18 17:27:06 +00:00
2005-12-10 11:16:45 +00:00
case 1 :
2006-02-18 17:27:06 +00:00
if ( down ) {
2005-12-10 11:16:45 +00:00
_right _button _down = true ;
_right _button _clicked = true ;
} else {
_right _button _down = false ;
}
break ;
}
}
static inline NSPoint QZ_GetMouseLocation ( NSEvent * event )
{
NSPoint pt ;
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
pt = [ NSEvent mouseLocation ] ;
pt . y = _cocoa _video _data . height - pt . y ;
} else {
pt = [ event locationInWindow ] ;
pt = [ _cocoa _video _data . qdview convertPoint : pt fromView : nil ] ;
}
return pt ;
}
static bool QZ_MouseIsInsideView ( NSPoint * pt )
{
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
return pt -> x >= 0 && pt -> y >= 0 && pt -> x < _cocoa _video _data . width && pt -> y < _cocoa _video _data . height ;
2006-02-18 17:27:06 +00:00
} else {
2005-12-10 11:16:45 +00:00
return [ _cocoa _video _data . qdview mouse : * pt inRect : [ _cocoa _video _data . qdview bounds ] ] ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
}
static bool QZ_PollEvent ( void )
{
NSEvent * event ;
NSPoint pt ;
NSString * chars ;
# ifdef _DEBUG
uint32 et0 , et ;
# endif
# ifdef _DEBUG
et0 = GetTick ( ) ;
# endif
event = [ NSApp nextEventMatchingMask : NSAnyEventMask
untilDate : [ NSDate distantPast ]
inMode : NSDefaultRunLoopMode dequeue : YES ] ;
# ifdef _DEBUG
et = GetTick ( ) ;
_cocoa _video _data . tEvent + = et - et0 ;
# endif
2006-02-18 17:27:06 +00:00
if ( event = = nil ) return false ;
if ( ! _cocoa _video _data . active ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
return true ;
}
QZ_DoUnsidedModifiers ( [ event modifierFlags ] ) ;
switch ( [ event type ] ) {
case NSMouseMoved :
case NSOtherMouseDragged :
case NSRightMouseDragged :
case NSLeftMouseDragged :
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) &&
! _cocoa _video _data . emulating_right _button ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
break ;
case NSLeftMouseDown :
2006-02-18 17:27:06 +00:00
if ( ! ( [ event modifierFlags ] & NSCommandKeyMask ) ||
! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
[ NSApp sendEvent : event ] ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
/ * Right mouse button emulation * /
2006-02-18 17:27:06 +00:00
if ( [ event modifierFlags ] & NSCommandKeyMask ) {
2005-12-10 11:16:45 +00:00
_cocoa _video _data . emulating_right _button = true ;
QZ_MouseButtonEvent ( 1 , YES ) ;
2006-02-18 17:27:06 +00:00
} else {
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( 0 , YES ) ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
break ;
2006-02-18 17:27:06 +00:00
2005-12-10 11:16:45 +00:00
case NSLeftMouseUp :
[ NSApp sendEvent : event ] ;
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
/ * Right mouse button emulation * /
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . emulating_right _button ) {
2005-12-10 11:16:45 +00:00
_cocoa _video _data . emulating_right _button = false ;
QZ_MouseButtonEvent ( 1 , NO ) ;
2006-02-18 17:27:06 +00:00
} else {
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( 0 , NO ) ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
break ;
case NSRightMouseDown :
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( 1 , YES ) ;
break ;
2006-02-18 17:27:06 +00:00
2005-12-10 11:16:45 +00:00
case NSRightMouseUp :
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( 1 , NO ) ;
break ;
2006-02-18 17:27:06 +00:00
# if 0
2005-12-10 11:16:45 +00:00
/ * This is not needed since openttd currently only use two buttons * /
case NSOtherMouseDown :
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( [ event buttonNumber ] , YES ) ;
break ;
2006-02-18 17:27:06 +00:00
2005-12-10 11:16:45 +00:00
case NSOtherMouseUp :
pt = QZ_GetMouseLocation ( event ) ;
2006-02-18 17:27:06 +00:00
if ( ! QZ_MouseIsInsideView ( & pt ) ) {
2005-12-10 11:16:45 +00:00
QZ_ShowMouse ( ) ;
[ NSApp sendEvent : event ] ;
break ;
}
QZ_HideMouse ( ) ;
2006-02-18 17:27:06 +00:00
QZ_MouseMovedEvent ( ( int ) pt . x , ( int ) pt . y ) ;
2005-12-10 11:16:45 +00:00
QZ_MouseButtonEvent ( [ event buttonNumber ] , NO ) ;
break ;
2006-02-18 17:27:06 +00:00
# endif
2005-12-10 11:16:45 +00:00
case NSKeyDown :
/ * Quit , hide and minimize * /
2006-02-18 17:27:06 +00:00
switch ( [ event keyCode ] ) {
2005-12-10 11:16:45 +00:00
case QZ_q :
case QZ_h :
case QZ_m :
2006-02-18 17:27:06 +00:00
if ( [ event modifierFlags ] & NSCommandKeyMask ) {
2005-12-10 11:16:45 +00:00
[ NSApp sendEvent : event ] ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
break ;
}
chars = [ event characters ] ;
QZ_KeyEvent ( [ event keyCode ] , [ chars length ] ? [ chars characterAtIndex : 0 ] : 0 , YES ) ;
break ;
case NSKeyUp :
/ * Quit , hide and minimize * /
2006-02-18 17:27:06 +00:00
switch ( [ event keyCode ] ) {
2005-12-10 11:16:45 +00:00
case QZ_q :
case QZ_h :
case QZ_m :
2006-02-18 17:27:06 +00:00
if ( [ event modifierFlags ] & NSCommandKeyMask ) {
2005-12-10 11:16:45 +00:00
[ NSApp sendEvent : event ] ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
break ;
}
chars = [ event characters ] ;
QZ_KeyEvent ( [ event keyCode ] , [ chars length ] ? [ chars characterAtIndex : 0 ] : 0 , NO ) ;
break ;
case NSScrollWheel :
2006-02-18 17:27:06 +00:00
if ( [ event deltaX ] > 0.0 || [ event deltaY ] > 0.0 ) { / * Scroll up * /
2005-12-10 11:16:45 +00:00
_cursor . wheel - - ;
2006-02-18 17:27:06 +00:00
} else { / * Scroll down * /
2005-12-10 11:16:45 +00:00
_cursor . wheel + + ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
break ;
default :
[ NSApp sendEvent : event ] ;
}
return true ;
}
static void QZ_GameLoop ( void )
{
uint32 next_tick = GetTick ( ) + 30 ;
uint32 cur_ticks ;
uint32 pal_tick = 0 ;
# ifdef _DEBUG
uint32 et0 , et , st0 , st ;
# endif
int i ;
DEBUG ( driver , 1 ) ( "cocoa_v: QZ_GameLoop" ) ;
# ifdef _DEBUG
et0 = GetTick ( ) ;
st = 0 ;
# endif
_screen . dst_ptr = _cocoa _video _data . pixels ;
DisplaySplashImage ( ) ;
QZ_CheckPaletteAnim ( ) ;
QZ_Draw ( ) ;
CSleep ( 1 ) ;
2006-02-18 17:27:06 +00:00
for ( i = 0 ; i < 2 ; i + + ) GameLoop ( ) ;
2005-12-10 11:16:45 +00:00
_screen . dst_ptr = _cocoa _video _data . pixels ;
UpdateWindows ( ) ;
QZ_CheckPaletteAnim ( ) ;
QZ_Draw ( ) ;
CSleep ( 1 ) ;
2006-02-18 17:27:06 +00:00
for ( ;; ) {
2005-12-10 11:16:45 +00:00
InteractiveRandom ( ) ; // randomness
while ( QZ_PollEvent ( ) ) { }
2006-02-18 17:27:06 +00:00
if ( _exit _game ) break ;
2005-12-10 11:16:45 +00:00
# if defined ( _DEBUG )
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . current_mods & NSShiftKeyMask )
2005-12-10 11:16:45 +00:00
# else
if ( _cocoa _video _data . tab_is _down )
# endif
{
if ( ! _networking && _game _mode ! = GM_MENU ) _fast _forward | = 2 ;
} else if ( _fast _forward & 2 ) {
_fast _forward = 0 ;
}
cur_ticks = GetTick ( ) ;
if ( ( _fast _forward && ! _pause ) || cur_ticks > next_tick )
next_tick = cur_ticks ;
if ( cur_ticks = = next_tick ) {
next_tick + = 30 ;
_ctrl _pressed = ! ! ( _cocoa _video _data . current_mods & NSControlKeyMask ) ;
_shift _pressed = ! ! ( _cocoa _video _data . current_mods & NSShiftKeyMask ) ;
# ifdef _DEBUG
_dbg _screen _rect = ! ! ( _cocoa _video _data . current_mods & NSAlphaShiftKeyMask ) ;
# endif
GameLoop ( ) ;
_screen . dst_ptr = _cocoa _video _data . pixels ;
UpdateWindows ( ) ;
if ( + + pal_tick > 4 ) {
QZ_CheckPaletteAnim ( ) ;
pal_tick = 1 ;
}
QZ_Draw ( ) ;
} else {
# ifdef _DEBUG
st0 = GetTick ( ) ;
# endif
CSleep ( 1 ) ;
# ifdef _DEBUG
2006-02-18 17:27:06 +00:00
st + = GetTick ( ) - st0 ;
2005-12-10 11:16:45 +00:00
# endif
_screen . dst_ptr = _cocoa _video _data . pixels ;
DrawTextMessage ( ) ;
DrawMouseCursor ( ) ;
QZ_Draw ( ) ;
}
}
# ifdef _DEBUG
et = GetTick ( ) ;
DEBUG ( driver , 1 ) ( "cocoa_v: nextEventMatchingMask took %i ms total" , _cocoa _video _data . tEvent ) ;
2006-02-18 17:27:06 +00:00
DEBUG ( driver , 1 ) ( "cocoa_v: game loop took %i ms total (%i ms without sleep)" , et - et0 , et - et0 - st ) ;
DEBUG ( driver , 1 ) ( "cocoa_v: (nextEventMatchingMask total)/(game loop total) is %f%%" , ( double ) _cocoa _video _data . tEvent / ( double ) ( et - et0 ) * 100 ) ;
DEBUG ( driver , 1 ) ( "cocoa_v: (nextEventMatchingMask total)/(game loop without sleep total) is %f%%" , ( double ) _cocoa _video _data . tEvent / ( double ) ( et - et0 - st ) * 100 ) ;
2005-12-10 11:16:45 +00:00
# endif
}
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Windowed mode *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * This function makes the * game region * of the window 100 % opaque .
* The genie effect uses the alpha component . Otherwise ,
* it doesn ' t seem to matter what value it has .
* /
static void QZ_SetPortAlphaOpaque ( void )
{
2005-12-10 11:16:45 +00:00
if ( _cocoa _video _data . device_bpp = = 32 ) {
2006-02-18 17:27:06 +00:00
uint32 * pixels = ( uint32 * ) _cocoa _video _data . realpixels ;
uint32 rowPixels = _cocoa _video _data . pitch / 4 ;
uint32 i ;
uint32 j ;
2005-12-10 11:16:45 +00:00
for ( i = 0 ; i < _cocoa _video _data . height ; i + + )
for ( j = 0 ; j < _cocoa _video _data . width ; j + + ) {
2006-02-18 17:27:06 +00:00
pixels [ i * rowPixels + j ] | = 0 xFF000000 ;
2005-12-10 11:16:45 +00:00
}
}
}
@ implementation OTTD_QuartzWindow
/ * we override these methods to fix the miniaturize animation / dock icon bug * /
- ( void ) miniaturize : ( id ) sender
{
/ * make the alpha channel opaque so anim won ' t have holes in it * /
QZ_SetPortAlphaOpaque ( ) ;
/ * window is hidden now * /
_cocoa _video _data . active = false ;
QZ_ShowMouse ( ) ;
[ super miniaturize : sender ] ;
}
- ( void ) display
{
2006-02-18 17:27:06 +00:00
/ * This method fires just before the window deminaturizes from the Dock .
* We ' ll save the current visible surface , let the window manager redraw any
* UI elements , and restore the surface . This way , no expose event
* is required , and the deminiaturize works perfectly .
* /
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
QZ_SetPortAlphaOpaque ( ) ;
2005-12-10 11:16:45 +00:00
/ * save current visible surface * /
[ self cacheImageInRect : [ _cocoa _video _data . qdview frame ] ] ;
/ * let the window manager redraw controls , border , etc * /
[ super display ] ;
/ * restore visible surface * /
[ self restoreCachedImage ] ;
/ * window is visible again * /
_cocoa _video _data . active = true ;
}
- ( void ) setFrame : ( NSRect ) frameRect display : ( BOOL ) flag
{
NSRect newViewFrame ;
CGrafPtr thePort ;
[ super setFrame : frameRect display : flag ] ;
/ * Don ' t do anything if the window is currently beign created * /
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . issetting ) return ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . window = = nil ) return ;
2005-12-10 11:16:45 +00:00
newViewFrame = [ _cocoa _video _data . qdview frame ] ;
/ * Update the pixels and pitch * /
thePort = [ _cocoa _video _data . qdview qdPort ] ;
2006-02-18 17:27:06 +00:00
LockPortBits ( thePort ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
_cocoa _video _data . realpixels = GetPixBaseAddr ( GetPortPixMap ( thePort ) ) ;
_cocoa _video _data . pitch = GetPixRowBytes ( GetPortPixMap ( thePort ) ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * _cocoa _video _data . realpixels now points to the window ' s pixels
* We want it to point to the * view ' s * pixels
* /
2005-12-10 11:16:45 +00:00
{
int vOffset = [ _cocoa _video _data . window frame ] . size . height - newViewFrame . size . height - newViewFrame . origin . y ;
int hOffset = newViewFrame . origin . x ;
2006-02-18 17:27:06 +00:00
_cocoa _video _data . realpixels = ( uint8 * ) _cocoa _video _data . realpixels + ( vOffset * _cocoa _video _data . pitch ) + hOffset * ( _cocoa _video _data . device_bpp / 8 ) ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
UnlockPortBits ( thePort ) ;
2005-12-10 11:16:45 +00:00
/ * Allocate new buffer * /
2006-02-18 17:27:06 +00:00
free ( _cocoa _video _data . pixels ) ;
_cocoa _video _data . pixels = ( uint8 * ) malloc ( newViewFrame . size . width * newViewFrame . size . height ) ;
2006-03-18 16:11:29 +00:00
assert ( _cocoa _video _data . pixels ! = NULL ) ;
2005-12-10 11:16:45 +00:00
/ * Tell the game that the resolution changed * /
_cocoa _video _data . width = newViewFrame . size . width ;
_cocoa _video _data . height = newViewFrame . size . height ;
_screen . width = _cocoa _video _data . width ;
_screen . height = _cocoa _video _data . height ;
_screen . pitch = _cocoa _video _data . width ;
GameSizeChanged ( ) ;
/ * Redraw screen * /
_cocoa _video _data . num_dirty _rects = MAX_DIRTY _RECTS ;
}
- ( void ) appDidHide : ( NSNotification * ) note
{
_cocoa _video _data . active = false ;
}
- ( void ) appWillUnhide : ( NSNotification * ) note
{
QZ_SetPortAlphaOpaque ( ) ;
/ * save current visible surface * /
[ self cacheImageInRect : [ _cocoa _video _data . qdview frame ] ] ;
}
- ( void ) appDidUnhide : ( NSNotification * ) note
{
/ * restore cached image , since it may not be current , post expose event too * /
[ self restoreCachedImage ] ;
_cocoa _video _data . active = true ;
}
- ( id ) initWithContentRect : ( NSRect ) contentRect styleMask : ( unsigned int ) styleMask backing : ( NSBackingStoreType ) backingType defer : ( BOOL ) flag
{
/ * Make our window subclass receive these application notifications * /
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( appDidHide : ) name : NSApplicationDidHideNotification object : NSApp ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( appDidUnhide : ) name : NSApplicationDidUnhideNotification object : NSApp ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( appWillUnhide : ) name : NSApplicationWillUnhideNotification object : NSApp ] ;
return [ super initWithContentRect : contentRect styleMask : styleMask backing : backingType defer : flag ] ;
}
@ end
@ implementation OTTD_QuartzWindowDelegate
- ( BOOL ) windowShouldClose : ( id ) sender
{
QZ_AskQuit ( ) ;
return NO ;
}
2006-02-18 17:27:06 +00:00
- ( void ) windowDidBecomeKey : ( NSNotification * ) aNotification
2005-12-10 11:16:45 +00:00
{
_cocoa _video _data . active = true ;
}
2006-02-18 17:27:06 +00:00
- ( void ) windowDidResignKey : ( NSNotification * ) aNotification
2005-12-10 11:16:45 +00:00
{
_cocoa _video _data . active = false ;
}
2006-02-18 17:27:06 +00:00
- ( void ) windowDidBecomeMain : ( NSNotification * ) aNotification
2005-12-10 11:16:45 +00:00
{
_cocoa _video _data . active = true ;
}
2006-02-18 17:27:06 +00:00
- ( void ) windowDidResignMain : ( NSNotification * ) aNotification
2005-12-10 11:16:45 +00:00
{
_cocoa _video _data . active = false ;
}
@ end
static void QZ_UpdateWindowPalette ( uint start , uint count )
{
uint i ;
2006-02-18 17:27:06 +00:00
switch ( _cocoa _video _data . device_bpp ) {
2005-12-10 11:16:45 +00:00
case 32 :
for ( i = start ; i < start + count ; i + + ) {
2006-02-18 17:27:06 +00:00
uint32 clr32 = 0 xff000000 ;
clr32 | = ( uint32 ) _cur _palette [ i ] . r < < 16 ;
clr32 | = ( uint32 ) _cur _palette [ i ] . g < < 8 ;
clr32 | = ( uint32 ) _cur _palette [ i ] . b ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . palette32 [ i ] = clr32 ;
}
break ;
case 16 :
for ( i = start ; i < start + count ; i + + ) {
2006-02-18 17:27:06 +00:00
uint16 clr16 = 0 x0000 ;
clr16 | = ( uint16 ) ( ( _cur _palette [ i ] . r > > 3 ) & 0 x1f ) < < 10 ;
clr16 | = ( uint16 ) ( ( _cur _palette [ i ] . g > > 3 ) & 0 x1f ) < < 5 ;
clr16 | = ( uint16 ) ( ( _cur _palette [ i ] . b > > 3 ) & 0 x1f ) ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . palette16 [ i ] = clr16 ;
}
break ;
}
_cocoa _video _data . num_dirty _rects = MAX_DIRTY _RECTS ;
}
2006-02-19 10:21:01 +00:00
static inline void QZ_WindowBlitIndexedPixelsToView32 ( uint left , uint top , uint right , uint bottom )
2005-12-10 11:16:45 +00:00
{
2006-02-19 10:21:01 +00:00
const uint32 * pal = _cocoa _video _data . palette32 ;
const uint8 * src = _cocoa _video _data . pixels ;
uint32 * dst = ( uint32 * ) _cocoa _video _data . realpixels ;
uint width = _cocoa _video _data . width ;
uint pitch = _cocoa _video _data . pitch / 4 ;
uint x ;
uint y ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
for ( y = top ; y < bottom ; y + + ) {
2006-02-19 10:21:01 +00:00
for ( x = left ; x < right ; x + + ) {
dst [ y * pitch + x ] = pal [ src [ y * width + x ] ] ;
2005-12-10 11:16:45 +00:00
}
}
}
2006-02-19 10:21:01 +00:00
static inline void QZ_WindowBlitIndexedPixelsToView16 ( uint left , uint top , uint right , uint bottom )
2005-12-10 11:16:45 +00:00
{
2006-02-19 10:21:01 +00:00
const uint16 * pal = _cocoa _video _data . palette16 ;
const uint8 * src = _cocoa _video _data . pixels ;
uint16 * dst = ( uint16 * ) _cocoa _video _data . realpixels ;
uint width = _cocoa _video _data . width ;
uint pitch = _cocoa _video _data . pitch / 2 ;
uint x ;
uint y ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
for ( y = top ; y < bottom ; y + + ) {
2006-02-19 10:21:01 +00:00
for ( x = left ; x < right ; x + + ) {
dst [ y * pitch + x ] = pal [ src [ y * width + x ] ] ;
2005-12-10 11:16:45 +00:00
}
}
}
static inline void QZ_WindowBlitIndexedPixelsToView ( int left , int top , int right , int bottom )
{
2006-02-18 17:27:06 +00:00
switch ( _cocoa _video _data . device_bpp ) {
case 32 : QZ_WindowBlitIndexedPixelsToView32 ( left , top , right , bottom ) ; break ;
case 16 : QZ_WindowBlitIndexedPixelsToView16 ( left , top , right , bottom ) ; break ;
2005-12-10 11:16:45 +00:00
}
}
2006-02-18 17:27:06 +00:00
static bool _resize _icon [ ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ,
0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 ,
0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ,
0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 ,
0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ,
0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 ,
0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ,
1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0
2005-12-10 11:16:45 +00:00
} ;
2006-02-18 17:27:06 +00:00
static void QZ_DrawResizeIcon ( void )
{
int xoff = _cocoa _video _data . width - 16 ;
int yoff = _cocoa _video _data . height - 16 ;
int x ;
int y ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
for ( y = 0 ; y < 16 ; y + + ) {
uint16 * trg16 = ( uint16 * ) _cocoa _video _data . realpixels + ( yoff + y ) * _cocoa _video _data . pitch / 2 + xoff ;
uint32 * trg32 = ( uint32 * ) _cocoa _video _data . realpixels + ( yoff + y ) * _cocoa _video _data . pitch / 4 + xoff ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
for ( x = 0 ; x < 16 ; x + + , trg16 + + , trg32 + + ) {
if ( ! _resize _icon [ y * 16 + x ] ) continue ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
switch ( _cocoa _video _data . device_bpp ) {
case 32 : * trg32 = 0 xff000000 ; break ;
case 16 : * trg16 = 0 x0000 ; break ;
2005-12-10 11:16:45 +00:00
}
}
}
}
2006-02-18 17:27:06 +00:00
static void QZ_DrawWindow ( void )
{
2005-12-10 11:16:45 +00:00
int i ;
RgnHandle dirty , temp ;
/ * Check if we need to do anything * /
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . num_dirty _rects = = 0 ||
[ _cocoa _video _data . window isMiniaturized ] ) {
2005-12-10 11:16:45 +00:00
return ;
2006-02-18 17:27:06 +00:00
}
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . num_dirty _rects >= MAX_DIRTY _RECTS ) {
2005-12-10 11:16:45 +00:00
_cocoa _video _data . num_dirty _rects = 1 ;
_cocoa _video _data . dirty_rects [ 0 ] . left = 0 ;
_cocoa _video _data . dirty_rects [ 0 ] . top = 0 ;
_cocoa _video _data . dirty_rects [ 0 ] . right = _cocoa _video _data . width ;
_cocoa _video _data . dirty_rects [ 0 ] . bottom = _cocoa _video _data . height ;
}
2006-02-18 17:27:06 +00:00
dirty = NewRgn ( ) ;
temp = NewRgn ( ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
SetEmptyRgn ( dirty ) ;
2005-12-10 11:16:45 +00:00
/ * Build the region of dirty rectangles * /
for ( i = 0 ; i < _cocoa _video _data . num_dirty _rects ; i + + ) {
2006-02-18 17:27:06 +00:00
QZ_WindowBlitIndexedPixelsToView (
_cocoa _video _data . dirty_rects [ i ] . left ,
_cocoa _video _data . dirty_rects [ i ] . top ,
_cocoa _video _data . dirty_rects [ i ] . right ,
_cocoa _video _data . dirty_rects [ i ] . bottom
) ;
MacSetRectRgn (
temp ,
_cocoa _video _data . dirty_rects [ i ] . left ,
_cocoa _video _data . dirty_rects [ i ] . top ,
_cocoa _video _data . dirty_rects [ i ] . right ,
_cocoa _video _data . dirty_rects [ i ] . bottom
) ;
MacUnionRgn ( dirty , temp , dirty ) ;
2005-12-10 11:16:45 +00:00
}
QZ_DrawResizeIcon ( ) ;
/ * Flush the dirty region * /
2006-02-18 17:27:06 +00:00
QDFlushPortBuffer ( [ _cocoa _video _data . qdview qdPort ] , dirty ) ;
DisposeRgn ( dirty ) ;
DisposeRgn ( temp ) ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . num_dirty _rects = 0 ;
}
extern const char _openttd _revision [ ] ;
2006-02-18 17:27:06 +00:00
static const char * QZ_SetVideoWindowed ( uint width , uint height )
{
2005-12-10 11:16:45 +00:00
char caption [ 50 ] ;
NSString * nsscaption ;
unsigned int style ;
NSRect contentRect ;
BOOL isCustom = NO ;
2006-02-18 17:27:06 +00:00
if ( width > _cocoa _video _data . device_width )
2005-12-10 11:16:45 +00:00
width = _cocoa _video _data . device_width ;
2006-02-18 17:27:06 +00:00
if ( height > _cocoa _video _data . device_height )
2005-12-10 11:16:45 +00:00
height = _cocoa _video _data . device_height ;
_cocoa _video _data . width = width ;
_cocoa _video _data . height = height ;
2006-02-18 17:27:06 +00:00
contentRect = NSMakeRect ( 0 , 0 , width , height ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * Check if we should completely destroy the previous mode
* - If it is fullscreen
* /
if ( _cocoa _video _data . isset && _cocoa _video _data . fullscreen )
QZ_UnsetVideoMode ( ) ;
2005-12-10 11:16:45 +00:00
/ * Check if we should recreate the window * /
if ( _cocoa _video _data . window = = nil ) {
/ * Set the window style * /
style = NSTitledWindowMask ;
2006-02-18 17:27:06 +00:00
style | = ( NSMiniaturizableWindowMask | NSClosableWindowMask ) ;
style | = NSResizableWindowMask ;
2005-12-10 11:16:45 +00:00
/ * Manually create a window , avoids having a nib file resource * /
_cocoa _video _data . window = [ [ OTTD_QuartzWindow alloc ]
initWithContentRect : contentRect
styleMask : style
backing : NSBackingStoreBuffered
defer : NO ] ;
if ( _cocoa _video _data . window = = nil )
return "Could not create the Cocoa window" ;
snprintf ( caption , sizeof ( caption ) , "OpenTTD %s" , _openttd _revision ) ;
2005-12-10 23:03:59 +00:00
nsscaption = [ [ NSString alloc ] initWithCString : caption ] ;
2005-12-10 11:16:45 +00:00
[ _cocoa _video _data . window setTitle : nsscaption ] ;
[ _cocoa _video _data . window setMiniwindowTitle : nsscaption ] ;
[ nsscaption release ] ;
[ _cocoa _video _data . window setAcceptsMouseMovedEvents : YES ] ;
[ _cocoa _video _data . window setViewsNeedDisplay : NO ] ;
[ _cocoa _video _data . window setDelegate : [ [ [ OTTD_QuartzWindowDelegate alloc ] init ] autorelease ] ] ;
2006-02-18 17:27:06 +00:00
} else {
/ * We already have a window , just change its size * /
2005-12-10 11:16:45 +00:00
if ( ! isCustom ) {
[ _cocoa _video _data . window setContentSize : contentRect . size ] ;
[ _cocoa _video _data . qdview setFrameSize : contentRect . size ] ;
}
}
[ _cocoa _video _data . window center ] ;
/ * Only recreate the view if it doesn ' t already exist * /
if ( _cocoa _video _data . qdview = = nil ) {
_cocoa _video _data . qdview = [ [ NSQuickDrawView alloc ] initWithFrame : contentRect ] ;
[ _cocoa _video _data . qdview setAutoresizingMask : NSViewWidthSizable | NSViewHeightSizable ] ;
[ [ _cocoa _video _data . window contentView ] addSubview : _cocoa _video _data . qdview ] ;
[ _cocoa _video _data . qdview release ] ;
[ _cocoa _video _data . window makeKeyAndOrderFront : nil ] ;
}
2006-02-18 17:27:06 +00:00
LockPortBits ( [ _cocoa _video _data . qdview qdPort ] ) ;
_cocoa _video _data . realpixels = GetPixBaseAddr ( GetPortPixMap ( [ _cocoa _video _data . qdview qdPort ] ) ) ;
_cocoa _video _data . pitch = GetPixRowBytes ( GetPortPixMap ( [ _cocoa _video _data . qdview qdPort ] ) ) ;
UnlockPortBits ( [ _cocoa _video _data . qdview qdPort ] ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * _cocoa _video _data . realpixels now points to the window ' s pixels
* We want it to point to the * view ' s * pixels
2005-12-10 11:16:45 +00:00
* /
{
int vOffset = [ _cocoa _video _data . window frame ] . size . height - [ _cocoa _video _data . qdview frame ] . size . height - [ _cocoa _video _data . qdview frame ] . origin . y ;
int hOffset = [ _cocoa _video _data . qdview frame ] . origin . x ;
2006-02-18 17:27:06 +00:00
_cocoa _video _data . realpixels = ( uint8 * ) _cocoa _video _data . realpixels + ( vOffset * _cocoa _video _data . pitch ) + hOffset * ( _cocoa _video _data . device_bpp / 8 ) ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
free ( _cocoa _video _data . pixels ) ;
_cocoa _video _data . pixels = ( uint8 * ) malloc ( width * height ) ;
if ( _cocoa _video _data . pixels = = NULL ) return "Failed to allocate 8-bit buffer" ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . fullscreen = false ;
return NULL ;
}
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fullscreen mode *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
/ * Gamma functions to try to hide the flash from a rez switch
* Fade the display from normal to black
* Save gamma tables for fade back to normal
* /
2006-02-18 18:27:17 +00:00
static uint32 QZ_FadeGammaOut ( OTTD_QuartzGammaTable * table )
2006-02-18 17:27:06 +00:00
{
CGGammaValue redTable [ QZ_GAMMA _TABLE _SIZE ] ;
CGGammaValue greenTable [ QZ_GAMMA _TABLE _SIZE ] ;
CGGammaValue blueTable [ QZ_GAMMA _TABLE _SIZE ] ;
2005-12-10 11:16:45 +00:00
float percent ;
int j ;
unsigned int actual ;
2006-02-18 17:27:06 +00:00
if ( CGGetDisplayTransferByTable (
_cocoa _video _data . display_id , QZ_GAMMA _TABLE _SIZE ,
table -> red , table -> green , table -> blue , & actual
) ! = CGDisplayNoErr ||
actual ! = QZ_GAMMA _TABLE _SIZE ) {
2005-12-10 11:16:45 +00:00
return 1 ;
}
2006-02-18 17:27:06 +00:00
memcpy ( redTable , table -> red , sizeof ( redTable ) ) ;
memcpy ( greenTable , table -> green , sizeof ( greenTable ) ) ;
memcpy ( blueTable , table -> blue , sizeof ( greenTable ) ) ;
2005-12-10 11:16:45 +00:00
for ( percent = 1.0 ; percent >= 0.0 ; percent - = 0.01 ) {
for ( j = 0 ; j < QZ_GAMMA _TABLE _SIZE ; j + + ) {
redTable [ j ] = redTable [ j ] * percent ;
greenTable [ j ] = greenTable [ j ] * percent ;
blueTable [ j ] = blueTable [ j ] * percent ;
}
2006-02-18 17:27:06 +00:00
if ( CGSetDisplayTransferByTable (
_cocoa _video _data . display_id , QZ_GAMMA _TABLE _SIZE ,
redTable , greenTable , blueTable
) ! = CGDisplayNoErr ) {
CGDisplayRestoreColorSyncSettings ( ) ;
return 1 ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
CSleep ( 10 ) ;
2005-12-10 11:16:45 +00:00
}
return 0 ;
}
2006-02-18 17:27:06 +00:00
/ * 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 ] ;
2005-12-10 11:16:45 +00:00
float percent ;
int j ;
2006-02-18 17:27:06 +00:00
memset ( redTable , 0 , sizeof ( redTable ) ) ;
memset ( greenTable , 0 , sizeof ( greenTable ) ) ;
memset ( blueTable , 0 , sizeof ( greenTable ) ) ;
2005-12-10 11:16:45 +00:00
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 ;
}
2006-02-18 17:27:06 +00:00
if ( CGSetDisplayTransferByTable (
_cocoa _video _data . display_id , QZ_GAMMA _TABLE _SIZE ,
redTable , greenTable , blueTable
) ! = CGDisplayNoErr ) {
2005-12-10 11:16:45 +00:00
CGDisplayRestoreColorSyncSettings ( ) ;
return 1 ;
}
CSleep ( 10 ) ;
}
return 0 ;
}
2006-02-18 17:27:06 +00:00
static const char * QZ_SetVideoFullScreen ( int width , int height )
{
const char * errstr = "QZ_SetVideoFullScreen error" ;
2005-12-10 11:16:45 +00:00
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 * /
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . isset ) QZ_UnsetVideoMode ( ) ;
2005-12-10 11:16:45 +00:00
/ * 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 * /
2006-02-18 17:27:06 +00:00
if ( ! exact_match ) {
2005-12-10 11:16:45 +00:00
number = CFDictionaryGetValue ( _cocoa _video _data . mode , kCGDisplayBitsPerPixel ) ;
2006-02-18 17:27:06 +00:00
CFNumberGetValue ( number , kCFNumberSInt32Type , & bpp ) ;
if ( bpp ! = 8 ) {
2005-12-10 11:16:45 +00:00
errstr = "Failed to find display resolution" ;
goto ERR_NO _MATCH ;
}
2006-02-18 17:27:06 +00:00
number = CFDictionaryGetValue ( _cocoa _video _data . mode , kCGDisplayWidth ) ;
CFNumberGetValue ( number , kCFNumberSInt32Type , & width ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
number = CFDictionaryGetValue ( _cocoa _video _data . mode , kCGDisplayHeight ) ;
CFNumberGetValue ( number , kCFNumberSInt32Type , & height ) ;
2005-12-10 11:16:45 +00:00
}
/ * Fade display to zero gamma * /
2006-02-18 17:27:06 +00:00
gamma_error = QZ_FadeGammaOut ( & gamma_table ) ;
2005-12-10 11:16:45 +00:00
/ * Put up the blanking window ( a window above all other windows ) * /
2006-02-18 17:27:06 +00:00
error = CGDisplayCapture ( _cocoa _video _data . display_id ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
if ( CGDisplayNoErr ! = error ) {
2005-12-10 11:16:45 +00:00
errstr = "Failed capturing display" ;
goto ERR_NO _CAPTURE ;
}
/ * Do the physical switch * /
2006-02-18 17:27:06 +00:00
if ( CGDisplaySwitchToMode ( _cocoa _video _data . display_id , _cocoa _video _data . mode ) ! = CGDisplayNoErr ) {
2005-12-10 11:16:45 +00:00
errstr = "Failed switching display resolution" ;
goto ERR_NO _SWITCH ;
}
2006-02-18 17:27:06 +00:00
_cocoa _video _data . realpixels = ( uint8 * ) CGDisplayBaseAddress ( _cocoa _video _data . display_id ) ;
_cocoa _video _data . pitch = CGDisplayBytesPerRow ( _cocoa _video _data . display_id ) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
_cocoa _video _data . width = CGDisplayPixelsWide ( _cocoa _video _data . display_id ) ;
_cocoa _video _data . height = CGDisplayPixelsHigh ( _cocoa _video _data . display_id ) ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . fullscreen = true ;
/ * Setup double - buffer emulation * /
2006-02-18 17:27:06 +00:00
_cocoa _video _data . pixels = ( uint8 * ) malloc ( width * height ) ;
if ( _cocoa _video _data . pixels = = NULL ) {
2005-12-10 11:16:45 +00:00
errstr = "Failed to allocate memory for double buffering" ;
goto ERR_DOUBLEBUF ;
}
2006-02-18 17:27:06 +00:00
if ( ! CGDisplayCanSetPalette ( _cocoa _video _data . display_id ) ) {
2005-12-10 11:16:45 +00:00
errstr = "Not an indexed display mode." ;
goto ERR_NOT _INDEXED ;
}
/ * If we don ' t hide menu bar , it will get events and interrupt the program * /
2006-02-18 17:27:06 +00:00
HideMenuBar ( ) ;
2005-12-10 11:16:45 +00:00
/ * Fade the display to original gamma * /
2006-02-18 17:27:06 +00:00
if ( ! gamma_error ) QZ_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 , width , height ) ;
2005-12-10 11:16:45 +00:00
[ [ NSScreen mainScreen ] setFrame : screen_rect ] ;
/ * we ' re fullscreen , so flag all input states . . . * /
_cocoa _video _data . active = true ;
pt = [ NSEvent mouseLocation ] ;
2006-02-18 17:27:06 +00:00
pt . y = CGDisplayPixelsHigh ( _cocoa _video _data . display_id ) - pt . y ;
if ( QZ_MouseIsInsideView ( & pt ) ) QZ_HideMouse ( ) ;
2005-12-10 11:16:45 +00:00
return NULL ;
/ * Since the blanking window covers * all * windows ( even force quit ) correct recovery is crucial * /
ERR_NOT _INDEXED :
free ( _cocoa _video _data . pixels ) ;
_cocoa _video _data . pixels = NULL ;
ERR_DOUBLEBUF :
2006-02-18 17:27:06 +00:00
CGDisplaySwitchToMode ( _cocoa _video _data . display_id , _cocoa _video _data . save_mode ) ;
2005-12-10 11:16:45 +00:00
ERR_NO _SWITCH :
2006-02-18 17:27:06 +00:00
CGReleaseAllDisplays ( ) ;
2005-12-10 11:16:45 +00:00
ERR_NO _CAPTURE :
2006-02-18 17:27:06 +00:00
if ( ! gamma_error ) QZ_FadeGammaIn ( & gamma_table ) ;
2005-12-10 11:16:45 +00:00
ERR_NO _MATCH :
return errstr ;
}
2006-02-18 17:27:06 +00:00
static void QZ_UpdateFullscreenPalette ( uint first_color , uint num_colors )
{
2005-12-10 11:16:45 +00:00
CGTableCount index ;
CGDeviceColor color ;
for ( index = first_color ; index < first_color + num_colors ; index + + ) {
/ * Clamp colors between 0.0 and 1.0 * /
color . red = _cur _palette [ index ] . r / 255.0 ;
color . blue = _cur _palette [ index ] . b / 255.0 ;
color . green = _cur _palette [ index ] . g / 255.0 ;
2006-02-18 17:27:06 +00:00
CGPaletteSetColorAtIndex ( _cocoa _video _data . palette , color , index ) ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
CGDisplaySetPalette ( _cocoa _video _data . display_id , _cocoa _video _data . palette ) ;
2005-12-10 11:16:45 +00:00
}
/ * Wait for the VBL to occur ( estimated since we don ' t have a hardware interrupt ) * /
static void QZ_WaitForVerticalBlank ( void )
{
/ * The VBL delay is based on Ian Ollmann ' s RezLib < iano @ cco . caltech . edu > * /
double refreshRate ;
double linesPerSecond ;
double target ;
double position ;
double adjustment ;
CFNumberRef refreshRateCFNumber ;
2006-02-18 17:27:06 +00:00
refreshRateCFNumber = CFDictionaryGetValue ( _cocoa _video _data . mode , kCGDisplayRefreshRate ) ;
if ( refreshRateCFNumber = = NULL ) return ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
if ( CFNumberGetValue ( refreshRateCFNumber , kCFNumberDoubleType , & refreshRate ) = = 0 )
2005-12-10 11:16:45 +00:00
return ;
2006-02-18 17:27:06 +00:00
if ( refreshRate = = 0 ) return ;
2005-12-10 11:16:45 +00:00
linesPerSecond = refreshRate * _cocoa _video _data . height ;
target = _cocoa _video _data . height ;
/ * Figure out the first delay so we start off about right * /
2006-02-18 17:27:06 +00:00
position = CGDisplayBeamPosition ( _cocoa _video _data . display_id ) ;
if ( position > target ) position = 0 ;
2005-12-10 11:16:45 +00:00
adjustment = ( target - position ) / linesPerSecond ;
2006-02-18 17:27:06 +00:00
CSleep ( ( uint32 ) ( adjustment * 1000 ) ) ;
2005-12-10 11:16:45 +00:00
}
static void QZ_DrawScreen ( void )
{
2006-02-19 10:21:01 +00:00
const uint8 * src ;
uint8 * dst ;
uint height ;
uint width ;
uint pitch ;
2005-12-10 11:16:45 +00:00
uint y ;
2006-03-25 07:22:53 +00:00
uint num_dirty _rects ;
uint length_drawn ;
uint left ;
uint i ;
2005-12-10 11:16:45 +00:00
2006-02-19 10:21:01 +00:00
src = _cocoa _video _data . pixels ;
dst = ( uint8 * ) _cocoa _video _data . realpixels ;
width = _cocoa _video _data . width ;
pitch = _cocoa _video _data . pitch ;
2006-03-25 07:22:53 +00:00
num_dirty _rects = _cocoa _video _data . num_dirty _rects ;
2006-02-24 22:05:20 +00:00
2006-03-25 07:22:53 +00:00
/ * Check if we need to do anything * /
if ( num_dirty _rects = = 0 ) return ;
2006-02-24 22:05:20 +00:00
2006-03-25 07:22:53 +00:00
if ( num_dirty _rects >= MAX_DIRTY _RECTS ) {
num_dirty _rects = 1 ;
_cocoa _video _data . dirty_rects [ 0 ] . left = 0 ;
_cocoa _video _data . dirty_rects [ 0 ] . top = 0 ;
_cocoa _video _data . dirty_rects [ 0 ] . right = _cocoa _video _data . width ;
_cocoa _video _data . dirty_rects [ 0 ] . bottom = _cocoa _video _data . height ;
}
2006-02-24 22:05:20 +00:00
2006-03-25 07:22:53 +00:00
QZ_WaitForVerticalBlank ( ) ;
/ * Build the region of dirty rectangles * /
for ( i = 0 ; i < num_dirty _rects ; i + + ) {
2006-02-24 22:05:20 +00:00
2006-03-25 07:22:53 +00:00
y = _cocoa _video _data . dirty_rects [ i ] . top ;
left = _cocoa _video _data . dirty_rects [ i ] . left ;
length_drawn = _cocoa _video _data . dirty_rects [ i ] . right - left ;
height = _cocoa _video _data . dirty_rects [ i ] . bottom ;
for ( ; y < height ; y + + ) memcpy ( dst + y * pitch + left , src + y * width + left , length_drawn ) ;
2006-02-24 22:05:20 +00:00
}
2006-03-25 07:22:53 +00:00
_cocoa _video _data . num_dirty _rects = 0 ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
static int QZ_ListFullscreenModes ( OTTDPoint * mode_list , int max_modes )
{
2005-12-10 11:16:45 +00:00
CFIndex num_modes ;
CFIndex i ;
int list_size = 0 ;
2006-02-18 17:27:06 +00:00
num_modes = CFArrayGetCount ( _cocoa _video _data . mode_list ) ;
2005-12-10 11:16:45 +00:00
/ * Build list of modes with the requested bpp * /
for ( i = 0 ; i < num_modes && list_size < max_modes ; i + + ) {
CFDictionaryRef onemode ;
CFNumberRef number ;
int bpp ;
int intvalue ;
bool hasMode ;
uint16 width , height ;
2006-02-18 17:27:06 +00:00
onemode = CFArrayGetValueAtIndex ( _cocoa _video _data . mode_list , i ) ;
number = CFDictionaryGetValue ( onemode , kCGDisplayBitsPerPixel ) ;
2005-12-10 11:16:45 +00:00
CFNumberGetValue ( number , kCFNumberSInt32Type , & bpp ) ;
2006-02-18 17:27:06 +00:00
if ( bpp ! = 8 ) continue ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
number = CFDictionaryGetValue ( onemode , kCGDisplayWidth ) ;
CFNumberGetValue ( number , kCFNumberSInt32Type , & intvalue ) ;
width = ( uint16 ) intvalue ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
number = CFDictionaryGetValue ( onemode , kCGDisplayHeight ) ;
CFNumberGetValue ( number , kCFNumberSInt32Type , & intvalue ) ;
height = ( uint16 ) intvalue ;
2005-12-10 11:16:45 +00:00
/ * Check if mode is already in the list * /
{
int i ;
hasMode = false ;
for ( i = 0 ; i < list_size ; i + + ) {
if ( mode_list [ i ] . x = = width && mode_list [ i ] . y = = height ) {
hasMode = true ;
break ;
}
}
}
2006-02-18 17:27:06 +00:00
if ( hasMode ) continue ;
2005-12-10 11:16:45 +00:00
/ * Add mode to the list * /
mode_list [ list_size ] . x = width ;
mode_list [ list_size ] . y = height ;
list_size + + ;
}
/ * Sort list smallest to largest * /
{
int i , j ;
for ( i = 0 ; i < list_size ; i + + ) {
for ( j = 0 ; j < list_size -1 ; j + + ) {
2006-02-18 17:27:06 +00:00
if ( mode_list [ j ] . x > mode_list [ j + 1 ] . x || (
mode_list [ j ] . x = = mode_list [ j + 1 ] . x &&
mode_list [ j ] . y > mode_list [ j + 1 ] . y
) ) {
2005-12-10 11:16:45 +00:00
uint tmpw = mode_list [ j ] . x ;
uint tmph = mode_list [ j ] . y ;
2006-02-18 17:27:06 +00:00
mode_list [ j ] . x = mode_list [ j + 1 ] . x ;
mode_list [ j ] . y = mode_list [ j + 1 ] . y ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
mode_list [ j + 1 ] . x = tmpw ;
mode_list [ j + 1 ] . y = tmph ;
2005-12-10 11:16:45 +00:00
}
}
}
}
return list_size ;
}
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Windowed and fullscreen common code *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
static void QZ_UpdatePalette ( uint start , uint count )
{
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
QZ_UpdateFullscreenPalette ( start , count ) ;
} else {
QZ_UpdateWindowPalette ( start , count ) ;
}
}
static void QZ_InitPalette ( void )
{
QZ_UpdatePalette ( 0 , 256 ) ;
}
static void QZ_Draw ( void )
{
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
QZ_DrawScreen ( ) ;
} else {
QZ_DrawWindow ( ) ;
}
}
static const OTTDPoint _default _resolutions [ ] = {
{ 640 , 480 } ,
{ 800 , 600 } ,
{ 1024 , 768 } ,
{ 1152 , 864 } ,
{ 1280 , 800 } ,
{ 1280 , 960 } ,
{ 1280 , 1024 } ,
{ 1400 , 1050 } ,
{ 1600 , 1200 } ,
{ 1680 , 1050 } ,
{ 1920 , 1200 }
} ;
static void QZ_UpdateVideoModes ( void )
{
uint i , j , count ;
OTTDPoint modes [ 32 ] ;
const OTTDPoint * current_modes ;
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
count = QZ_ListFullscreenModes ( modes , 32 ) ;
current_modes = modes ;
} else {
count = lengthof ( _default _resolutions ) ;
current_modes = _default _resolutions ;
}
2006-02-18 17:27:06 +00:00
for ( i = 0 , j = 0 ; j < lengthof ( _resolutions ) && i < count ; i + + ) {
if ( _cocoa _video _data . fullscreen || (
2006-03-24 09:47:50 +00:00
( uint ) current_modes [ i ] . x < _cocoa _video _data . device_width &&
( uint ) current_modes [ i ] . y < _cocoa _video _data . device_height )
2006-02-18 17:27:06 +00:00
) {
2005-12-10 11:16:45 +00:00
_resolutions [ j ] [ 0 ] = current_modes [ i ] . x ;
_resolutions [ j ] [ 1 ] = current_modes [ i ] . y ;
j + + ;
}
}
_num _resolutions = j ;
}
2006-02-18 17:27:06 +00:00
static void QZ_UnsetVideoMode ( void )
{
if ( _cocoa _video _data . fullscreen ) {
/ * Release fullscreen resources * /
2005-12-10 11:16:45 +00:00
OTTD_QuartzGammaTable gamma_table ;
int gamma_error ;
NSRect screen_rect ;
2006-02-18 17:27:06 +00:00
gamma_error = QZ_FadeGammaOut ( & gamma_table ) ;
2005-12-10 11:16:45 +00:00
/ * Restore original screen resolution / bpp * /
2006-02-18 17:27:06 +00:00
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
* /
2005-12-10 11:16:45 +00:00
screen_rect = NSMakeRect ( 0 , 0 , _cocoa _video _data . device_width , _cocoa _video _data . device_height ) ;
[ [ NSScreen mainScreen ] setFrame : screen_rect ] ;
2006-02-18 17:27:06 +00:00
if ( ! gamma_error ) QZ_FadeGammaIn ( & gamma_table ) ;
} else {
/ * Release window mode resources * /
2005-12-10 11:16:45 +00:00
[ _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 ;
2006-03-24 10:17:39 +00:00
QZ_ShowMouse ( ) ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
static const char * QZ_SetVideoMode ( uint width , uint height , bool fullscreen )
{
2005-12-10 11:16:45 +00:00
const char * ret ;
2006-02-18 17:27:06 +00:00
_cocoa _video _data . issetting = true ;
if ( fullscreen ) {
/ * Setup full screen video * /
ret = QZ_SetVideoFullScreen ( width , height ) ;
} else {
/ * Setup windowed video * /
ret = QZ_SetVideoWindowed ( width , height ) ;
2005-12-10 11:16:45 +00:00
}
2006-02-18 17:27:06 +00:00
_cocoa _video _data . issetting = false ;
if ( ret ! = NULL ) return ret ;
2005-12-10 11:16:45 +00:00
/ * 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 ;
}
2006-02-18 17:27:06 +00:00
static const char * QZ_SetVideoModeAndRestoreOnFailure ( uint width , uint height , bool fullscreen )
2005-12-10 11:16:45 +00:00
{
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 ) ;
2006-02-18 17:27:06 +00:00
if ( ret ! = NULL && wasset ) QZ_SetVideoMode ( oldwidth , oldheight , oldfullscreen ) ;
2005-12-10 11:16:45 +00:00
return ret ;
}
2006-02-18 17:27:06 +00:00
static void QZ_VideoInit ( void )
{
2005-12-10 11:16:45 +00:00
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 ;
2006-02-18 17:27:06 +00:00
_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 ( ) ;
2005-12-10 11:16:45 +00:00
/ * Gather some information that is useful to know about the display * /
/ * Maybe this should be moved to QZ_SetVideoMode , in case this is changed after startup * /
2006-02-18 17:27:06 +00:00
CFNumberGetValue (
CFDictionaryGetValue ( _cocoa _video _data . save_mode , kCGDisplayBitsPerPixel ) ,
kCFNumberSInt32Type , & _cocoa _video _data . device_bpp
) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
CFNumberGetValue (
CFDictionaryGetValue ( _cocoa _video _data . save_mode , kCGDisplayWidth ) ,
kCFNumberSInt32Type , & _cocoa _video _data . device_width
) ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
CFNumberGetValue (
CFDictionaryGetValue ( _cocoa _video _data . save_mode , kCGDisplayHeight ) ,
kCFNumberSInt32Type , & _cocoa _video _data . device_height
) ;
2005-12-10 11:16:45 +00:00
_cocoa _video _data . cursor_visible = true ;
/ * register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE * /
2006-02-18 17:27:06 +00:00
// QZ_RegisterForSleepNotifications ( ) ;
2005-12-10 11:16:45 +00:00
}
/ * Convert local coordinate to window server ( CoreGraphics ) coordinate * /
2006-02-18 17:27:06 +00:00
static CGPoint QZ_PrivateLocalToCG ( NSPoint * p )
{
2005-12-10 11:16:45 +00:00
CGPoint cgp ;
2006-02-18 17:27:06 +00:00
if ( ! _cocoa _video _data . fullscreen ) {
2005-12-10 11:16:45 +00:00
* p = [ _cocoa _video _data . qdview convertPoint : * p toView : nil ] ;
* p = [ _cocoa _video _data . window convertBaseToScreen : * p ] ;
p -> y = _cocoa _video _data . device_height - p -> y ;
}
cgp . x = p -> x ;
cgp . y = p -> y ;
return cgp ;
}
2006-02-18 17:27:06 +00:00
static void QZ_WarpCursor ( int x , int y )
{
2005-12-10 11:16:45 +00:00
NSPoint p ;
CGPoint cgp ;
/ * Only allow warping when in foreground * /
2006-02-18 17:27:06 +00:00
if ( ! [ NSApp isActive ] ) return ;
2005-12-10 11:16:45 +00:00
2006-02-18 17:27:06 +00:00
p = NSMakePoint ( x , y ) ;
cgp = QZ_PrivateLocalToCG ( & p ) ;
2005-12-10 11:16:45 +00:00
/ * this is the magic call that fixes cursor "freezing" after warp * /
2006-02-18 17:27:06 +00:00
CGSetLocalEventsSuppressionInterval ( 0.0 ) ;
2005-12-10 11:16:45 +00:00
/ * Do the actual warp * /
2006-02-18 17:27:06 +00:00
CGWarpMouseCursorPosition ( cgp ) ;
2005-12-10 11:16:45 +00:00
/ * Generate the mouse moved event * /
}
2006-02-18 17:27:06 +00:00
static void QZ_ShowMouse ( void )
{
2005-12-10 11:16:45 +00:00
if ( ! _cocoa _video _data . cursor_visible ) {
[ NSCursor unhide ] ;
_cocoa _video _data . cursor_visible = true ;
2006-03-24 10:17:39 +00:00
// Hide the openttd cursor when leaving the window
if ( _cocoa _video _data . isset )
UndrawMouseCursor ( ) ;
_cursor . in_window = false ;
2005-12-10 11:16:45 +00:00
}
}
2006-02-18 17:27:06 +00:00
static void QZ_HideMouse ( void )
{
2005-12-10 11:16:45 +00:00
if ( _cocoa _video _data . cursor_visible ) {
# ifndef _DEBUG
[ NSCursor hide ] ;
# endif
_cocoa _video _data . cursor_visible = false ;
2006-03-24 10:17:39 +00:00
// Show the openttd cursor again
_cursor . in_window = true ;
2005-12-10 11:16:45 +00:00
}
}
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* OS X application creation *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
/ * The main class of the application , the application ' s delegate * /
@ implementation OTTDMain
/ * Called when the internal event loop has just started running * /
2006-02-18 17:27:06 +00:00
- ( void ) applicationDidFinishLaunching : ( NSNotification * ) note
2005-12-10 11:16:45 +00:00
{
2006-01-06 21:27:44 +00:00
/ * Hand off to main application code * /
2005-12-10 11:16:45 +00:00
QZ_GameLoop ( ) ;
/ * We ' re done , thank you for playing * /
[ NSApp stop : _ottd _main ] ;
}
/ * Display the in game quit confirmation dialog * /
2006-02-18 17:27:06 +00:00
- ( NSApplicationTerminateReply ) applicationShouldTerminate : ( NSApplication * ) sender
2005-12-10 11:16:45 +00:00
{
QZ_AskQuit ( ) ;
return NSTerminateCancel ; // NSTerminateLater ?
}
@ end
static void setApplicationMenu ( void )
{
/ * warning : this code is very odd * /
NSMenu * appleMenu ;
NSMenuItem * menuItem ;
NSString * title ;
NSString * appName ;
appName = @ "OTTD" ;
appleMenu = [ [ NSMenu alloc ] initWithTitle : appName ] ;
/ * Add menu items * /
title = [ @ "About " stringByAppendingString : appName ] ;
[ appleMenu addItemWithTitle : title action : @ selector ( orderFrontStandardAboutPanel : ) keyEquivalent : @ "" ] ;
[ appleMenu addItem : [ NSMenuItem separatorItem ] ] ;
title = [ @ "Hide " stringByAppendingString : appName ] ;
[ appleMenu addItemWithTitle : title action : @ selector ( hide : ) keyEquivalent : @ "h" ] ;
2006-02-18 17:27:06 +00:00
menuItem = ( NSMenuItem * ) [ appleMenu addItemWithTitle : @ "Hide Others" action : @ selector ( hideOtherApplications : ) keyEquivalent : @ "h" ] ;
2005-12-10 11:16:45 +00:00
[ menuItem setKeyEquivalentModifierMask : ( NSAlternateKeyMask | NSCommandKeyMask ) ] ;
[ appleMenu addItemWithTitle : @ "Show All" action : @ selector ( unhideAllApplications : ) keyEquivalent : @ "" ] ;
[ appleMenu addItem : [ NSMenuItem separatorItem ] ] ;
title = [ @ "Quit " stringByAppendingString : appName ] ;
[ appleMenu addItemWithTitle : title action : @ selector ( terminate : ) keyEquivalent : @ "q" ] ;
/ * Put menu into the menubar * /
menuItem = [ [ NSMenuItem alloc ] initWithTitle : @ "" action : nil keyEquivalent : @ "" ] ;
[ menuItem setSubmenu : appleMenu ] ;
[ [ NSApp mainMenu ] addItem : menuItem ] ;
/ * Tell the application object that this is now the application menu * /
[ NSApp setAppleMenu : appleMenu ] ;
/ * Finally give up our references to the objects * /
[ appleMenu release ] ;
[ menuItem release ] ;
}
/ * Create a window menu * /
static void setupWindowMenu ( void )
{
2006-02-18 17:27:06 +00:00
NSMenu * windowMenu ;
NSMenuItem * windowMenuItem ;
NSMenuItem * menuItem ;
2005-12-10 11:16:45 +00:00
windowMenu = [ [ NSMenu alloc ] initWithTitle : @ "Window" ] ;
/ * "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 ( void )
{
CPSProcessSerNum PSN ;
/ * Ensure the application object is initialised * /
[ NSApplication sharedApplication ] ;
/ * Tell the dock about us * /
2006-02-18 17:27:06 +00:00
if ( ! CPSGetCurrentProcess ( & PSN ) &&
! CPSEnableForegroundOperation ( & PSN , 0 x03 , 0 x3C , 0 x2C , 0 x1103 ) &&
! CPSSetFrontProcess ( & PSN ) ) {
[ NSApplication sharedApplication ] ;
}
2005-12-10 11:16:45 +00:00
/ * 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 ] ;
}
2006-02-18 17:27:06 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Video driver interface *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2005-12-10 11:16:45 +00:00
static void CocoaVideoStop ( void )
{
DEBUG ( driver , 1 ) ( "cocoa_v: CocoaVideoStop" ) ;
2006-02-18 17:27:06 +00:00
if ( ! _cocoa _video _started ) return ;
2006-01-06 21:27:44 +00:00
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _data . isset ) QZ_UnsetVideoMode ( ) ;
2005-12-10 11:16:45 +00:00
[ _ottd _main release ] ;
2006-01-06 21:27:44 +00:00
_cocoa _video _started = false ;
2005-12-10 11:16:45 +00:00
}
static const char * CocoaVideoStart ( const char * const * parm )
{
const char * ret ;
DEBUG ( driver , 1 ) ( "cocoa_v: CocoaVideoStart" ) ;
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _started ) return "Already started" ;
2006-01-06 21:27:44 +00:00
_cocoa _video _started = true ;
memset ( & _cocoa _video _data , 0 , sizeof ( _cocoa _video _data ) ) ;
2005-12-10 11:16:45 +00:00
setupApplication ( ) ;
2006-01-06 21:27:44 +00:00
/ * Don ' t create a window or enter fullscreen if we ' re just going to show a dialog . * /
2006-02-18 17:27:06 +00:00
if ( _cocoa _video _dialog ) return NULL ;
2006-01-06 21:27:44 +00:00
2005-12-10 11:16:45 +00:00
QZ_VideoInit ( ) ;
ret = QZ_SetVideoMode ( _cur _resolution [ 0 ] , _cur _resolution [ 1 ] , _fullscreen ) ;
2006-02-18 17:27:06 +00:00
if ( ret ! = NULL ) CocoaVideoStop ( ) ;
2005-12-10 11:16:45 +00:00
return ret ;
}
static void CocoaVideoMakeDirty ( 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 )
{
DEBUG ( driver , 1 ) ( "cocoa_v: CocoaVideoMainLoop" ) ;
/ * Start the main event loop * /
[ NSApp run ] ;
}
static bool CocoaVideoChangeRes ( int w , int h )
{
const char * ret ;
DEBUG ( driver , 1 ) ( "cocoa_v: CocoaVideoChangeRes" ) ;
2006-02-18 17:27:06 +00:00
ret = QZ_SetVideoModeAndRestoreOnFailure ( ( uint ) w , ( uint ) h , _cocoa _video _data . fullscreen ) ;
if ( ret ! = NULL ) {
2005-12-10 11:16:45 +00:00
DEBUG ( driver , 1 ) ( "cocoa_v: failed with message: %s" , ret ) ;
}
return ret = = NULL ;
}
static void CocoaVideoFullScreen ( bool full_screen )
{
const char * ret ;
DEBUG ( driver , 1 ) ( "cocoa_v: CocoaVideoFullScreen" ) ;
ret = QZ_SetVideoModeAndRestoreOnFailure ( _cocoa _video _data . width , _cocoa _video _data . height , full_screen ) ;
2006-02-18 17:27:06 +00:00
if ( ret ! = NULL ) {
2005-12-10 11:16:45 +00:00
DEBUG ( driver , 1 ) ( "cocoa_v: failed with message: %s" , ret ) ;
}
_fullscreen = _cocoa _video _data . fullscreen ;
}
const HalVideoDriver _cocoa _video _driver = {
CocoaVideoStart ,
CocoaVideoStop ,
CocoaVideoMakeDirty ,
CocoaVideoMainLoop ,
CocoaVideoChangeRes ,
CocoaVideoFullScreen ,
} ;
2006-01-06 21:27:44 +00:00
/ * This is needed since sometimes assert is called before the videodriver is initialized * /
2006-02-18 17:27:06 +00:00
void CocoaDialog ( const char * title , const char * message , const char * buttonLabel )
2006-01-06 21:27:44 +00:00
{
bool wasstarted ;
_cocoa _video _dialog = true ;
wasstarted = _cocoa _video _started ;
2006-02-18 17:27:06 +00:00
if ( ! _cocoa _video _started && CocoaVideoStart ( NULL ) ! = NULL ) {
2006-01-06 21:27:44 +00:00
fprintf ( stderr , "%s: %s\n" , title , message ) ;
return ;
}
NSRunAlertPanel ( [ NSString stringWithCString : title ] , [ NSString stringWithCString : message ] , [ NSString stringWithCString : buttonLabel ] , nil , nil ) ;
2006-02-18 17:27:06 +00:00
if ( ! wasstarted ) CocoaVideoStop ( ) ;
2006-01-06 21:27:44 +00:00
_cocoa _video _dialog = false ;
}
2005-12-10 11:16:45 +00:00
/ * This is needed since OS X applications are started with the working dir set to / when double - clicked * /
void cocoaSetWorkingDirectory ( void )
{
char parentdir [ MAXPATHLEN ] ;
int chdir_ret ;
CFURLRef url = CFBundleCopyBundleURL ( CFBundleGetMainBundle ( ) ) ;
CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent ( 0 , url ) ;
2006-02-18 17:27:06 +00:00
if ( CFURLGetFileSystemRepresentation ( url2 , true , ( unsigned char * ) parentdir , MAXPATHLEN ) ) {
chdir_ret = chdir ( parentdir ) ; / * chdir to the binary app ' s parent * /
2005-12-10 11:16:45 +00:00
assert ( chdir_ret = = 0 ) ;
}
CFRelease ( url ) ;
CFRelease ( url2 ) ;
}
/ * These are called from main ( ) to prevent a _NSAutoreleaseNoPool error when
* exiting before the cocoa video driver has been loaded
* /
void cocoaSetupAutoreleasePool ( void )
{
_ottd _autorelease _pool = [ [ NSAutoreleasePool alloc ] init ] ;
}
void cocoaReleaseAutoreleasePool ( void )
{
[ _ottd _autorelease _pool release ] ;
}
# endif / * WITH_COCOA * /