Ove Kaaven 1441e03e0c Fixed fake multimedia timers. Grim Fandango is now able to start up
when under favorable conditions. The preview movie on the Brood Wars
disc now plays, too.
1999-04-10 16:27:08 +00:00

369 lines
10 KiB
C

/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* MMSYTEM time functions
*
* Copyright 1993 Martin Ayotte
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "windef.h"
#include "wine/winbase16.h" /* GetTaskDS */
#include "callback.h"
#include "mmsystem.h"
#include "xmalloc.h"
#include "options.h"
#include "debug.h"
#define USE_FAKE_MM_TIMERS
static MMTIME16 mmSysTimeMS;
static MMTIME16 mmSysTimeSMPTE;
typedef struct tagTIMERENTRY {
UINT wDelay;
UINT wResol;
FARPROC16 lpFunc;
HINSTANCE hInstance;
DWORD dwUser;
UINT wFlags;
UINT wTimerID;
UINT wCurTime;
UINT isWin32;
struct tagTIMERENTRY* Next;
} TIMERENTRY, *LPTIMERENTRY;
static LPTIMERENTRY lpTimerList = NULL;
#ifdef USE_FAKE_MM_TIMERS
static DWORD dwLastCBTick = 0;
static BOOL bUseFakeTimers = FALSE;
static WORD wInCallBackLoop = 0;
#endif
/*
* FIXME
* We're using "1" as the mininum resolution to the timer,
* as Windows 95 does, according to the docs. Maybe it should
* depend on the computers resources!
*/
#define MMSYSTIME_MININTERVAL (1)
#define MMSYSTIME_MAXINTERVAL (65535)
static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer, DWORD dwCurrent)
{
lpTimer->wCurTime = lpTimer->wDelay;
if (lpTimer->lpFunc != (FARPROC16) NULL) {
TRACE(mmtime, "before CallBack16 (%lu)!\n", dwCurrent);
TRACE(mmtime, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
TRACE(mmtime, "hInstance=%04X !\n", lpTimer->hInstance);
/* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
* during interrupt time, is allowed to execute very limited number of API calls (like
* PostMessage), and must reside in DLL (therefore uses stack of active application). So I
* guess current implementation via SetTimer has to be improved upon.
*/
switch (lpTimer->wFlags & 0x30) {
case TIME_CALLBACK_FUNCTION:
if (lpTimer->isWin32)
lpTimer->lpFunc(lpTimer->wTimerID,0,lpTimer->dwUser,0,0);
else
Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
lpTimer->wTimerID,0,
lpTimer->dwUser,0,0);
break;
case TIME_CALLBACK_EVENT_SET:
SetEvent((HANDLE)lpTimer->lpFunc);
break;
case TIME_CALLBACK_EVENT_PULSE:
PulseEvent((HANDLE)lpTimer->lpFunc);
break;
default:
FIXME(mmtime,"Unknown callback type 0x%04x for mmtime callback (%p),ignored.\n",lpTimer->wFlags,lpTimer->lpFunc);
break;
}
TRACE(mmtime, "after CallBack16 !\n");
}
if (lpTimer->wFlags & TIME_ONESHOT)
timeKillEvent(lpTimer->wTimerID);
}
/**************************************************************************
* TIME_MMSysTimeCallback
*/
static VOID WINAPI TIME_MMSysTimeCallback( HWND hwnd, UINT msg,
UINT id, DWORD dwTime )
{
LPTIMERENTRY lpTimer;
mmSysTimeMS.u.ms += MMSYSTIME_MININTERVAL;
mmSysTimeSMPTE.u.smpte.frame++;
#ifdef USE_FAKE_MM_TIMERS
if (bUseFakeTimers)
dwLastCBTick = GetTickCount();
if (!wInCallBackLoop++)
#endif
for (lpTimer = lpTimerList; lpTimer != NULL; lpTimer = lpTimer->Next) {
if (lpTimer->wCurTime < MMSYSTIME_MININTERVAL) {
TIME_TriggerCallBack(lpTimer, dwTime);
} else {
lpTimer->wCurTime -= MMSYSTIME_MININTERVAL;
}
}
#ifdef USE_FAKE_MM_TIMERS
wInCallBackLoop--;
#endif
}
/**************************************************************************
* StartMMTime [internal]
*/
static void StartMMTime()
{
static BOOL mmTimeStarted = FALSE;
if (!mmTimeStarted) {
mmTimeStarted = TRUE;
mmSysTimeMS.wType = TIME_MS;
mmSysTimeMS.u.ms = 0;
mmSysTimeSMPTE.wType = TIME_SMPTE;
mmSysTimeSMPTE.u.smpte.hour = 0;
mmSysTimeSMPTE.u.smpte.min = 0;
mmSysTimeSMPTE.u.smpte.sec = 0;
mmSysTimeSMPTE.u.smpte.frame = 0;
mmSysTimeSMPTE.u.smpte.fps = 0;
mmSysTimeSMPTE.u.smpte.dummy = 0;
SetTimer( 0, 0, MMSYSTIME_MININTERVAL, TIME_MMSysTimeCallback );
#ifdef USE_FAKE_MM_TIMERS
bUseFakeTimers = PROFILE_GetWineIniBool("options", "MMFakeTimers", TRUE);
TRACE(mmtime, "FakeTimer=%c\n", bUseFakeTimers ? 'Y' : 'N');
if (bUseFakeTimers)
dwLastCBTick = GetTickCount();
#endif
}
}
/**************************************************************************
* timeGetSystemTime [WINMM.140]
*/
MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize)
{
TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
StartMMTime();
lpTime->wType = TIME_MS;
lpTime->u.ms = mmSysTimeMS.u.ms;
return 0;
}
/**************************************************************************
* timeGetSystemTime [MMSYSTEM.601]
*/
MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize)
{
TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
StartMMTime();
lpTime->wType = TIME_MS;
lpTime->u.ms = mmSysTimeMS.u.ms;
return 0;
}
static WORD timeSetEventInternal(UINT wDelay,UINT wResol,
FARPROC16 lpFunc,DWORD dwUser,
UINT wFlags, UINT16 isWin32)
{
WORD wNewID = 0;
LPTIMERENTRY lpNewTimer;
LPTIMERENTRY lpTimer = lpTimerList;
TRACE(mmtime, "(%u, %u, %p, %08lX, %04X);\n",
wDelay, wResol, lpFunc, dwUser, wFlags);
StartMMTime();
lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY));
if (lpNewTimer == NULL)
return 0;
while (lpTimer != NULL) {
wNewID = MAX(wNewID, lpTimer->wTimerID);
lpTimer = lpTimer->Next;
}
lpNewTimer->Next = lpTimerList;
lpTimerList = lpNewTimer;
lpNewTimer->wTimerID = wNewID + 1;
lpNewTimer->wCurTime = wDelay;
lpNewTimer->wDelay = wDelay;
lpNewTimer->wResol = wResol;
lpNewTimer->lpFunc = lpFunc;
lpNewTimer->isWin32 = isWin32;
lpNewTimer->hInstance = GetTaskDS16();
TRACE(mmtime, "hInstance=%04X !\n", lpNewTimer->hInstance);
TRACE(mmtime, "lpFunc=0x%08lx !\n", (DWORD)lpFunc );
lpNewTimer->dwUser = dwUser;
lpNewTimer->wFlags = wFlags;
return lpNewTimer->wTimerID;
}
/**************************************************************************
* timeSetEvent [MMSYSTEM.602]
*/
MMRESULT WINAPI timeSetEvent(UINT wDelay,UINT wResol,
LPTIMECALLBACK lpFunc,DWORD dwUser,
UINT wFlags)
{
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc,
dwUser, wFlags, 1);
}
/**************************************************************************
* timeSetEvent [MMSYSTEM.602]
*/
MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol,
LPTIMECALLBACK16 lpFunc,DWORD dwUser,
UINT16 wFlags)
{
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc,
dwUser, wFlags, 0);
}
/**************************************************************************
* timeKillEvent [WINMM.142]
*/
MMRESULT WINAPI timeKillEvent(UINT wID)
{
LPTIMERENTRY* lpTimer;
for (lpTimer = &lpTimerList; *lpTimer; lpTimer = &((*lpTimer)->Next)) {
if (wID == (*lpTimer)->wTimerID) {
LPTIMERENTRY xlptimer = (*lpTimer)->Next;
free(*lpTimer);
*lpTimer = xlptimer;
return TRUE;
}
}
return 0;
}
/**************************************************************************
* timeKillEvent [MMSYSTEM.603]
*/
MMRESULT16 WINAPI timeKillEvent16(UINT16 wID)
{
return timeKillEvent(wID);
}
/**************************************************************************
* timeGetDevCaps [WINMM.139]
*/
MMRESULT WINAPI timeGetDevCaps(LPTIMECAPS lpCaps,UINT wSize)
{
TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
StartMMTime();
lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
return 0;
}
/**************************************************************************
* timeGetDevCaps [MMSYSTEM.604]
*/
MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize)
{
TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
StartMMTime();
lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
return 0;
}
/**************************************************************************
* timeBeginPeriod [WINMM.137]
*/
MMRESULT WINAPI timeBeginPeriod(UINT wPeriod)
{
TRACE(mmtime, "(%u) !\n", wPeriod);
StartMMTime();
if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
return TIMERR_NOCANDO;
return 0;
}
/**************************************************************************
* timeBeginPeriod [MMSYSTEM.605]
*/
MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod)
{
TRACE(mmtime, "(%u) !\n", wPeriod);
StartMMTime();
if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
return TIMERR_NOCANDO;
return 0;
}
/**************************************************************************
* timeEndPeriod [WINMM.138]
*/
MMRESULT WINAPI timeEndPeriod(UINT wPeriod)
{
TRACE(mmtime, "(%u) !\n", wPeriod);
StartMMTime();
if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
return TIMERR_NOCANDO;
return 0;
}
/**************************************************************************
* timeEndPeriod [MMSYSTEM.606]
*/
MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod)
{
TRACE(mmtime, "(%u) !\n", wPeriod);
if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
return TIMERR_NOCANDO;
return 0;
}
/**************************************************************************
* timeGetTime [MMSYSTEM.607][WINMM.141]
*/
DWORD WINAPI timeGetTime()
{
DWORD dwNewTick = GetTickCount();
StartMMTime();
#ifdef USE_FAKE_MM_TIMERS
if (bUseFakeTimers) {
if (!wInCallBackLoop++) {
DWORD dwDelta;
if (dwNewTick < dwLastCBTick) {
ERR(mmtime, "dwNewTick(%lu) < dwLastCBTick(%lu)\n", dwNewTick, dwLastCBTick);
}
dwDelta = dwNewTick - dwLastCBTick;
if (dwDelta > MMSYSTIME_MININTERVAL) {
LPTIMERENTRY lpTimer;
mmSysTimeMS.u.ms += dwDelta; /* FIXME: faked timer */
dwLastCBTick = dwNewTick;
for (lpTimer = lpTimerList; lpTimer != NULL; lpTimer = lpTimer->Next) {
if (lpTimer->wCurTime < dwDelta) {
TIME_TriggerCallBack(lpTimer, dwNewTick);
} else {
lpTimer->wCurTime -= dwDelta;
}
}
}
}
dwNewTick = mmSysTimeMS.u.ms;
wInCallBackLoop--;
}
#endif
return dwNewTick;
}