1 /* 2 * ITfContext 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 "config.h" 22 23 #include <stdarg.h> 24 25 #define COBJMACROS 26 27 #include "wine/debug.h" 28 #include "windef.h" 29 #include "winbase.h" 30 #include "winreg.h" 31 #include "winuser.h" 32 #include "shlwapi.h" 33 #include "winerror.h" 34 #include "objbase.h" 35 #include "olectl.h" 36 37 #include "wine/unicode.h" 38 39 #include "msctf.h" 40 #include "msctf_internal.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(msctf); 43 44 typedef struct tagContext { 45 ITfContext ITfContext_iface; 46 ITfSource ITfSource_iface; 47 /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */ 48 /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */ 49 /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */ 50 ITfInsertAtSelection ITfInsertAtSelection_iface; 51 /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */ 52 /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */ 53 ITfSourceSingle ITfSourceSingle_iface; 54 ITextStoreACPSink ITextStoreACPSink_iface; 55 ITextStoreACPServices ITextStoreACPServices_iface; 56 LONG refCount; 57 BOOL connected; 58 59 /* Aggregation */ 60 ITfCompartmentMgr *CompartmentMgr; 61 62 TfClientId tidOwner; 63 TfEditCookie defaultCookie; 64 TS_STATUS documentStatus; 65 ITfDocumentMgr *manager; 66 67 ITextStoreACP *pITextStoreACP; 68 ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink; 69 70 ITfEditSession* currentEditSession; 71 72 /* kept as separate lists to reduce unnecessary iterations */ 73 struct list pContextKeyEventSink; 74 struct list pEditTransactionSink; 75 struct list pStatusSink; 76 struct list pTextEditSink; 77 struct list pTextLayoutSink; 78 79 } Context; 80 81 typedef struct tagEditCookie { 82 DWORD lockType; 83 Context *pOwningContext; 84 } EditCookie; 85 86 static inline Context *impl_from_ITfContext(ITfContext *iface) 87 { 88 return CONTAINING_RECORD(iface, Context, ITfContext_iface); 89 } 90 91 static inline Context *impl_from_ITfSource(ITfSource *iface) 92 { 93 return CONTAINING_RECORD(iface, Context, ITfSource_iface); 94 } 95 96 static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface) 97 { 98 return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface); 99 } 100 101 static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface) 102 { 103 return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface); 104 } 105 106 static inline Context *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface) 107 { 108 return CONTAINING_RECORD(iface, Context, ITextStoreACPSink_iface); 109 } 110 111 static inline Context *impl_from_ITextStoreACPServices(ITextStoreACPServices *iface) 112 { 113 return CONTAINING_RECORD(iface, Context, ITextStoreACPServices_iface); 114 } 115 116 static void Context_Destructor(Context *This) 117 { 118 EditCookie *cookie; 119 TRACE("destroying %p\n", This); 120 121 if (This->pITextStoreACP) 122 ITextStoreACP_Release(This->pITextStoreACP); 123 124 if (This->pITfContextOwnerCompositionSink) 125 ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink); 126 127 if (This->defaultCookie) 128 { 129 cookie = remove_Cookie(This->defaultCookie); 130 HeapFree(GetProcessHeap(),0,cookie); 131 This->defaultCookie = 0; 132 } 133 134 free_sinks(&This->pContextKeyEventSink); 135 free_sinks(&This->pEditTransactionSink); 136 free_sinks(&This->pStatusSink); 137 free_sinks(&This->pTextEditSink); 138 free_sinks(&This->pTextLayoutSink); 139 140 CompartmentMgr_Destructor(This->CompartmentMgr); 141 HeapFree(GetProcessHeap(),0,This); 142 } 143 144 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut) 145 { 146 Context *This = impl_from_ITfContext(iface); 147 *ppvOut = NULL; 148 149 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext)) 150 { 151 *ppvOut = &This->ITfContext_iface; 152 } 153 else if (IsEqualIID(iid, &IID_ITfSource)) 154 { 155 *ppvOut = &This->ITfSource_iface; 156 } 157 else if (IsEqualIID(iid, &IID_ITfInsertAtSelection)) 158 { 159 *ppvOut = &This->ITfInsertAtSelection_iface; 160 } 161 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) 162 { 163 *ppvOut = This->CompartmentMgr; 164 } 165 else if (IsEqualIID(iid, &IID_ITfSourceSingle)) 166 { 167 *ppvOut = &This->ITfSourceSingle_iface; 168 } 169 170 if (*ppvOut) 171 { 172 ITfContext_AddRef(iface); 173 return S_OK; 174 } 175 176 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 177 return E_NOINTERFACE; 178 } 179 180 static ULONG WINAPI Context_AddRef(ITfContext *iface) 181 { 182 Context *This = impl_from_ITfContext(iface); 183 return InterlockedIncrement(&This->refCount); 184 } 185 186 static ULONG WINAPI Context_Release(ITfContext *iface) 187 { 188 Context *This = impl_from_ITfContext(iface); 189 ULONG ret; 190 191 ret = InterlockedDecrement(&This->refCount); 192 if (ret == 0) 193 Context_Destructor(This); 194 return ret; 195 } 196 197 /***************************************************** 198 * ITfContext functions 199 *****************************************************/ 200 static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface, 201 TfClientId tid, ITfEditSession *pes, DWORD dwFlags, 202 HRESULT *phrSession) 203 { 204 Context *This = impl_from_ITfContext(iface); 205 HRESULT hr; 206 DWORD dwLockFlags = 0x0; 207 208 TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession); 209 210 if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE)) 211 { 212 *phrSession = E_FAIL; 213 return E_INVALIDARG; 214 } 215 216 if (!This->pITextStoreACP) 217 { 218 FIXME("No ITextStoreACP available\n"); 219 *phrSession = E_FAIL; 220 return E_FAIL; 221 } 222 223 if (!(dwFlags & TF_ES_ASYNC)) 224 dwLockFlags |= TS_LF_SYNC; 225 226 if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) 227 dwLockFlags |= TS_LF_READWRITE; 228 else if (dwFlags & TF_ES_READ) 229 dwLockFlags |= TS_LF_READ; 230 231 if (!This->documentStatus.dwDynamicFlags) 232 ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus); 233 234 if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY)) 235 { 236 *phrSession = TS_E_READONLY; 237 return S_OK; 238 } 239 240 if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession))) 241 { 242 *phrSession = E_FAIL; 243 return E_INVALIDARG; 244 } 245 246 hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession); 247 248 return hr; 249 } 250 251 static HRESULT WINAPI Context_InWriteSession (ITfContext *iface, 252 TfClientId tid, 253 BOOL *pfWriteSession) 254 { 255 Context *This = impl_from_ITfContext(iface); 256 FIXME("STUB:(%p)\n",This); 257 return E_NOTIMPL; 258 } 259 260 static HRESULT WINAPI Context_GetSelection (ITfContext *iface, 261 TfEditCookie ec, ULONG ulIndex, ULONG ulCount, 262 TF_SELECTION *pSelection, ULONG *pcFetched) 263 { 264 Context *This = impl_from_ITfContext(iface); 265 EditCookie *cookie; 266 ULONG count, i; 267 ULONG totalFetched = 0; 268 HRESULT hr = S_OK; 269 270 if (!pSelection || !pcFetched) 271 return E_INVALIDARG; 272 273 *pcFetched = 0; 274 275 if (!This->connected) 276 return TF_E_DISCONNECTED; 277 278 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) 279 return TF_E_NOLOCK; 280 281 if (!This->pITextStoreACP) 282 { 283 FIXME("Context does not have a ITextStoreACP\n"); 284 return E_NOTIMPL; 285 } 286 287 cookie = get_Cookie_data(ec); 288 289 if (ulIndex == TF_DEFAULT_SELECTION) 290 count = 1; 291 else 292 count = ulCount; 293 294 for (i = 0; i < count; i++) 295 { 296 DWORD fetched; 297 TS_SELECTION_ACP acps; 298 299 hr = ITextStoreACP_GetSelection(This->pITextStoreACP, ulIndex + i, 300 1, &acps, &fetched); 301 302 if (hr == TS_E_NOLOCK) 303 return TF_E_NOLOCK; 304 else if (SUCCEEDED(hr)) 305 { 306 pSelection[totalFetched].style.ase = acps.style.ase; 307 pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar; 308 Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range); 309 totalFetched ++; 310 } 311 else 312 break; 313 } 314 315 *pcFetched = totalFetched; 316 317 return hr; 318 } 319 320 static HRESULT WINAPI Context_SetSelection (ITfContext *iface, 321 TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection) 322 { 323 Context *This = impl_from_ITfContext(iface); 324 TS_SELECTION_ACP *acp; 325 ULONG i; 326 HRESULT hr; 327 328 TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection); 329 330 if (!This->pITextStoreACP) 331 { 332 FIXME("Context does not have a ITextStoreACP\n"); 333 return E_NOTIMPL; 334 } 335 336 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) 337 return TF_E_NOLOCK; 338 339 acp = HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount); 340 if (!acp) 341 return E_OUTOFMEMORY; 342 343 for (i = 0; i < ulCount; i++) 344 if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i]))) 345 { 346 TRACE("Selection Conversion Failed\n"); 347 HeapFree(GetProcessHeap(), 0 , acp); 348 return E_FAIL; 349 } 350 351 hr = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp); 352 353 HeapFree(GetProcessHeap(), 0, acp); 354 355 return hr; 356 } 357 358 static HRESULT WINAPI Context_GetStart (ITfContext *iface, 359 TfEditCookie ec, ITfRange **ppStart) 360 { 361 Context *This = impl_from_ITfContext(iface); 362 EditCookie *cookie; 363 TRACE("(%p) %i %p\n",This,ec,ppStart); 364 365 if (!ppStart) 366 return E_INVALIDARG; 367 368 *ppStart = NULL; 369 370 if (!This->connected) 371 return TF_E_DISCONNECTED; 372 373 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) 374 return TF_E_NOLOCK; 375 376 cookie = get_Cookie_data(ec); 377 return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, 0, 0, ppStart); 378 } 379 380 static HRESULT WINAPI Context_GetEnd (ITfContext *iface, 381 TfEditCookie ec, ITfRange **ppEnd) 382 { 383 Context *This = impl_from_ITfContext(iface); 384 EditCookie *cookie; 385 LONG end; 386 TRACE("(%p) %i %p\n",This,ec,ppEnd); 387 388 if (!ppEnd) 389 return E_INVALIDARG; 390 391 *ppEnd = NULL; 392 393 if (!This->connected) 394 return TF_E_DISCONNECTED; 395 396 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) 397 return TF_E_NOLOCK; 398 399 if (!This->pITextStoreACP) 400 { 401 FIXME("Context does not have a ITextStoreACP\n"); 402 return E_NOTIMPL; 403 } 404 405 cookie = get_Cookie_data(ec); 406 ITextStoreACP_GetEndACP(This->pITextStoreACP,&end); 407 408 return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, end, end, ppEnd); 409 } 410 411 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface, 412 ITfContextView **ppView) 413 { 414 Context *This = impl_from_ITfContext(iface); 415 FIXME("STUB:(%p)\n",This); 416 return E_NOTIMPL; 417 } 418 419 static HRESULT WINAPI Context_EnumViews (ITfContext *iface, 420 IEnumTfContextViews **ppEnum) 421 { 422 Context *This = impl_from_ITfContext(iface); 423 FIXME("STUB:(%p)\n",This); 424 return E_NOTIMPL; 425 } 426 427 static HRESULT WINAPI Context_GetStatus (ITfContext *iface, 428 TF_STATUS *pdcs) 429 { 430 Context *This = impl_from_ITfContext(iface); 431 TRACE("(%p) %p\n",This,pdcs); 432 433 if (!This->connected) 434 return TF_E_DISCONNECTED; 435 436 if (!pdcs) 437 return E_INVALIDARG; 438 439 if (!This->pITextStoreACP) 440 { 441 FIXME("Context does not have a ITextStoreACP\n"); 442 return E_NOTIMPL; 443 } 444 445 ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus); 446 447 *pdcs = This->documentStatus; 448 449 return S_OK; 450 } 451 452 static HRESULT WINAPI Context_GetProperty (ITfContext *iface, 453 REFGUID guidProp, ITfProperty **ppProp) 454 { 455 Context *This = impl_from_ITfContext(iface); 456 FIXME("STUB:(%p)\n",This); 457 return E_NOTIMPL; 458 } 459 460 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface, 461 REFGUID guidProp, ITfReadOnlyProperty **ppProp) 462 { 463 Context *This = impl_from_ITfContext(iface); 464 FIXME("STUB:(%p)\n",This); 465 return E_NOTIMPL; 466 } 467 468 static HRESULT WINAPI Context_TrackProperties (ITfContext *iface, 469 const GUID **prgProp, ULONG cProp, const GUID **prgAppProp, 470 ULONG cAppProp, ITfReadOnlyProperty **ppProperty) 471 { 472 Context *This = impl_from_ITfContext(iface); 473 FIXME("STUB:(%p)\n",This); 474 return E_NOTIMPL; 475 } 476 477 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface, 478 IEnumTfProperties **ppEnum) 479 { 480 Context *This = impl_from_ITfContext(iface); 481 FIXME("STUB:(%p)\n",This); 482 return E_NOTIMPL; 483 } 484 485 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface, 486 ITfDocumentMgr **ppDm) 487 { 488 Context *This = impl_from_ITfContext(iface); 489 TRACE("(%p) %p\n",This,ppDm); 490 491 if (!ppDm) 492 return E_INVALIDARG; 493 494 *ppDm = This->manager; 495 if (!This->manager) 496 return S_FALSE; 497 498 ITfDocumentMgr_AddRef(This->manager); 499 500 return S_OK; 501 } 502 503 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface, 504 TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup) 505 { 506 Context *This = impl_from_ITfContext(iface); 507 FIXME("STUB:(%p)\n",This); 508 return E_NOTIMPL; 509 } 510 511 static const ITfContextVtbl ContextVtbl = 512 { 513 Context_QueryInterface, 514 Context_AddRef, 515 Context_Release, 516 Context_RequestEditSession, 517 Context_InWriteSession, 518 Context_GetSelection, 519 Context_SetSelection, 520 Context_GetStart, 521 Context_GetEnd, 522 Context_GetActiveView, 523 Context_EnumViews, 524 Context_GetStatus, 525 Context_GetProperty, 526 Context_GetAppProperty, 527 Context_TrackProperties, 528 Context_EnumProperties, 529 Context_GetDocumentMgr, 530 Context_CreateRangeBackup 531 }; 532 533 static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) 534 { 535 Context *This = impl_from_ITfSource(iface); 536 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); 537 } 538 539 static ULONG WINAPI ContextSource_AddRef(ITfSource *iface) 540 { 541 Context *This = impl_from_ITfSource(iface); 542 return ITfContext_AddRef(&This->ITfContext_iface); 543 } 544 545 static ULONG WINAPI ContextSource_Release(ITfSource *iface) 546 { 547 Context *This = impl_from_ITfSource(iface); 548 return ITfContext_Release(&This->ITfContext_iface); 549 } 550 551 /***************************************************** 552 * ITfSource functions 553 *****************************************************/ 554 static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface, 555 REFIID riid, IUnknown *punk, DWORD *pdwCookie) 556 { 557 Context *This = impl_from_ITfSource(iface); 558 559 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie); 560 561 if (!riid || !punk || !pdwCookie) 562 return E_INVALIDARG; 563 564 if (IsEqualIID(riid, &IID_ITfTextEditSink)) 565 return advise_sink(&This->pTextEditSink, &IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie); 566 567 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); 568 return E_NOTIMPL; 569 } 570 571 static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) 572 { 573 Context *This = impl_from_ITfSource(iface); 574 575 TRACE("(%p) %x\n",This,pdwCookie); 576 577 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK) 578 return E_INVALIDARG; 579 580 return unadvise_sink(pdwCookie); 581 } 582 583 static const ITfSourceVtbl ContextSourceVtbl = 584 { 585 ContextSource_QueryInterface, 586 ContextSource_AddRef, 587 ContextSource_Release, 588 ContextSource_AdviseSink, 589 ContextSource_UnadviseSink 590 }; 591 592 /***************************************************** 593 * ITfInsertAtSelection functions 594 *****************************************************/ 595 static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut) 596 { 597 Context *This = impl_from_ITfInsertAtSelection(iface); 598 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); 599 } 600 601 static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface) 602 { 603 Context *This = impl_from_ITfInsertAtSelection(iface); 604 return ITfContext_AddRef(&This->ITfContext_iface); 605 } 606 607 static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface) 608 { 609 Context *This = impl_from_ITfInsertAtSelection(iface); 610 return ITfContext_Release(&This->ITfContext_iface); 611 } 612 613 static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection( 614 ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags, 615 const WCHAR *pchText, LONG cch, ITfRange **ppRange) 616 { 617 Context *This = impl_from_ITfInsertAtSelection(iface); 618 EditCookie *cookie; 619 LONG acpStart, acpEnd; 620 TS_TEXTCHANGE change; 621 HRESULT hr; 622 623 TRACE("(%p) %i %x %s %p\n",This, ec, dwFlags, debugstr_wn(pchText,cch), ppRange); 624 625 if (!This->connected) 626 return TF_E_DISCONNECTED; 627 628 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) 629 return TF_E_NOLOCK; 630 631 cookie = get_Cookie_data(ec); 632 633 if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE ) 634 return TS_E_READONLY; 635 636 if (!This->pITextStoreACP) 637 { 638 FIXME("Context does not have a ITextStoreACP\n"); 639 return E_NOTIMPL; 640 } 641 642 hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change); 643 if (SUCCEEDED(hr)) 644 Range_Constructor(&This->ITfContext_iface, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange); 645 646 return hr; 647 } 648 649 static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection( 650 ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags, 651 IDataObject *pDataObject, ITfRange **ppRange) 652 { 653 Context *This = impl_from_ITfInsertAtSelection(iface); 654 FIXME("STUB:(%p)\n",This); 655 return E_NOTIMPL; 656 } 657 658 static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl = 659 { 660 InsertAtSelection_QueryInterface, 661 InsertAtSelection_AddRef, 662 InsertAtSelection_Release, 663 InsertAtSelection_InsertTextAtSelection, 664 InsertAtSelection_InsertEmbeddedAtSelection, 665 }; 666 667 /***************************************************** 668 * ITfSourceSingle functions 669 *****************************************************/ 670 static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut) 671 { 672 Context *This = impl_from_ITfSourceSingle(iface); 673 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); 674 } 675 676 static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface) 677 { 678 Context *This = impl_from_ITfSourceSingle(iface); 679 return ITfContext_AddRef(&This->ITfContext_iface); 680 } 681 682 static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface) 683 { 684 Context *This = impl_from_ITfSourceSingle(iface); 685 return ITfContext_Release(&This->ITfContext_iface); 686 } 687 688 static HRESULT WINAPI SourceSingle_AdviseSingleSink( ITfSourceSingle *iface, 689 TfClientId tid, REFIID riid, IUnknown *punk) 690 { 691 Context *This = impl_from_ITfSourceSingle(iface); 692 FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk); 693 return E_NOTIMPL; 694 } 695 696 static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface, 697 TfClientId tid, REFIID riid) 698 { 699 Context *This = impl_from_ITfSourceSingle(iface); 700 FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid)); 701 return E_NOTIMPL; 702 } 703 704 static const ITfSourceSingleVtbl ContextSourceSingleVtbl = 705 { 706 SourceSingle_QueryInterface, 707 SourceSingle_AddRef, 708 SourceSingle_Release, 709 SourceSingle_AdviseSingleSink, 710 SourceSingle_UnadviseSingleSink, 711 }; 712 713 /************************************************************************** 714 * ITextStoreACPSink 715 **************************************************************************/ 716 717 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut) 718 { 719 Context *This = impl_from_ITextStoreACPSink(iface); 720 721 *ppvOut = NULL; 722 723 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink)) 724 { 725 *ppvOut = &This->ITextStoreACPSink_iface; 726 } 727 else if (IsEqualIID(iid, &IID_ITextStoreACPServices)) 728 *ppvOut = &This->ITextStoreACPServices_iface; 729 730 if (*ppvOut) 731 { 732 ITextStoreACPSink_AddRef(iface); 733 return S_OK; 734 } 735 736 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 737 return E_NOINTERFACE; 738 } 739 740 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface) 741 { 742 Context *This = impl_from_ITextStoreACPSink(iface); 743 return ITfContext_AddRef(&This->ITfContext_iface); 744 } 745 746 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface) 747 { 748 Context *This = impl_from_ITextStoreACPSink(iface); 749 return ITfContext_Release(&This->ITfContext_iface); 750 } 751 752 /***************************************************** 753 * ITextStoreACPSink functions 754 *****************************************************/ 755 756 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface, 757 DWORD dwFlags, const TS_TEXTCHANGE *pChange) 758 { 759 Context *This = impl_from_ITextStoreACPSink(iface); 760 FIXME("STUB:(%p)\n",This); 761 return S_OK; 762 } 763 764 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface) 765 { 766 Context *This = impl_from_ITextStoreACPSink(iface); 767 FIXME("STUB:(%p)\n",This); 768 return S_OK; 769 } 770 771 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface, 772 TsLayoutCode lcode, TsViewCookie vcView) 773 { 774 Context *This = impl_from_ITextStoreACPSink(iface); 775 FIXME("STUB:(%p)\n",This); 776 return S_OK; 777 } 778 779 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface, 780 DWORD dwFlags) 781 { 782 Context *This = impl_from_ITextStoreACPSink(iface); 783 HRESULT hr, hrSession; 784 785 TRACE("(%p) %x\n",This, dwFlags); 786 787 if (!This->pITextStoreACP) 788 { 789 FIXME("Context does not have a ITextStoreACP\n"); 790 return E_NOTIMPL; 791 } 792 793 hr = ITextStoreACP_RequestLock(This->pITextStoreACP, TS_LF_READ, &hrSession); 794 795 if(SUCCEEDED(hr) && SUCCEEDED(hrSession)) 796 This->documentStatus.dwDynamicFlags = dwFlags; 797 798 return S_OK; 799 } 800 801 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface, 802 LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs) 803 { 804 Context *This = impl_from_ITextStoreACPSink(iface); 805 FIXME("STUB:(%p)\n",This); 806 return E_NOTIMPL; 807 } 808 809 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface, 810 DWORD dwLockFlags) 811 { 812 Context *This = impl_from_ITextStoreACPSink(iface); 813 HRESULT hr; 814 EditCookie *cookie,*sinkcookie; 815 TfEditCookie ec; 816 struct list *cursor; 817 818 TRACE("(%p) %x\n",This, dwLockFlags); 819 820 if (!This->currentEditSession) 821 { 822 FIXME("OnLockGranted called for something other than an EditSession\n"); 823 return S_OK; 824 } 825 826 cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie)); 827 if (!cookie) 828 return E_OUTOFMEMORY; 829 830 sinkcookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie)); 831 if (!sinkcookie) 832 { 833 HeapFree(GetProcessHeap(), 0, cookie); 834 return E_OUTOFMEMORY; 835 } 836 837 cookie->lockType = dwLockFlags; 838 cookie->pOwningContext = This; 839 ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie); 840 841 hr = ITfEditSession_DoEditSession(This->currentEditSession, ec); 842 843 if ((dwLockFlags&TS_LF_READWRITE) == TS_LF_READWRITE) 844 { 845 ITfTextEditSink *sink; 846 TfEditCookie sc; 847 848 sinkcookie->lockType = TS_LF_READ; 849 sinkcookie->pOwningContext = This; 850 sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie); 851 852 /*TODO: implement ITfEditRecord */ 853 SINK_FOR_EACH(cursor, &This->pTextEditSink, ITfTextEditSink, sink) 854 { 855 ITfTextEditSink_OnEndEdit(sink, (ITfContext*) &This->ITfContext_iface, sc, NULL); 856 } 857 sinkcookie = remove_Cookie(sc); 858 } 859 HeapFree(GetProcessHeap(),0,sinkcookie); 860 861 ITfEditSession_Release(This->currentEditSession); 862 This->currentEditSession = NULL; 863 864 /* Edit Cookie is only valid during the edit session */ 865 cookie = remove_Cookie(ec); 866 HeapFree(GetProcessHeap(),0,cookie); 867 868 return hr; 869 } 870 871 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface) 872 { 873 Context *This = impl_from_ITextStoreACPSink(iface); 874 FIXME("STUB:(%p)\n",This); 875 return E_NOTIMPL; 876 } 877 878 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface) 879 { 880 Context *This = impl_from_ITextStoreACPSink(iface); 881 FIXME("STUB:(%p)\n",This); 882 return E_NOTIMPL; 883 } 884 885 static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl = 886 { 887 TextStoreACPSink_QueryInterface, 888 TextStoreACPSink_AddRef, 889 TextStoreACPSink_Release, 890 TextStoreACPSink_OnTextChange, 891 TextStoreACPSink_OnSelectionChange, 892 TextStoreACPSink_OnLayoutChange, 893 TextStoreACPSink_OnStatusChange, 894 TextStoreACPSink_OnAttrsChange, 895 TextStoreACPSink_OnLockGranted, 896 TextStoreACPSink_OnStartEditTransaction, 897 TextStoreACPSink_OnEndEditTransaction 898 }; 899 900 static HRESULT WINAPI TextStoreACPServices_QueryInterface(ITextStoreACPServices *iface, REFIID riid, void **obj) 901 { 902 Context *This = impl_from_ITextStoreACPServices(iface); 903 return ITextStoreACPSink_QueryInterface(&This->ITextStoreACPSink_iface, riid, obj); 904 } 905 906 static ULONG WINAPI TextStoreACPServices_AddRef(ITextStoreACPServices *iface) 907 { 908 Context *This = impl_from_ITextStoreACPServices(iface); 909 return ITextStoreACPSink_AddRef(&This->ITextStoreACPSink_iface); 910 } 911 912 static ULONG WINAPI TextStoreACPServices_Release(ITextStoreACPServices *iface) 913 { 914 Context *This = impl_from_ITextStoreACPServices(iface); 915 return ITextStoreACPSink_Release(&This->ITextStoreACPSink_iface); 916 } 917 918 static HRESULT WINAPI TextStoreACPServices_Serialize(ITextStoreACPServices *iface, ITfProperty *prop, ITfRange *range, 919 TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream) 920 { 921 Context *This = impl_from_ITextStoreACPServices(iface); 922 923 FIXME("stub: %p %p %p %p %p\n", This, prop, range, header, stream); 924 925 return E_NOTIMPL; 926 } 927 928 static HRESULT WINAPI TextStoreACPServices_Unserialize(ITextStoreACPServices *iface, ITfProperty *prop, 929 const TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream, ITfPersistentPropertyLoaderACP *loader) 930 { 931 Context *This = impl_from_ITextStoreACPServices(iface); 932 933 FIXME("stub: %p %p %p %p %p\n", This, prop, header, stream, loader); 934 935 return E_NOTIMPL; 936 } 937 938 static HRESULT WINAPI TextStoreACPServices_ForceLoadProperty(ITextStoreACPServices *iface, ITfProperty *prop) 939 { 940 Context *This = impl_from_ITextStoreACPServices(iface); 941 942 FIXME("stub: %p %p\n", This, prop); 943 944 return E_NOTIMPL; 945 } 946 947 static HRESULT WINAPI TextStoreACPServices_CreateRange(ITextStoreACPServices *iface, 948 LONG start, LONG end, ITfRangeACP **range) 949 { 950 Context *This = impl_from_ITextStoreACPServices(iface); 951 952 FIXME("stub: %p %d %d %p\n", This, start, end, range); 953 954 return S_OK; 955 } 956 957 static const ITextStoreACPServicesVtbl TextStoreACPServicesVtbl = 958 { 959 TextStoreACPServices_QueryInterface, 960 TextStoreACPServices_AddRef, 961 TextStoreACPServices_Release, 962 TextStoreACPServices_Serialize, 963 TextStoreACPServices_Unserialize, 964 TextStoreACPServices_ForceLoadProperty, 965 TextStoreACPServices_CreateRange 966 }; 967 968 HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore) 969 { 970 Context *This; 971 EditCookie *cookie; 972 973 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context)); 974 if (This == NULL) 975 return E_OUTOFMEMORY; 976 977 cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie)); 978 if (cookie == NULL) 979 { 980 HeapFree(GetProcessHeap(),0,This); 981 return E_OUTOFMEMORY; 982 } 983 984 TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore); 985 986 This->ITfContext_iface.lpVtbl= &ContextVtbl; 987 This->ITfSource_iface.lpVtbl = &ContextSourceVtbl; 988 This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl; 989 This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl; 990 This->ITextStoreACPSink_iface.lpVtbl = &TextStoreACPSinkVtbl; 991 This->ITextStoreACPServices_iface.lpVtbl = &TextStoreACPServicesVtbl; 992 This->refCount = 1; 993 This->tidOwner = tidOwner; 994 This->connected = FALSE; 995 This->manager = mgr; 996 997 CompartmentMgr_Constructor((IUnknown*)&This->ITfContext_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); 998 999 cookie->lockType = TF_ES_READ; 1000 cookie->pOwningContext = This; 1001 1002 if (punk) 1003 { 1004 IUnknown_QueryInterface(punk, &IID_ITextStoreACP, 1005 (LPVOID*)&This->pITextStoreACP); 1006 1007 IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink, 1008 (LPVOID*)&This->pITfContextOwnerCompositionSink); 1009 1010 if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink) 1011 FIXME("Unhandled pUnk\n"); 1012 } 1013 1014 This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie); 1015 *pecTextStore = This->defaultCookie; 1016 1017 list_init(&This->pContextKeyEventSink); 1018 list_init(&This->pEditTransactionSink); 1019 list_init(&This->pStatusSink); 1020 list_init(&This->pTextEditSink); 1021 list_init(&This->pTextLayoutSink); 1022 1023 *ppOut = &This->ITfContext_iface; 1024 TRACE("returning %p\n", *ppOut); 1025 1026 return S_OK; 1027 } 1028 1029 HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager) 1030 { 1031 Context *This = impl_from_ITfContext(iface); 1032 1033 if (This->pITextStoreACP) 1034 ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink, 1035 (IUnknown*)&This->ITextStoreACPSink_iface, TS_AS_ALL_SINKS); 1036 This->connected = TRUE; 1037 This->manager = manager; 1038 return S_OK; 1039 } 1040 1041 HRESULT Context_Uninitialize(ITfContext *iface) 1042 { 1043 Context *This = impl_from_ITfContext(iface); 1044 1045 if (This->pITextStoreACP) 1046 ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)&This->ITextStoreACPSink_iface); 1047 This->connected = FALSE; 1048 This->manager = NULL; 1049 return S_OK; 1050 } 1051