Home | History | Annotate | Download | only in macos
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Lesser General Public
      7     License as published by the Free Software Foundation; either
      8     version 2.1 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Lesser General Public License for more details.
     14 
     15     You should have received a copy of the GNU Lesser General Public
     16     License along with this library; if not, write to the Free Software
     17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #ifdef SDL_TIMER_MACOS
     25 
     26 #include <Types.h>
     27 #include <Timer.h>
     28 #include <OSUtils.h>
     29 #include <Gestalt.h>
     30 #include <Processes.h>
     31 
     32 #include <LowMem.h>
     33 
     34 #include "SDL_timer.h"
     35 #include "../SDL_timer_c.h"
     36 
     37 #define MS_PER_TICK	(1000/60)		/* MacOS tick = 1/60 second */
     38 
     39 /* Note: This is only a step above the original 1/60s implementation.
     40  *       For a good implementation, see FastTimes.[ch], by Matt Slot.
     41  */
     42 #define USE_MICROSECONDS
     43 #define WideTo64bit(w)	(*(UInt64 *) &(w))
     44 
     45 UInt64 start;
     46 
     47 void SDL_StartTicks(void)
     48 {
     49 #ifdef USE_MICROSECONDS
     50 	UnsignedWide now;
     51 
     52 	Microseconds(&now);
     53 	start = WideTo64bit(now);
     54 #else
     55 	/* FIXME: Should we implement a wrapping algorithm, like Win32? */
     56 #endif
     57 }
     58 
     59 Uint32 SDL_GetTicks(void)
     60 {
     61 #ifdef USE_MICROSECONDS
     62 	UnsignedWide now;
     63 
     64 	Microseconds(&now);
     65 	return (Uint32)((WideTo64bit(now)-start)/1000);
     66 #else
     67 	return(LMGetTicks()*MS_PER_TICK);
     68 #endif
     69 }
     70 
     71 void SDL_Delay(Uint32 ms)
     72 {
     73 #ifdef USE_MICROSECONDS
     74 	Uint32 end_ms;
     75 
     76 	end_ms = SDL_GetTicks() + ms;
     77 	do {
     78 		/* FIXME: Yield CPU? */ ;
     79 	} while ( SDL_GetTicks() < end_ms );
     80 #else
     81 	UInt32		unused; /* MJS */
     82 	Delay(ms/MS_PER_TICK, &unused);
     83 #endif
     84 }
     85 
     86 
     87 /* Data to handle a single periodic alarm */
     88 typedef struct _ExtendedTimerRec
     89 {
     90 	TMTask		     tmTask;
     91 	ProcessSerialNumber  taskPSN;
     92 } ExtendedTimerRec, *ExtendedTimerPtr;
     93 
     94 static ExtendedTimerRec gExtendedTimerRec;
     95 
     96 
     97 int SDL_SYS_TimerInit(void)
     98 {
     99 	/* We don't need a setup? */
    100 	return(0);
    101 }
    102 
    103 void SDL_SYS_TimerQuit(void)
    104 {
    105 	/* We don't need a cleanup? */
    106 	return;
    107 }
    108 
    109 /* Our Stub routine to set up and then call the real routine. */
    110 pascal void TimerCallbackProc(TMTaskPtr tmTaskPtr)
    111 {
    112 	Uint32 ms;
    113 
    114 	WakeUpProcess(&((ExtendedTimerPtr) tmTaskPtr)->taskPSN);
    115 
    116 	ms = SDL_alarm_callback(SDL_alarm_interval);
    117 	if ( ms ) {
    118 		SDL_alarm_interval = ROUND_RESOLUTION(ms);
    119 		PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask,
    120 		          SDL_alarm_interval);
    121 	} else {
    122 		SDL_alarm_interval = 0;
    123 	}
    124 }
    125 
    126 int SDL_SYS_StartTimer(void)
    127 {
    128 	/*
    129 	 * Configure the global structure that stores the timing information.
    130 	 */
    131 	gExtendedTimerRec.tmTask.qLink = NULL;
    132 	gExtendedTimerRec.tmTask.qType = 0;
    133 	gExtendedTimerRec.tmTask.tmAddr = NewTimerUPP(TimerCallbackProc);
    134 	gExtendedTimerRec.tmTask.tmCount = 0;
    135 	gExtendedTimerRec.tmTask.tmWakeUp = 0;
    136 	gExtendedTimerRec.tmTask.tmReserved = 0;
    137 	GetCurrentProcess(&gExtendedTimerRec.taskPSN);
    138 
    139 	/* Install the task record */
    140 	InsXTime((QElemPtr)&gExtendedTimerRec.tmTask);
    141 
    142 	/* Go! */
    143 	PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, SDL_alarm_interval);
    144 	return(0);
    145 }
    146 
    147 void SDL_SYS_StopTimer(void)
    148 {
    149 	RmvTime((QElemPtr)&gExtendedTimerRec.tmTask);
    150 }
    151 
    152 #endif /* SDL_TIMER_MACOS */
    153