1 /* 2 * ITfDocumentMgr implementation 3 * 4 * Copyright 2009 Aric Stewart, CodeWeavers 5 * 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. 10 * 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. 15 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "msctf_internal.h" 22 23 typedef struct tagDocumentMgr { 24 ITfDocumentMgr ITfDocumentMgr_iface; 25 ITfSource ITfSource_iface; 26 LONG refCount; 27 28 /* Aggregation */ 29 ITfCompartmentMgr *CompartmentMgr; 30 31 ITfContext* contextStack[2]; /* limit of 2 contexts */ 32 ITfThreadMgrEventSink* ThreadMgrSink; 33 34 struct list TransitoryExtensionSink; 35 } DocumentMgr; 36 37 typedef struct tagEnumTfContext { 38 IEnumTfContexts IEnumTfContexts_iface; 39 LONG refCount; 40 41 DWORD index; 42 DocumentMgr *docmgr; 43 } EnumTfContext; 44 45 static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut); 46 47 static inline DocumentMgr *impl_from_ITfDocumentMgr(ITfDocumentMgr *iface) 48 { 49 return CONTAINING_RECORD(iface, DocumentMgr, ITfDocumentMgr_iface); 50 } 51 52 static inline DocumentMgr *impl_from_ITfSource(ITfSource *iface) 53 { 54 return CONTAINING_RECORD(iface, DocumentMgr, ITfSource_iface); 55 } 56 57 static inline EnumTfContext *impl_from_IEnumTfContexts(IEnumTfContexts *iface) 58 { 59 return CONTAINING_RECORD(iface, EnumTfContext, IEnumTfContexts_iface); 60 } 61 62 static void DocumentMgr_Destructor(DocumentMgr *This) 63 { 64 ITfThreadMgr *tm; 65 TRACE("destroying %p\n", This); 66 67 TF_GetThreadMgr(&tm); 68 ThreadMgr_OnDocumentMgrDestruction(tm, &This->ITfDocumentMgr_iface); 69 70 if (This->contextStack[0]) 71 ITfContext_Release(This->contextStack[0]); 72 if (This->contextStack[1]) 73 ITfContext_Release(This->contextStack[1]); 74 free_sinks(&This->TransitoryExtensionSink); 75 CompartmentMgr_Destructor(This->CompartmentMgr); 76 HeapFree(GetProcessHeap(),0,This); 77 } 78 79 static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID iid, LPVOID *ppvOut) 80 { 81 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 82 *ppvOut = NULL; 83 84 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfDocumentMgr)) 85 { 86 *ppvOut = &This->ITfDocumentMgr_iface; 87 } 88 else if (IsEqualIID(iid, &IID_ITfSource)) 89 { 90 *ppvOut = &This->ITfSource_iface; 91 } 92 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) 93 { 94 *ppvOut = This->CompartmentMgr; 95 } 96 97 if (*ppvOut) 98 { 99 ITfDocumentMgr_AddRef(iface); 100 return S_OK; 101 } 102 103 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 104 return E_NOINTERFACE; 105 } 106 107 static ULONG WINAPI DocumentMgr_AddRef(ITfDocumentMgr *iface) 108 { 109 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 110 return InterlockedIncrement(&This->refCount); 111 } 112 113 static ULONG WINAPI DocumentMgr_Release(ITfDocumentMgr *iface) 114 { 115 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 116 ULONG ret; 117 118 ret = InterlockedDecrement(&This->refCount); 119 if (ret == 0) 120 DocumentMgr_Destructor(This); 121 return ret; 122 } 123 124 /***************************************************** 125 * ITfDocumentMgr functions 126 *****************************************************/ 127 static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface, 128 TfClientId tidOwner, 129 DWORD dwFlags, IUnknown *punk, ITfContext **ppic, 130 TfEditCookie *pecTextStore) 131 { 132 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 133 TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore); 134 return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore); 135 } 136 137 static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic) 138 { 139 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 140 ITfContext *check; 141 142 TRACE("(%p) %p\n",This,pic); 143 144 if (This->contextStack[1]) /* FUll */ 145 return TF_E_STACKFULL; 146 147 if (!pic || FAILED(ITfContext_QueryInterface(pic,&IID_ITfContext,(LPVOID*) &check))) 148 return E_INVALIDARG; 149 150 if (This->contextStack[0] == NULL) 151 ITfThreadMgrEventSink_OnInitDocumentMgr(This->ThreadMgrSink,iface); 152 153 This->contextStack[1] = This->contextStack[0]; 154 This->contextStack[0] = check; 155 156 Context_Initialize(check, iface); 157 ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check); 158 159 return S_OK; 160 } 161 162 static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags) 163 { 164 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 165 TRACE("(%p) 0x%x\n",This,dwFlags); 166 167 if (dwFlags == TF_POPF_ALL) 168 { 169 int i; 170 171 for (i = 0; i < sizeof(This->contextStack)/sizeof(This->contextStack[0]); i++) 172 if (This->contextStack[i]) 173 { 174 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink, This->contextStack[i]); 175 Context_Uninitialize(This->contextStack[i]); 176 ITfContext_Release(This->contextStack[i]); 177 This->contextStack[i] = NULL; 178 } 179 180 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); 181 return S_OK; 182 } 183 184 if (dwFlags) 185 return E_INVALIDARG; 186 187 if (This->contextStack[1] == NULL) /* Cannot pop last context */ 188 return E_FAIL; 189 190 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink,This->contextStack[0]); 191 Context_Uninitialize(This->contextStack[0]); 192 ITfContext_Release(This->contextStack[0]); 193 This->contextStack[0] = This->contextStack[1]; 194 This->contextStack[1] = NULL; 195 196 if (This->contextStack[0] == NULL) 197 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); 198 199 return S_OK; 200 } 201 202 static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic) 203 { 204 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 205 TRACE("(%p)\n",This); 206 if (!ppic) 207 return E_INVALIDARG; 208 209 if (This->contextStack[0]) 210 ITfContext_AddRef(This->contextStack[0]); 211 212 *ppic = This->contextStack[0]; 213 214 return S_OK; 215 } 216 217 static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **ppic) 218 { 219 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 220 ITfContext *tgt; 221 222 TRACE("(%p)\n",This); 223 if (!ppic) 224 return E_INVALIDARG; 225 226 if (This->contextStack[1]) 227 tgt = This->contextStack[1]; 228 else 229 tgt = This->contextStack[0]; 230 231 if (tgt) 232 ITfContext_AddRef(tgt); 233 234 *ppic = tgt; 235 236 return S_OK; 237 } 238 239 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum) 240 { 241 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 242 TRACE("(%p) %p\n",This,ppEnum); 243 return EnumTfContext_Constructor(This, ppEnum); 244 } 245 246 static const ITfDocumentMgrVtbl DocumentMgrVtbl = 247 { 248 DocumentMgr_QueryInterface, 249 DocumentMgr_AddRef, 250 DocumentMgr_Release, 251 DocumentMgr_CreateContext, 252 DocumentMgr_Push, 253 DocumentMgr_Pop, 254 DocumentMgr_GetTop, 255 DocumentMgr_GetBase, 256 DocumentMgr_EnumContexts 257 }; 258 259 static HRESULT WINAPI DocumentMgrSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) 260 { 261 DocumentMgr *This = impl_from_ITfSource(iface); 262 return ITfDocumentMgr_QueryInterface(&This->ITfDocumentMgr_iface, iid, ppvOut); 263 } 264 265 static ULONG WINAPI DocumentMgrSource_AddRef(ITfSource *iface) 266 { 267 DocumentMgr *This = impl_from_ITfSource(iface); 268 return ITfDocumentMgr_AddRef(&This->ITfDocumentMgr_iface); 269 } 270 271 static ULONG WINAPI DocumentMgrSource_Release(ITfSource *iface) 272 { 273 DocumentMgr *This = impl_from_ITfSource(iface); 274 return ITfDocumentMgr_Release(&This->ITfDocumentMgr_iface); 275 } 276 277 /***************************************************** 278 * ITfSource functions 279 *****************************************************/ 280 static HRESULT WINAPI DocumentMgrSource_AdviseSink(ITfSource *iface, 281 REFIID riid, IUnknown *punk, DWORD *pdwCookie) 282 { 283 DocumentMgr *This = impl_from_ITfSource(iface); 284 285 TRACE("(%p) %s %p %p\n", This, debugstr_guid(riid), punk, pdwCookie); 286 287 if (!riid || !punk || !pdwCookie) 288 return E_INVALIDARG; 289 290 if (IsEqualIID(riid, &IID_ITfTransitoryExtensionSink)) 291 { 292 WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n"); 293 return advise_sink(&This->TransitoryExtensionSink, &IID_ITfTransitoryExtensionSink, 294 COOKIE_MAGIC_DMSINK, punk, pdwCookie); 295 } 296 297 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); 298 return E_NOTIMPL; 299 } 300 301 static HRESULT WINAPI DocumentMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) 302 { 303 DocumentMgr *This = impl_from_ITfSource(iface); 304 305 TRACE("(%p) %x\n",This,pdwCookie); 306 307 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_DMSINK) 308 return E_INVALIDARG; 309 310 return unadvise_sink(pdwCookie); 311 } 312 313 static const ITfSourceVtbl DocumentMgrSourceVtbl = 314 { 315 DocumentMgrSource_QueryInterface, 316 DocumentMgrSource_AddRef, 317 DocumentMgrSource_Release, 318 DocumentMgrSource_AdviseSink, 319 DocumentMgrSource_UnadviseSink, 320 }; 321 322 HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut) 323 { 324 DocumentMgr *This; 325 326 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr)); 327 if (This == NULL) 328 return E_OUTOFMEMORY; 329 330 This->ITfDocumentMgr_iface.lpVtbl = &DocumentMgrVtbl; 331 This->ITfSource_iface.lpVtbl = &DocumentMgrSourceVtbl; 332 This->refCount = 1; 333 This->ThreadMgrSink = ThreadMgrSink; 334 list_init(&This->TransitoryExtensionSink); 335 336 CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); 337 338 *ppOut = &This->ITfDocumentMgr_iface; 339 TRACE("returning %p\n", *ppOut); 340 return S_OK; 341 } 342 343 /************************************************** 344 * IEnumTfContexts implementation 345 **************************************************/ 346 static void EnumTfContext_Destructor(EnumTfContext *This) 347 { 348 TRACE("destroying %p\n", This); 349 HeapFree(GetProcessHeap(),0,This); 350 } 351 352 static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut) 353 { 354 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 355 *ppvOut = NULL; 356 357 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts)) 358 { 359 *ppvOut = &This->IEnumTfContexts_iface; 360 } 361 362 if (*ppvOut) 363 { 364 IEnumTfContexts_AddRef(iface); 365 return S_OK; 366 } 367 368 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 369 return E_NOINTERFACE; 370 } 371 372 static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface) 373 { 374 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 375 return InterlockedIncrement(&This->refCount); 376 } 377 378 static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface) 379 { 380 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 381 ULONG ret; 382 383 ret = InterlockedDecrement(&This->refCount); 384 if (ret == 0) 385 EnumTfContext_Destructor(This); 386 return ret; 387 } 388 389 static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface, 390 ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) 391 { 392 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 393 ULONG fetched = 0; 394 395 TRACE("(%p)\n",This); 396 397 if (rgContext == NULL) return E_POINTER; 398 399 while (fetched < ulCount) 400 { 401 if (This->index > 1) 402 break; 403 404 if (!This->docmgr->contextStack[This->index]) 405 break; 406 407 *rgContext = This->docmgr->contextStack[This->index]; 408 ITfContext_AddRef(*rgContext); 409 410 ++This->index; 411 ++fetched; 412 ++rgContext; 413 } 414 415 if (pcFetched) *pcFetched = fetched; 416 return fetched == ulCount ? S_OK : S_FALSE; 417 } 418 419 static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt) 420 { 421 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 422 TRACE("(%p)\n",This); 423 This->index += celt; 424 return S_OK; 425 } 426 427 static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface) 428 { 429 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 430 TRACE("(%p)\n",This); 431 This->index = 0; 432 return S_OK; 433 } 434 435 static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface, 436 IEnumTfContexts **ppenum) 437 { 438 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 439 HRESULT res; 440 441 TRACE("(%p)\n",This); 442 443 if (ppenum == NULL) return E_POINTER; 444 445 res = EnumTfContext_Constructor(This->docmgr, ppenum); 446 if (SUCCEEDED(res)) 447 { 448 EnumTfContext *new_This = impl_from_IEnumTfContexts(*ppenum); 449 new_This->index = This->index; 450 } 451 return res; 452 } 453 454 static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={ 455 EnumTfContext_QueryInterface, 456 EnumTfContext_AddRef, 457 EnumTfContext_Release, 458 459 EnumTfContext_Clone, 460 EnumTfContext_Next, 461 EnumTfContext_Reset, 462 EnumTfContext_Skip 463 }; 464 465 static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut) 466 { 467 EnumTfContext *This; 468 469 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext)); 470 if (This == NULL) 471 return E_OUTOFMEMORY; 472 473 This->IEnumTfContexts_iface.lpVtbl = &IEnumTfContexts_Vtbl; 474 This->refCount = 1; 475 This->docmgr = mgr; 476 477 *ppOut = &This->IEnumTfContexts_iface; 478 TRACE("returning %p\n", *ppOut); 479 return S_OK; 480 } 481