1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * MMSYTEM time functions
6 * Copyright 1993 Martin Ayotte
24 #define USE_FAKE_MM_TIMERS
26 static MMTIME16 mmSysTimeMS
;
27 static MMTIME16 mmSysTimeSMPTE
;
29 typedef struct tagTIMERENTRY
{
33 HINSTANCE32 hInstance
;
39 struct tagTIMERENTRY
* Next
;
40 } TIMERENTRY
, *LPTIMERENTRY
;
42 static LPTIMERENTRY lpTimerList
= NULL
;
44 #ifdef USE_FAKE_MM_TIMERS
45 static DWORD dwLastCBTick
= 0;
46 static BOOL32 bUseFakeTimers
= FALSE
;
47 static WORD wInCallBackLoop
= 0;
52 * We're using "1" as the mininum resolution to the timer,
53 * as Windows 95 does, according to the docs. Maybe it should
54 * depend on the computers resources!
56 #define MMSYSTIME_MININTERVAL (1)
57 #define MMSYSTIME_MAXINTERVAL (65535)
59 static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer
, DWORD dwCurrent
)
61 lpTimer
->wCurTime
= lpTimer
->wDelay
;
63 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
64 TRACE(mmtime
, "before CallBack16 (%lu)!\n", dwCurrent
);
65 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
66 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
67 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
70 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
71 * during interrupt time, is allowed to execute very limited number of API calls (like
72 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
73 * guess current implementation via SetTimer has to be improved upon.
75 switch (lpTimer
->wFlags
& 0x30) {
76 case TIME_CALLBACK_FUNCTION
:
78 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
80 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
84 case TIME_CALLBACK_EVENT_SET
:
85 SetEvent((HANDLE32
)lpTimer
->lpFunc
);
87 case TIME_CALLBACK_EVENT_PULSE
:
88 PulseEvent((HANDLE32
)lpTimer
->lpFunc
);
91 FIXME(mmtime
,"Unknown callback type 0x%04x for mmtime callback (%p),ignored.\n",lpTimer
->wFlags
,lpTimer
->lpFunc
);
94 TRACE(mmtime
, "after CallBack16 !\n");
96 if (lpTimer
->wFlags
& TIME_ONESHOT
)
97 timeKillEvent32(lpTimer
->wTimerID
);
100 /**************************************************************************
101 * TIME_MMSysTimeCallback
103 static VOID WINAPI
TIME_MMSysTimeCallback( HWND32 hwnd
, UINT32 msg
,
104 UINT32 id
, DWORD dwTime
)
106 LPTIMERENTRY lpTimer
;
108 mmSysTimeMS
.u
.ms
+= MMSYSTIME_MININTERVAL
;
109 mmSysTimeSMPTE
.u
.smpte
.frame
++;
111 #ifdef USE_FAKE_MM_TIMERS
113 dwLastCBTick
= GetTickCount();
115 if (!wInCallBackLoop
++)
117 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
118 if (lpTimer
->wCurTime
< MMSYSTIME_MININTERVAL
) {
119 TIME_TriggerCallBack(lpTimer
, dwTime
);
121 lpTimer
->wCurTime
-= MMSYSTIME_MININTERVAL
;
124 #ifdef USE_FAKE_MM_TIMERS
129 /**************************************************************************
130 * StartMMTime [internal]
132 static void StartMMTime()
134 static BOOL32 mmTimeStarted
= FALSE
;
136 if (!mmTimeStarted
) {
137 mmTimeStarted
= TRUE
;
138 mmSysTimeMS
.wType
= TIME_MS
;
139 mmSysTimeMS
.u
.ms
= 0;
140 mmSysTimeSMPTE
.wType
= TIME_SMPTE
;
141 mmSysTimeSMPTE
.u
.smpte
.hour
= 0;
142 mmSysTimeSMPTE
.u
.smpte
.min
= 0;
143 mmSysTimeSMPTE
.u
.smpte
.sec
= 0;
144 mmSysTimeSMPTE
.u
.smpte
.frame
= 0;
145 mmSysTimeSMPTE
.u
.smpte
.fps
= 0;
146 mmSysTimeSMPTE
.u
.smpte
.dummy
= 0;
147 SetTimer32( 0, 0, MMSYSTIME_MININTERVAL
, TIME_MMSysTimeCallback
);
148 #ifdef USE_FAKE_MM_TIMERS
149 bUseFakeTimers
= PROFILE_GetWineIniBool("options", "MMFakeTimers", TRUE
);
150 TRACE(mmtime
, "FakeTimer=%c\n", bUseFakeTimers
? 'Y' : 'N');
152 dwLastCBTick
= GetTickCount();
157 /**************************************************************************
158 * timeGetSystemTime [WINMM.140]
160 MMRESULT32 WINAPI
timeGetSystemTime32(LPMMTIME32 lpTime
, UINT32 wSize
)
162 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
164 lpTime
->wType
= TIME_MS
;
165 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
169 /**************************************************************************
170 * timeGetSystemTime [MMSYSTEM.601]
172 MMRESULT16 WINAPI
timeGetSystemTime16(LPMMTIME16 lpTime
, UINT16 wSize
)
174 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
176 lpTime
->wType
= TIME_MS
;
177 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
181 static WORD
timeSetEventInternal(UINT32 wDelay
,UINT32 wResol
,
182 FARPROC16 lpFunc
,DWORD dwUser
,
183 UINT32 wFlags
, UINT16 isWin32
)
186 LPTIMERENTRY lpNewTimer
;
187 LPTIMERENTRY lpTimer
= lpTimerList
;
189 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
190 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
192 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
193 if (lpNewTimer
== NULL
)
195 while (lpTimer
!= NULL
) {
196 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
197 lpTimer
= lpTimer
->Next
;
200 lpNewTimer
->Next
= lpTimerList
;
201 lpTimerList
= lpNewTimer
;
202 lpNewTimer
->wTimerID
= wNewID
+ 1;
203 lpNewTimer
->wCurTime
= wDelay
;
204 lpNewTimer
->wDelay
= wDelay
;
205 lpNewTimer
->wResol
= wResol
;
206 lpNewTimer
->lpFunc
= lpFunc
;
207 lpNewTimer
->isWin32
= isWin32
;
208 lpNewTimer
->hInstance
= GetTaskDS();
209 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
210 TRACE(mmtime
, "lpFunc=%p !\n", isWin32
? lpFunc
: PTR_SEG_TO_LIN(lpFunc
));
211 lpNewTimer
->dwUser
= dwUser
;
212 lpNewTimer
->wFlags
= wFlags
;
213 return lpNewTimer
->wTimerID
;
216 /**************************************************************************
217 * timeSetEvent [MMSYSTEM.602]
219 MMRESULT32 WINAPI
timeSetEvent32(UINT32 wDelay
,UINT32 wResol
,
220 LPTIMECALLBACK32 lpFunc
,DWORD dwUser
,
223 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
227 /**************************************************************************
228 * timeSetEvent [MMSYSTEM.602]
230 MMRESULT16 WINAPI
timeSetEvent16(UINT16 wDelay
, UINT16 wResol
,
231 LPTIMECALLBACK16 lpFunc
,DWORD dwUser
,
234 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
238 /**************************************************************************
239 * timeKillEvent [WINMM.142]
241 MMRESULT32 WINAPI
timeKillEvent32(UINT32 wID
)
243 LPTIMERENTRY
* lpTimer
;
245 for (lpTimer
= &lpTimerList
; *lpTimer
; lpTimer
= &((*lpTimer
)->Next
)) {
246 if (wID
== (*lpTimer
)->wTimerID
) {
247 LPTIMERENTRY xlptimer
= (*lpTimer
)->Next
;
257 /**************************************************************************
258 * timeKillEvent [MMSYSTEM.603]
260 MMRESULT16 WINAPI
timeKillEvent16(UINT16 wID
)
262 return timeKillEvent32(wID
);
265 /**************************************************************************
266 * timeGetDevCaps [WINMM.139]
268 MMRESULT32 WINAPI
timeGetDevCaps32(LPTIMECAPS32 lpCaps
,UINT32 wSize
)
270 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
272 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
273 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
277 /**************************************************************************
278 * timeGetDevCaps [MMSYSTEM.604]
280 MMRESULT16 WINAPI
timeGetDevCaps16(LPTIMECAPS16 lpCaps
, UINT16 wSize
)
282 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
284 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
285 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
289 /**************************************************************************
290 * timeBeginPeriod [WINMM.137]
292 MMRESULT32 WINAPI
timeBeginPeriod32(UINT32 wPeriod
)
294 TRACE(mmtime
, "(%u) !\n", wPeriod
);
296 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
297 return TIMERR_NOCANDO
;
300 /**************************************************************************
301 * timeBeginPeriod [MMSYSTEM.605]
303 MMRESULT16 WINAPI
timeBeginPeriod16(UINT16 wPeriod
)
305 TRACE(mmtime
, "(%u) !\n", wPeriod
);
307 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
308 return TIMERR_NOCANDO
;
312 /**************************************************************************
313 * timeEndPeriod [WINMM.138]
315 MMRESULT32 WINAPI
timeEndPeriod32(UINT32 wPeriod
)
317 TRACE(mmtime
, "(%u) !\n", wPeriod
);
319 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
320 return TIMERR_NOCANDO
;
324 /**************************************************************************
325 * timeEndPeriod [MMSYSTEM.606]
327 MMRESULT16 WINAPI
timeEndPeriod16(UINT16 wPeriod
)
329 TRACE(mmtime
, "(%u) !\n", wPeriod
);
330 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
331 return TIMERR_NOCANDO
;
335 /**************************************************************************
336 * timeGetTime [MMSYSTEM.607][WINMM.141]
338 DWORD WINAPI
timeGetTime()
340 DWORD dwNewTick
= GetTickCount();
343 #ifdef USE_FAKE_MM_TIMERS
344 if (bUseFakeTimers
) {
345 if (wInCallBackLoop
++) {
349 if (dwNewTick
< dwLastCBTick
) {
350 ERR(mmtime
, "dwNewTick(%lu) < dwLastCBTick(%lu)\n", dwNewTick
, dwLastCBTick
);
352 dwDelta
= dwNewTick
- dwLastCBTick
;
353 if (dwDelta
> MMSYSTIME_MININTERVAL
) {
354 LPTIMERENTRY lpTimer
;
356 mmSysTimeMS
.u
.ms
+= dwDelta
; /* FIXME: faked timer */
357 dwLastCBTick
= dwNewTick
;
358 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
359 if (lpTimer
->wCurTime
< dwDelta
) {
360 TIME_TriggerCallBack(lpTimer
, dwNewTick
);
362 lpTimer
->wCurTime
-= dwDelta
;
365 dwNewTick
= mmSysTimeMS
.u
.ms
;