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.

525 lines
14 KiB

  1. //
  2. // icclean.cpp
  3. //
  4. #include "private.h"
  5. #include "tim.h"
  6. #include "ic.h"
  7. #include "compose.h"
  8. #include "assembly.h"
  9. class CCleanupShared
  10. {
  11. public:
  12. CCleanupShared(POSTCLEANUPCALLBACK pfnPostCleanup, LONG_PTR lPrivate)
  13. {
  14. _cRef = 1;
  15. _pfnPostCleanup = pfnPostCleanup;
  16. _lPrivate = lPrivate;
  17. }
  18. ~CCleanupShared()
  19. {
  20. SYSTHREAD *psfn = GetSYSTHREAD();
  21. if (psfn == NULL)
  22. return;
  23. if (psfn->ptim != NULL)
  24. {
  25. psfn->ptim->_SendEndCleanupNotifications();
  26. }
  27. if (_pfnPostCleanup != NULL)
  28. {
  29. _pfnPostCleanup(FALSE, _lPrivate);
  30. }
  31. if (psfn->ptim != NULL)
  32. {
  33. psfn->ptim->_HandlePendingCleanupContext();
  34. }
  35. }
  36. void _AddRef()
  37. {
  38. _cRef++;
  39. }
  40. LONG _Release()
  41. {
  42. LONG cRef = --_cRef;
  43. if (_cRef == 0)
  44. {
  45. delete this;
  46. }
  47. return cRef;
  48. }
  49. private:
  50. LONG _cRef;
  51. POSTCLEANUPCALLBACK _pfnPostCleanup;
  52. LONG_PTR _lPrivate;
  53. };
  54. class CCleanupQueueItem : public CAsyncQueueItem
  55. {
  56. public:
  57. CCleanupQueueItem(BOOL fSync, CCleanupShared *pcs, CStructArray<TfClientId> *prgClientIds) : CAsyncQueueItem(fSync)
  58. {
  59. _prgClientIds = prgClientIds;
  60. if (!fSync)
  61. {
  62. _pcs = pcs;
  63. _pcs->_AddRef();
  64. }
  65. }
  66. ~CCleanupQueueItem()
  67. {
  68. delete _prgClientIds;
  69. _CheckCleanupShared();
  70. }
  71. HRESULT DoDispatch(CInputContext *pic);
  72. private:
  73. void _CheckCleanupShared()
  74. {
  75. // last queue item?
  76. if (_pcs != NULL)
  77. {
  78. _pcs->_Release();
  79. _pcs = NULL;
  80. }
  81. }
  82. CStructArray<TfClientId> *_prgClientIds;
  83. CCleanupShared *_pcs;
  84. };
  85. //+---------------------------------------------------------------------------
  86. //
  87. // DoDispatch
  88. //
  89. //----------------------------------------------------------------------------
  90. HRESULT CCleanupQueueItem::DoDispatch(CInputContext *pic)
  91. {
  92. pic->_CleanupContext(_prgClientIds);
  93. // if this was the last pending lock, let the caller know
  94. _CheckCleanupShared();
  95. return S_OK;
  96. }
  97. //+---------------------------------------------------------------------------
  98. //
  99. // _CleanupContext
  100. //
  101. //----------------------------------------------------------------------------
  102. void CInputContext::_CleanupContext(CStructArray<TfClientId> *prgClientIds)
  103. {
  104. int i;
  105. int j;
  106. CLEANUPSINK *pSink;
  107. Assert(!(_dwEditSessionFlags & TF_ES_INEDITSESSION)); // shouldn't get this far
  108. Assert(_tidInEditSession == TF_CLIENTID_NULL); // there should never be another session in progress -- this is not a reentrant func
  109. _dwEditSessionFlags = (TF_ES_INEDITSESSION | TF_ES_READWRITE | TF_ES_PROPERTY_WRITE);
  110. //
  111. // call any tips that want to cleanup
  112. //
  113. for (i=0; i<_rgCleanupSinks.Count(); i++)
  114. {
  115. pSink = _rgCleanupSinks.GetPtr(i);
  116. if (prgClientIds != NULL)
  117. {
  118. // we only want to call sinks with client ids on this list...
  119. for (j=0; j<prgClientIds->Count(); j++)
  120. {
  121. if (*prgClientIds->GetPtr(j) == pSink->tid)
  122. break;
  123. }
  124. // if we didn't find the sink's tid, skip it
  125. if (j == prgClientIds->Count())
  126. continue;
  127. }
  128. _tidInEditSession = pSink->tid;
  129. pSink->pSink->OnCleanupContext(_ec, this);
  130. _NotifyEndEdit();
  131. _IncEditCookie(); // next edit cookie value
  132. }
  133. _dwEditSessionFlags = 0;
  134. _tidInEditSession = TF_CLIENTID_NULL;
  135. //
  136. // wipe any left over compositions
  137. //
  138. TerminateComposition(NULL);
  139. Assert(_pCompositionList == NULL);
  140. }
  141. //+---------------------------------------------------------------------------
  142. //
  143. // _GetCleanupListIndex
  144. //
  145. //----------------------------------------------------------------------------
  146. int CInputContext::_GetCleanupListIndex(TfClientId tid)
  147. {
  148. int i;
  149. for (i=0; i<_rgCleanupSinks.Count(); i++)
  150. {
  151. if (_rgCleanupSinks.GetPtr(i)->tid == tid)
  152. return i;
  153. }
  154. return -1;
  155. }
  156. //+---------------------------------------------------------------------------
  157. //
  158. // _ContextNeedsCleanup
  159. //
  160. //----------------------------------------------------------------------------
  161. BOOL CInputContext::_ContextNeedsCleanup(const GUID *pCatId, LANGID langid, CStructArray<TfClientId> **pprgClientIds)
  162. {
  163. int i;
  164. int j;
  165. CLEANUPSINK *pSink;
  166. SYSTHREAD *psfn;
  167. CAssemblyList *pAsmList;
  168. CAssembly *pAsm;
  169. ASSEMBLYITEM *pAsmItem;
  170. TfGuidAtom gaAsmItem;
  171. TfClientId *ptid;
  172. *pprgClientIds = NULL; // NULL means "all"
  173. // any cleanup sinks?
  174. if (pCatId == NULL)
  175. return (_pCompositionList != NULL || _rgCleanupSinks.Count() > 0);
  176. if ((psfn = GetSYSTHREAD()) == NULL)
  177. goto Exit;
  178. if ((pAsmList = EnsureAssemblyList(psfn)) == NULL)
  179. goto Exit;
  180. if ((pAsm = pAsmList->FindAssemblyByLangId(langid)) == NULL)
  181. goto Exit;
  182. // need to lookup each sink in the assembly list
  183. // if we can find a tip in the list with a matching
  184. // catid, then we need to lock this ic
  185. for (i=0; i<_rgCleanupSinks.Count(); i++)
  186. {
  187. pSink = _rgCleanupSinks.GetPtr(i);
  188. for (j=0; j<pAsm->Count(); j++)
  189. {
  190. pAsmItem = pAsm->GetItem(j);
  191. if ((MyRegisterGUID(pAsmItem->clsid, &gaAsmItem) == S_OK &&
  192. gaAsmItem == pSink->tid) ||
  193. (g_gaApp == pSink->tid))
  194. {
  195. if (*pprgClientIds == NULL)
  196. {
  197. // need to alloc the [out] array of client ids
  198. if ((*pprgClientIds = new CStructArray<TfClientId>) == NULL)
  199. return FALSE;
  200. }
  201. ptid = (*pprgClientIds)->Append(1);
  202. if (ptid != NULL)
  203. {
  204. *ptid = pSink->tid;
  205. }
  206. break;
  207. }
  208. }
  209. }
  210. Exit:
  211. return (_pCompositionList != NULL || *pprgClientIds != NULL);
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // _HandlePendingCleanupContext
  216. //
  217. //----------------------------------------------------------------------------
  218. void CThreadInputMgr::_HandlePendingCleanupContext()
  219. {
  220. Assert(_fPendingCleanupContext);
  221. _fPendingCleanupContext = FALSE;
  222. if (_pPendingCleanupContext == NULL)
  223. return;
  224. CLEANUPCONTEXT *pcc = _pPendingCleanupContext;
  225. _pPendingCleanupContext = NULL;
  226. _CleanupContextsWorker(pcc);
  227. cicMemFree(pcc);
  228. }
  229. //+---------------------------------------------------------------------------
  230. //
  231. // _CleanupContexts
  232. //
  233. //----------------------------------------------------------------------------
  234. void CThreadInputMgr::_CleanupContexts(CLEANUPCONTEXT *pcc)
  235. {
  236. if (pcc->fSync && _fPendingCleanupContext)
  237. {
  238. // this can happen from Deactivate
  239. // can't interrupt another cleanup synchronously, abort the request
  240. if (pcc->pfnPostCleanup != NULL)
  241. {
  242. pcc->pfnPostCleanup(TRUE, pcc->lPrivate);
  243. }
  244. return;
  245. }
  246. if (_pPendingCleanupContext != NULL)
  247. {
  248. // abort the callback and free the pending cleanup
  249. if (_pPendingCleanupContext->pfnPostCleanup != NULL)
  250. {
  251. _pPendingCleanupContext->pfnPostCleanup(TRUE, _pPendingCleanupContext->lPrivate);
  252. }
  253. cicMemFree(_pPendingCleanupContext);
  254. _pPendingCleanupContext = NULL;
  255. }
  256. if (!_fPendingCleanupContext)
  257. {
  258. _CleanupContextsWorker(pcc);
  259. return;
  260. }
  261. // we've interrupted a cleanup in progress
  262. // allocate some space for the params
  263. if ((_pPendingCleanupContext = (CLEANUPCONTEXT *)cicMemAlloc(sizeof(CLEANUPCONTEXT))) == NULL)
  264. {
  265. if (pcc->pfnPostCleanup != NULL)
  266. {
  267. // abort the cleanup
  268. pcc->pfnPostCleanup(TRUE, pcc->lPrivate);
  269. }
  270. return;
  271. }
  272. *_pPendingCleanupContext = *pcc;
  273. }
  274. //+---------------------------------------------------------------------------
  275. //
  276. // _CleanupContexts
  277. //
  278. //----------------------------------------------------------------------------
  279. void CThreadInputMgr::_CleanupContextsWorker(CLEANUPCONTEXT *pcc)
  280. {
  281. int iDim;
  282. int iContext;
  283. CDocumentInputManager *dim;
  284. CInputContext *pic;
  285. CCleanupQueueItem *pItem;
  286. HRESULT hr;
  287. CCleanupShared *pcs;
  288. CStructArray<TfClientId> *prgClientIds;
  289. _fPendingCleanupContext = TRUE;
  290. pcs = NULL;
  291. _CalcAndSendBeginCleanupNotifications(pcc);
  292. // enum all the ic's on this thread
  293. for (iDim = 0; iDim < _rgdim.Count(); iDim++)
  294. {
  295. dim = _rgdim.Get(iDim);
  296. for (iContext = 0; iContext <= dim->_GetCurrentStack(); iContext++)
  297. {
  298. pic = dim->_GetIC(iContext);
  299. if (!pic->_ContextNeedsCleanup(pcc->pCatId, pcc->langid, &prgClientIds))
  300. continue;
  301. if (!pcc->fSync && pcs == NULL)
  302. {
  303. // allocate a shared counter
  304. if ((pcs = new CCleanupShared(pcc->pfnPostCleanup, pcc->lPrivate)) == NULL)
  305. {
  306. delete prgClientIds;
  307. return;
  308. }
  309. }
  310. // queue an async callback
  311. if (pItem = new CCleanupQueueItem(pcc->fSync, pcs, prgClientIds))
  312. {
  313. pItem->_CheckReadOnly(pic);
  314. if (pic->_QueueItem(pItem->GetItem(), FALSE, &hr) != S_OK)
  315. {
  316. Assert(0); // couldn't get app lock
  317. }
  318. pItem->_Release();
  319. }
  320. }
  321. }
  322. if (pcs == NULL)
  323. {
  324. // we didn't need to allocate any shared ref (either no ic's, or lock reqs were sync only)
  325. _SendEndCleanupNotifications();
  326. if (pcc->pfnPostCleanup != NULL)
  327. {
  328. pcc->pfnPostCleanup(FALSE, pcc->lPrivate);
  329. }
  330. _HandlePendingCleanupContext();
  331. }
  332. else
  333. {
  334. // release our ref
  335. pcs->_Release();
  336. }
  337. }
  338. //+---------------------------------------------------------------------------
  339. //
  340. // _CalcAndSendBeginCleanupNotifications
  341. //
  342. //----------------------------------------------------------------------------
  343. void CThreadInputMgr::_CalcAndSendBeginCleanupNotifications(CLEANUPCONTEXT *pcc)
  344. {
  345. UINT i;
  346. int j;
  347. int iDim;
  348. int iContext;
  349. CDocumentInputManager *dim;
  350. CInputContext *pic;
  351. CTip *tip;
  352. CStructArray<TfClientId> *prgClientIds;
  353. // first clear the _fNeedCleanupCall for all tips
  354. for (i=0; i<_GetTIPCount(); i++)
  355. {
  356. _rgTip.Get(i)->_fNeedCleanupCall = FALSE;
  357. }
  358. // now set the flag where appropriate
  359. // enum all the ic's on this thread
  360. for (iDim = 0; iDim < _rgdim.Count(); iDim++)
  361. {
  362. dim = _rgdim.Get(iDim);
  363. for (iContext = 0; iContext <= dim->_GetCurrentStack(); iContext++)
  364. {
  365. pic = dim->_GetIC(iContext);
  366. if (!pic->_ContextNeedsCleanup(pcc->pCatId, pcc->langid, &prgClientIds))
  367. continue;
  368. for (i=0; i<_GetTIPCount(); i++)
  369. {
  370. tip = _rgTip.Get(i);
  371. if (tip->_pCleanupDurationSink == NULL)
  372. continue; // no sink, no notification
  373. if (prgClientIds == NULL)
  374. {
  375. // all sinks on this ic need callbacks
  376. for (j=0; j<pic->_GetCleanupSinks()->Count(); j++)
  377. {
  378. if (pic->_GetCleanupSinks()->GetPtr(j)->tid == tip->_guidatom)
  379. {
  380. tip->_fNeedCleanupCall = TRUE;
  381. break;
  382. }
  383. }
  384. }
  385. else
  386. {
  387. // just the tips in prgClientIds need callbacks
  388. for (j=0; j<prgClientIds->Count(); j++)
  389. {
  390. if (*prgClientIds->GetPtr(j) == tip->_guidatom)
  391. {
  392. tip->_fNeedCleanupCall = TRUE;
  393. break;
  394. }
  395. }
  396. }
  397. }
  398. delete prgClientIds;
  399. }
  400. }
  401. // now send the notifications
  402. for (i=0; i<_GetTIPCount(); i++)
  403. {
  404. tip = _rgTip.Get(i);
  405. if (tip->_fNeedCleanupCall)
  406. {
  407. Assert(tip->_pCleanupDurationSink != NULL);
  408. tip->_pCleanupDurationSink->OnStartCleanupContext();
  409. }
  410. }
  411. }
  412. //+---------------------------------------------------------------------------
  413. //
  414. // _SendEndCleanupNotifications
  415. //
  416. //----------------------------------------------------------------------------
  417. void CThreadInputMgr::_SendEndCleanupNotifications()
  418. {
  419. CTip *tip;
  420. UINT i;
  421. for (i=0; i<_GetTIPCount(); i++)
  422. {
  423. tip = _rgTip.Get(i);
  424. if (tip->_fNeedCleanupCall)
  425. {
  426. if (tip->_pCleanupDurationSink != NULL)
  427. {
  428. tip->_pCleanupDurationSink->OnEndCleanupContext();
  429. }
  430. tip->_fNeedCleanupCall = FALSE;
  431. }
  432. }
  433. }