Added support for ResetDC.
[wine/wine64.git] / dlls / quartz / sysclock.c
blobe12b927721749d97262f53e44322819d3fd251d7
1 /*
2 * Implementation of CLSID_SystemClock.
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winerror.h"
28 #include "strmif.h"
29 #include "uuids.h"
31 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
34 #include "quartz_private.h"
35 #include "sysclock.h"
38 /***************************************************************************
40 * new/delete for CLSID_SystemClock
44 /* can I use offsetof safely? - FIXME? */
45 static QUARTZ_IFEntry IFEntries[] =
47 { &IID_IReferenceClock, offsetof(CSystemClock,refclk)-offsetof(CSystemClock,unk) },
51 static void QUARTZ_DestroySystemClock(IUnknown* punk)
53 CSystemClock_THIS(punk,unk);
55 CSystemClock_UninitIReferenceClock( This );
58 HRESULT QUARTZ_CreateSystemClock(IUnknown* punkOuter,void** ppobj)
60 CSystemClock* psc;
61 HRESULT hr;
63 TRACE("(%p,%p)\n",punkOuter,ppobj);
65 psc = (CSystemClock*)QUARTZ_AllocObj( sizeof(CSystemClock) );
66 if ( psc == NULL )
67 return E_OUTOFMEMORY;
69 QUARTZ_IUnkInit( &psc->unk, punkOuter );
70 hr = CSystemClock_InitIReferenceClock( psc );
71 if ( FAILED(hr) )
73 QUARTZ_FreeObj( psc );
74 return hr;
77 psc->unk.pEntries = IFEntries;
78 psc->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
79 psc->unk.pOnFinalRelease = QUARTZ_DestroySystemClock;
81 *ppobj = (void*)(&psc->unk);
83 return S_OK;
87 /***************************************************************************
89 * CLSID_SystemClock::IReferenceClock
93 #define QUARTZ_MSG_ADDTIMER (WM_APP+0)
94 #define QUARTZ_MSG_REMOVETIMER (WM_APP+1)
95 #define QUARTZ_MSG_EXITTHREAD (WM_APP+2)
98 /****************************************************************************/
100 static QUARTZ_TimerEntry* IReferenceClock_AllocTimerEntry(CSystemClock* This)
102 QUARTZ_TimerEntry* pEntry;
103 DWORD dw;
105 pEntry = &This->m_timerEntries[0];
106 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
108 if ( pEntry->hEvent == (HANDLE)NULL )
109 return pEntry;
110 pEntry ++;
113 return NULL;
116 static QUARTZ_TimerEntry* IReferenceClock_SearchTimer(CSystemClock* This, DWORD dwAdvCookie)
118 QUARTZ_TimerEntry* pEntry;
119 DWORD dw;
121 pEntry = &This->m_timerEntries[0];
122 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
124 if ( pEntry->hEvent != (HANDLE)NULL &&
125 pEntry->dwAdvCookie == dwAdvCookie )
126 return pEntry;
127 pEntry ++;
130 return NULL;
133 static DWORD IReferenceClock_OnTimerUpdated(CSystemClock* This)
135 QUARTZ_TimerEntry* pEntry;
136 REFERENCE_TIME rtCur;
137 REFERENCE_TIME rtSignal;
138 REFERENCE_TIME rtCount;
139 HRESULT hr;
140 LONG lCount;
141 DWORD dw;
142 DWORD dwTimeout = INFINITE;
143 DWORD dwTimeoutCur;
145 hr = IReferenceClock_GetTime((IReferenceClock*)(&This->refclk),&rtCur);
146 if ( hr != NOERROR )
147 return INFINITE;
149 pEntry = &This->m_timerEntries[0];
150 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
152 if ( pEntry->hEvent != (HANDLE)NULL )
154 rtSignal = pEntry->rtStart + pEntry->rtInterval;
155 if ( rtCur >= rtSignal )
157 if ( pEntry->fPeriodic )
159 rtCount = ((rtCur - pEntry->rtStart) / pEntry->rtInterval);
160 lCount = ( rtCount > (REFERENCE_TIME)0x7fffffff ) ?
161 (LONG)0x7fffffff : (LONG)rtCount;
162 if ( !ReleaseSemaphore( pEntry->hEvent, lCount, NULL ) )
164 while ( lCount > 0 )
166 if ( !ReleaseSemaphore( pEntry->hEvent, 1, NULL ) )
167 break;
170 dwTimeout = 0;
172 else
174 TRACE( "signal an event\n" );
175 SetEvent( pEntry->hEvent );
176 pEntry->hEvent = (HANDLE)NULL;
179 else
181 rtCount = rtSignal - rtCur;
182 /* [100ns] -> [ms] */
183 rtCount = (rtCount+(REFERENCE_TIME)9999)/(REFERENCE_TIME)10000;
184 dwTimeoutCur = (rtCount >= 0xfffffffe) ? (DWORD)0xfffffffe : (DWORD)rtCount;
185 if ( dwTimeout > dwTimeoutCur )
186 dwTimeout = dwTimeoutCur;
189 pEntry ++;
192 return dwTimeout;
195 static
196 DWORD WINAPI IReferenceClock_TimerEntry( LPVOID lpvParam )
198 CSystemClock* This = (CSystemClock*)lpvParam;
199 MSG msg;
200 DWORD dwRes;
201 DWORD dwTimeout;
203 /* initialize the message queue. */
204 PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE );
205 /* resume the owner thread. */
206 SetEvent( This->m_hEventInit );
208 TRACE( "Enter message loop.\n" );
210 /* message loop. */
211 dwTimeout = INFINITE;
212 while ( 1 )
214 if ( dwTimeout > 0 )
216 dwRes = MsgWaitForMultipleObjects(
217 0, NULL, FALSE,
218 dwTimeout,
219 QS_ALLEVENTS );
222 EnterCriticalSection( &This->m_csClock );
223 dwTimeout = IReferenceClock_OnTimerUpdated(This);
224 LeaveCriticalSection( &This->m_csClock );
225 TRACE( "catch an event / timeout %lu\n", dwTimeout );
227 while ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) )
229 if ( msg.message == WM_QUIT )
230 goto quitthread;
232 if ( msg.hwnd != (HWND)NULL )
234 TranslateMessage( &msg );
235 DispatchMessageA( &msg );
237 else
239 switch ( msg.message )
241 case QUARTZ_MSG_ADDTIMER:
242 case QUARTZ_MSG_REMOVETIMER:
243 dwTimeout = 0;
244 break;
245 case QUARTZ_MSG_EXITTHREAD:
246 PostQuitMessage(0);
247 break;
248 default:
249 FIXME( "invalid message %04u\n", (unsigned)msg.message );
250 break;
256 quitthread:
257 TRACE( "quit thread\n" );
258 return 0;
261 /****************************************************************************/
263 static HRESULT WINAPI
264 IReferenceClock_fnQueryInterface(IReferenceClock* iface,REFIID riid,void** ppobj)
266 CSystemClock_THIS(iface,refclk);
268 TRACE("(%p)->()\n",This);
270 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
273 static ULONG WINAPI
274 IReferenceClock_fnAddRef(IReferenceClock* iface)
276 CSystemClock_THIS(iface,refclk);
278 TRACE("(%p)->()\n",This);
280 return IUnknown_AddRef(This->unk.punkControl);
283 static ULONG WINAPI
284 IReferenceClock_fnRelease(IReferenceClock* iface)
286 CSystemClock_THIS(iface,refclk);
288 TRACE("(%p)->()\n",This);
290 return IUnknown_Release(This->unk.punkControl);
293 static HRESULT WINAPI
294 IReferenceClock_fnGetTime(IReferenceClock* iface,REFERENCE_TIME* prtTime)
296 CSystemClock_THIS(iface,refclk);
297 DWORD dwTimeCur;
299 TRACE( "(%p)->(%p)\n", This, prtTime );
301 if ( prtTime == NULL )
302 return E_POINTER;
304 EnterCriticalSection( &This->m_csClock );
306 dwTimeCur = GetTickCount();
307 This->m_rtLast += (REFERENCE_TIME)(DWORD)(dwTimeCur - This->m_dwTimeLast) * (REFERENCE_TIME)10000;
309 This->m_dwTimeLast = dwTimeCur;
311 *prtTime = This->m_rtLast;
313 LeaveCriticalSection( &This->m_csClock );
315 return NOERROR;
318 static HRESULT WINAPI
319 IReferenceClock_fnAdviseTime(IReferenceClock* iface,REFERENCE_TIME rtBase,REFERENCE_TIME rtStream,HEVENT hEvent,DWORD_PTR* pdwAdvCookie)
321 CSystemClock_THIS(iface,refclk);
322 QUARTZ_TimerEntry* pEntry;
323 HRESULT hr;
324 REFERENCE_TIME rtCur;
326 TRACE( "(%p)->()\n", This );
328 if ( pdwAdvCookie == NULL )
329 return E_POINTER;
330 if ( hEvent == (HANDLE)NULL )
331 return E_INVALIDARG;
333 EnterCriticalSection( &This->m_csClock );
335 *pdwAdvCookie = (DWORD_PTR)(This->m_dwAdvCookieNext ++);
337 hr = IReferenceClock_GetTime(iface,&rtCur);
338 if ( hr != NOERROR )
339 goto err;
340 if ( rtCur >= (rtBase+rtStream) )
342 SetEvent(hEvent);
343 hr = NOERROR;
344 goto err;
347 pEntry = IReferenceClock_AllocTimerEntry(This);
348 if ( pEntry == NULL )
350 hr = E_FAIL;
351 goto err;
354 pEntry->dwAdvCookie = *pdwAdvCookie;
355 pEntry->fPeriodic = FALSE;
356 pEntry->hEvent = hEvent;
357 pEntry->rtStart = rtBase;
358 pEntry->rtInterval = rtStream;
360 if ( !PostThreadMessageA(
361 This->m_idThreadTimer,
362 QUARTZ_MSG_ADDTIMER,
363 0, 0 ) )
365 pEntry->hEvent = (HANDLE)NULL;
366 hr = E_FAIL;
367 goto err;
370 hr = NOERROR;
371 err:
372 LeaveCriticalSection( &This->m_csClock );
374 return hr;
377 static HRESULT WINAPI
378 IReferenceClock_fnAdvisePeriodic(IReferenceClock* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtPeriod,HSEMAPHORE hSemaphore,DWORD_PTR* pdwAdvCookie)
380 CSystemClock_THIS(iface,refclk);
381 QUARTZ_TimerEntry* pEntry;
382 HRESULT hr;
384 TRACE( "(%p)->()\n", This );
386 if ( pdwAdvCookie == NULL )
387 return E_POINTER;
388 if ( hSemaphore == (HSEMAPHORE)NULL )
389 return E_INVALIDARG;
391 EnterCriticalSection( &This->m_csClock );
393 *pdwAdvCookie = (DWORD_PTR)(This->m_dwAdvCookieNext ++);
395 pEntry = IReferenceClock_AllocTimerEntry(This);
396 if ( pEntry == NULL )
398 hr = E_FAIL;
399 goto err;
402 pEntry->dwAdvCookie = *pdwAdvCookie;
403 pEntry->fPeriodic = TRUE;
404 pEntry->hEvent = (HANDLE)hSemaphore;
405 pEntry->rtStart = rtStart;
406 pEntry->rtInterval = rtPeriod;
408 if ( !PostThreadMessageA(
409 This->m_idThreadTimer,
410 QUARTZ_MSG_ADDTIMER,
411 0, 0 ) )
413 pEntry->hEvent = (HANDLE)NULL;
414 hr = E_FAIL;
415 goto err;
418 hr = NOERROR;
419 err:
420 LeaveCriticalSection( &This->m_csClock );
422 return hr;
425 static HRESULT WINAPI
426 IReferenceClock_fnUnadvise(IReferenceClock* iface,DWORD_PTR dwAdvCookie)
428 CSystemClock_THIS(iface,refclk);
429 QUARTZ_TimerEntry* pEntry;
431 TRACE( "(%p)->(%lu)\n", This, (DWORD)dwAdvCookie );
433 EnterCriticalSection( &This->m_csClock );
435 pEntry = IReferenceClock_SearchTimer(This,(DWORD)dwAdvCookie);
436 if ( pEntry != NULL )
438 pEntry->hEvent = (HANDLE)NULL;
441 LeaveCriticalSection( &This->m_csClock );
443 return NOERROR;
446 static ICOM_VTABLE(IReferenceClock) irefclk =
448 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
449 /* IUnknown fields */
450 IReferenceClock_fnQueryInterface,
451 IReferenceClock_fnAddRef,
452 IReferenceClock_fnRelease,
453 /* IReferenceClock fields */
454 IReferenceClock_fnGetTime,
455 IReferenceClock_fnAdviseTime,
456 IReferenceClock_fnAdvisePeriodic,
457 IReferenceClock_fnUnadvise,
461 HRESULT CSystemClock_InitIReferenceClock( CSystemClock* psc )
463 HANDLE hEvents[2];
465 TRACE("(%p)\n",psc);
466 ICOM_VTBL(&psc->refclk) = &irefclk;
468 InitializeCriticalSection( &psc->m_csClock );
469 psc->m_dwTimeLast = GetTickCount();
470 psc->m_rtLast = (REFERENCE_TIME)0;
471 psc->m_hThreadTimer = (HANDLE)NULL;
472 psc->m_hEventInit = (HANDLE)NULL;
473 psc->m_idThreadTimer = 0;
474 psc->m_dwAdvCookieNext = 1;
475 ZeroMemory( psc->m_timerEntries, sizeof(psc->m_timerEntries) );
477 psc->m_hEventInit = CreateEventA( NULL, TRUE, FALSE, NULL );
478 if ( psc->m_hEventInit == (HANDLE)NULL )
479 goto err;
481 psc->m_hThreadTimer = CreateThread(
482 NULL, 0,
483 IReferenceClock_TimerEntry,
484 psc, 0, &psc->m_idThreadTimer );
486 if ( psc->m_hThreadTimer == (HANDLE)NULL )
488 CloseHandle( psc->m_hEventInit );
489 psc->m_hEventInit = (HANDLE)NULL;
490 goto err;
493 hEvents[0] = psc->m_hEventInit;
494 hEvents[1] = psc->m_hThreadTimer;
495 if ( WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE )
496 != WAIT_OBJECT_0 )
498 CloseHandle( psc->m_hEventInit );
499 psc->m_hEventInit = (HANDLE)NULL;
500 CloseHandle( psc->m_hThreadTimer );
501 psc->m_hThreadTimer = (HANDLE)NULL;
502 goto err;
505 return NOERROR;
507 err:
508 DeleteCriticalSection( &psc->m_csClock );
509 return E_FAIL;
512 void CSystemClock_UninitIReferenceClock( CSystemClock* psc )
514 TRACE("(%p)\n",psc);
516 if ( psc->m_hThreadTimer != (HANDLE)NULL )
518 if ( PostThreadMessageA(
519 psc->m_idThreadTimer,
520 QUARTZ_MSG_EXITTHREAD,
521 0, 0 ) )
523 WaitForSingleObject( psc->m_hThreadTimer, INFINITE );
525 CloseHandle( psc->m_hThreadTimer );
526 psc->m_hThreadTimer = (HANDLE)NULL;
529 DeleteCriticalSection( &psc->m_csClock );