Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
9.2 KiB

  1. #include "stdafx.h"
  2. #include "Motion.h"
  3. #include "Action.h"
  4. /***************************************************************************\
  5. *****************************************************************************
  6. *
  7. * class Action
  8. *
  9. *****************************************************************************
  10. \***************************************************************************/
  11. //---------------------------------------------------------------------------
  12. Action::Action()
  13. {
  14. m_cEventsInPeriod = 0;
  15. m_cPeriods = 0;
  16. m_fPresent = FALSE;
  17. m_fDestroy = FALSE;
  18. m_flLastProgress = 0.0f;
  19. m_pThread = ::GetThread();
  20. }
  21. //---------------------------------------------------------------------------
  22. Action::~Action()
  23. {
  24. AssertMsg(!m_DEBUG_fInFire, "Can't destroy if should be locked for Schedule::xwFireNL()\n");
  25. //
  26. // We need to notify the application that it needs to cleanup, so we
  27. // can't take the Scheduler lock.
  28. //
  29. // We also need to directly setup the "Last" members so that xwFireNL()
  30. // will signal the application that the Action is being destroyed.
  31. //
  32. xwFireFinalNL();
  33. if (m_plstParent != NULL) {
  34. m_plstParent->Unlink(this);
  35. }
  36. }
  37. /***************************************************************************\
  38. *
  39. * Action::xwDeleteHandle
  40. *
  41. * xwDeleteHandle() is called when the application calls ::DeleteHandle() on
  42. * an object.
  43. *
  44. \***************************************************************************/
  45. BOOL
  46. Action::xwDeleteHandle()
  47. {
  48. if (m_fDestroy) {
  49. PromptInvalid("Can not call DeleteHandle() on an Action after the final callback");
  50. return FALSE;
  51. }
  52. //
  53. // When the user calls DeleteHandle() on an Action, we need to remove it
  54. // from the Scheduler's lists. It may also already be in a callback list
  55. // currently be processed, but that is okay. The important thing is to
  56. // Unlock() the Scheduler's reference so that we can properly be destroyed.
  57. //
  58. if (m_plstParent) {
  59. //
  60. // Still in a Scheduler list, so the Scheduler still has a valid lock.
  61. //
  62. m_plstParent->Unlink(this);
  63. m_plstParent = NULL;
  64. VerifyMsg(xwUnlock(), "Should still be valid after the Scheduler Unlock()");
  65. }
  66. //
  67. // If the object isn't destroyed, we need to clear out the callback
  68. // right now since the object that is being called is no longer valid.
  69. //
  70. // Unlike Gadgets, we actually clear out the callback here since Actions
  71. // are usually "simple" objects without complicated callbacks. They do
  72. // guarantee that to receive all callbacks before being destroyed. They
  73. // only guarentee to receive a "destroy" message when the Action is
  74. // actually destroyed.
  75. //
  76. BOOL fValid = BaseObject::xwDeleteHandle();
  77. if (fValid) {
  78. //
  79. // The Action may still be valid if it is in a Scheduler callback list.
  80. //
  81. xwFireFinalNL();
  82. }
  83. return fValid;
  84. }
  85. //---------------------------------------------------------------------------
  86. Action *
  87. Action::Build(
  88. IN GList<Action> * plstParent, // List containing Action
  89. IN const GMA_ACTION * pma, // Timing information
  90. IN DWORD dwCurTick, // Current time
  91. IN BOOL fPresent) // Action is already present
  92. {
  93. AssertMsg(plstParent != NULL, "Must specify a parent");
  94. Action * pact = ClientNew(Action);
  95. if (pact == NULL) {
  96. return NULL;
  97. }
  98. //
  99. // Copy the Action information over and determine the amount of time between
  100. // timeslices.
  101. //
  102. // For the default time (0), use 10 ms.
  103. // For no time (-1), use 0 ms.
  104. //
  105. pact->m_ma = *pma;
  106. pact->m_dwLastProcessTick = dwCurTick;
  107. if (pact->m_ma.dwPause == 0) {
  108. pact->m_ma.dwPause = 10;
  109. } else if (pact->m_ma.dwPause == (DWORD) -1) {
  110. pact->m_ma.dwPause = 0;
  111. }
  112. //
  113. // When creating the new Action, it needs to be in the future or the
  114. // beginning part of the Action may be clipped. However, if it is actually
  115. // in the present, set the starting time to right now so that it doesn't
  116. // get delayed.
  117. //
  118. pact->m_fSingleShot = IsPresentTime(pma->flDuration);
  119. pact->m_plstParent = plstParent;
  120. if (fPresent) {
  121. pact->ResetPresent(dwCurTick);
  122. } else {
  123. pact->ResetFuture(dwCurTick, TRUE);
  124. }
  125. pact->SetPresent(fPresent);
  126. return pact;
  127. }
  128. //---------------------------------------------------------------------------
  129. void
  130. Action::Process(DWORD dwCurTime, BOOL * pfFinishedPeriod, BOOL * pfFire)
  131. {
  132. AssertWritePtr(pfFinishedPeriod);
  133. AssertWritePtr(pfFire);
  134. #if DBG
  135. m_DEBUG_fFireValid = FALSE;
  136. #endif // DBG
  137. *pfFire = FALSE;
  138. *pfFinishedPeriod = FALSE;
  139. if (IsPresent()) {
  140. //
  141. // Processing a present action, so determine our progress through the
  142. // action and callback.
  143. //
  144. if (m_fSingleShot) {
  145. //
  146. // Single-shot Action
  147. //
  148. m_dwLastProcessTick = dwCurTime;
  149. m_flLastProgress = 1.0f;
  150. *pfFinishedPeriod = TRUE;
  151. *pfFire = TRUE;
  152. } else {
  153. //
  154. // Continuous Action
  155. //
  156. int nElapsed = ComputePastTickDelta(dwCurTime, m_dwStartTick);
  157. float flProgress = (nElapsed / m_ma.flDuration) / 1000.0f;
  158. if (flProgress > 1.0f) {
  159. flProgress = 1.0f;
  160. }
  161. int nDelta = ComputeTickDelta(dwCurTime, m_dwLastProcessTick + GetPauseTimeOut());
  162. *pfFire = nDelta > 0; // Full pause has elapsed
  163. if (*pfFire) {
  164. m_dwLastProcessTick = dwCurTime;
  165. }
  166. *pfFinishedPeriod = (flProgress >= 1.0f);
  167. m_flLastProgress = flProgress;
  168. }
  169. #if DBG
  170. m_DEBUG_fFireValid = *pfFire;
  171. #endif // DBG
  172. AssertMsg(!m_fDestroy, "Should not be marked as being destroyed yet");
  173. } else {
  174. //
  175. // Processing a future action, so advance counters
  176. //
  177. int nElapsed = ComputeTickDelta(dwCurTime, m_dwStartTick);
  178. if (nElapsed >= 0) {
  179. //
  180. // The action is now ready to be executed.
  181. //
  182. *pfFinishedPeriod = TRUE;
  183. }
  184. }
  185. }
  186. //---------------------------------------------------------------------------
  187. void
  188. Action::xwFireNL()
  189. {
  190. //
  191. // NOTE: xwFireNL() expects that m_flLastProgress and m_fDestroy were
  192. // properly filled in from the last call to Process().
  193. //
  194. AssertMsg(m_DEBUG_fFireValid, "Only valid if last call to Process() returned fFire");
  195. GMA_ACTIONINFO mai;
  196. mai.hact = (HACTION) GetHandle();
  197. mai.pvData = m_ma.pvData;
  198. mai.flDuration = m_ma.flDuration;
  199. mai.flProgress = m_flLastProgress;
  200. mai.cEvent = m_cEventsInPeriod++;
  201. mai.fFinished = m_fDestroy;
  202. #if DBG_CHECK_CALLBACKS
  203. BEGIN_CALLBACK()
  204. #endif
  205. __try
  206. {
  207. (m_ma.pfnProc)(&mai);
  208. }
  209. __except(StdExceptionFilter(GetExceptionInformation()))
  210. {
  211. ExitProcess(GetExceptionCode());
  212. }
  213. #if DBG_CHECK_CALLBACKS
  214. END_CALLBACK()
  215. #endif
  216. //
  217. // If the Action is complete and has not been manually destroyed, destroy
  218. // it now. The Action will still exist until the Scheduler actually
  219. // Unlock()'s it.
  220. //
  221. if ((!m_fDestroy) && m_fDeleteInFire) {
  222. AssertMsg(IsComplete(), "Must be complete to destroy");
  223. VerifyMsg(xwDeleteHandle(), "Should still be valid.");
  224. }
  225. }
  226. /***************************************************************************\
  227. *
  228. * Action::xwFireFinalNL
  229. *
  230. * xwFireFinalNL() fires the final notification to the Action. Any
  231. * notifications that the Action fires after this point will be sent to
  232. * EmptyActionProc(). This function can be called both by the destructor as
  233. * well as xwDeleteHandle() when the object doesn't finally go away.
  234. *
  235. \***************************************************************************/
  236. void
  237. Action::xwFireFinalNL()
  238. {
  239. if (m_fDestroy) {
  240. return;
  241. }
  242. #if DBG
  243. m_DEBUG_fFireValid = TRUE;
  244. #endif // DBG
  245. m_flLastProgress = 1.0f;
  246. m_fDestroy = TRUE;
  247. xwFireNL();
  248. m_ma.pfnProc = EmptyActionProc;
  249. }
  250. //---------------------------------------------------------------------------
  251. void
  252. Action::EndPeriod()
  253. {
  254. if ((m_ma.cRepeat != 0) && (m_ma.cRepeat != (UINT) -1)) {
  255. m_ma.cRepeat--;
  256. }
  257. }
  258. //---------------------------------------------------------------------------
  259. void
  260. Action::EmptyActionProc(GMA_ACTIONINFO * pmai)
  261. {
  262. UNREFERENCED_PARAMETER(pmai);
  263. }
  264. #if DBG
  265. //---------------------------------------------------------------------------
  266. void
  267. Action::DEBUG_MarkInFire(BOOL fInFire)
  268. {
  269. AssertMsg(!fInFire != !m_DEBUG_fInFire, "Must be switching states");
  270. m_DEBUG_fInFire = fInFire;
  271. }
  272. #endif // DBG