TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / msctf / context.c
blob941245c10dbec4ea896db49124b717bcc07bff9b
1 /*
2 * ITfContext implementation
4 * Copyright 2009 Aric Stewart, CodeWeavers
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #define COBJMACROS
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"
37 #include "wine/unicode.h"
38 #include "wine/list.h"
40 #include "msctf.h"
41 #include "msctf_internal.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
45 typedef struct tagContextSink {
46 struct list entry;
47 union {
48 /* Context Sinks */
49 IUnknown *pIUnknown;
50 /* ITfContextKeyEventSink *pITfContextKeyEventSink; */
51 /* ITfEditTransactionSink *pITfEditTransactionSink; */
52 /* ITfStatusSink *pITfStatusSink; */
53 ITfTextEditSink *pITfTextEditSink;
54 /* ITfTextLayoutSink *pITfTextLayoutSink; */
55 } interfaces;
56 } ContextSink;
58 typedef struct tagContext {
59 ITfContext ITfContext_iface;
60 ITfSource ITfSource_iface;
61 /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
62 /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */
63 /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
64 ITfInsertAtSelection ITfInsertAtSelection_iface;
65 /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
66 /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
67 ITfSourceSingle ITfSourceSingle_iface;
68 LONG refCount;
69 BOOL connected;
71 /* Aggregation */
72 ITfCompartmentMgr *CompartmentMgr;
74 TfClientId tidOwner;
75 TfEditCookie defaultCookie;
76 TS_STATUS documentStatus;
77 ITfDocumentMgr *manager;
79 ITextStoreACP *pITextStoreACP;
80 ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
82 ITextStoreACPSink *pITextStoreACPSink;
83 ITfEditSession* currentEditSession;
85 /* kept as separate lists to reduce unnecessary iterations */
86 struct list pContextKeyEventSink;
87 struct list pEditTransactionSink;
88 struct list pStatusSink;
89 struct list pTextEditSink;
90 struct list pTextLayoutSink;
92 } Context;
94 typedef struct tagEditCookie {
95 DWORD lockType;
96 Context *pOwningContext;
97 } EditCookie;
99 typedef struct tagTextStoreACPSink {
100 ITextStoreACPSink ITextStoreACPSink_iface;
101 /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
102 LONG refCount;
104 Context *pContext;
105 } TextStoreACPSink;
108 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
110 static inline Context *impl_from_ITfContext(ITfContext *iface)
112 return CONTAINING_RECORD(iface, Context, ITfContext_iface);
115 static inline Context *impl_from_ITfSource(ITfSource *iface)
117 return CONTAINING_RECORD(iface, Context, ITfSource_iface);
120 static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface)
122 return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface);
125 static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface)
127 return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface);
130 static inline TextStoreACPSink *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
132 return CONTAINING_RECORD(iface, TextStoreACPSink, ITextStoreACPSink_iface);
135 static void free_sink(ContextSink *sink)
137 IUnknown_Release(sink->interfaces.pIUnknown);
138 HeapFree(GetProcessHeap(),0,sink);
141 static void Context_Destructor(Context *This)
143 struct list *cursor, *cursor2;
144 EditCookie *cookie;
145 TRACE("destroying %p\n", This);
147 if (This->pITextStoreACPSink)
149 ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
150 ITextStoreACPSink_Release(This->pITextStoreACPSink);
153 if (This->pITextStoreACP)
154 ITextStoreACP_Release(This->pITextStoreACP);
156 if (This->pITfContextOwnerCompositionSink)
157 ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink);
159 if (This->defaultCookie)
161 cookie = remove_Cookie(This->defaultCookie);
162 HeapFree(GetProcessHeap(),0,cookie);
163 This->defaultCookie = 0;
166 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
168 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
169 list_remove(cursor);
170 free_sink(sink);
172 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
174 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
175 list_remove(cursor);
176 free_sink(sink);
178 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
180 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
181 list_remove(cursor);
182 free_sink(sink);
184 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
186 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
187 list_remove(cursor);
188 free_sink(sink);
190 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
192 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
193 list_remove(cursor);
194 free_sink(sink);
197 CompartmentMgr_Destructor(This->CompartmentMgr);
198 HeapFree(GetProcessHeap(),0,This);
201 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
203 Context *This = impl_from_ITfContext(iface);
204 *ppvOut = NULL;
206 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
208 *ppvOut = &This->ITfContext_iface;
210 else if (IsEqualIID(iid, &IID_ITfSource))
212 *ppvOut = &This->ITfSource_iface;
214 else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
216 *ppvOut = &This->ITfInsertAtSelection_iface;
218 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
220 *ppvOut = This->CompartmentMgr;
222 else if (IsEqualIID(iid, &IID_ITfSourceSingle))
224 *ppvOut = &This->ITfSourceSingle_iface;
227 if (*ppvOut)
229 ITfContext_AddRef(iface);
230 return S_OK;
233 WARN("unsupported interface: %s\n", debugstr_guid(iid));
234 return E_NOINTERFACE;
237 static ULONG WINAPI Context_AddRef(ITfContext *iface)
239 Context *This = impl_from_ITfContext(iface);
240 return InterlockedIncrement(&This->refCount);
243 static ULONG WINAPI Context_Release(ITfContext *iface)
245 Context *This = impl_from_ITfContext(iface);
246 ULONG ret;
248 ret = InterlockedDecrement(&This->refCount);
249 if (ret == 0)
250 Context_Destructor(This);
251 return ret;
254 /*****************************************************
255 * ITfContext functions
256 *****************************************************/
257 static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
258 TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
259 HRESULT *phrSession)
261 Context *This = impl_from_ITfContext(iface);
262 HRESULT hr;
263 DWORD dwLockFlags = 0x0;
265 TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);
267 if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE))
269 *phrSession = E_FAIL;
270 return E_INVALIDARG;
273 if (!This->pITextStoreACP)
275 FIXME("No ITextStoreACP available\n");
276 *phrSession = E_FAIL;
277 return E_FAIL;
280 if (!(dwFlags & TF_ES_ASYNC))
281 dwLockFlags |= TS_LF_SYNC;
283 if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
284 dwLockFlags |= TS_LF_READWRITE;
285 else if (dwFlags & TF_ES_READ)
286 dwLockFlags |= TS_LF_READ;
288 if (!This->documentStatus.dwDynamicFlags)
289 ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
291 if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY))
293 *phrSession = TS_E_READONLY;
294 return S_OK;
297 if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession)))
299 *phrSession = E_FAIL;
300 return E_INVALIDARG;
303 hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession);
305 return hr;
308 static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
309 TfClientId tid,
310 BOOL *pfWriteSession)
312 Context *This = impl_from_ITfContext(iface);
313 FIXME("STUB:(%p)\n",This);
314 return E_NOTIMPL;
317 static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
318 TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
319 TF_SELECTION *pSelection, ULONG *pcFetched)
321 Context *This = impl_from_ITfContext(iface);
322 EditCookie *cookie;
323 ULONG count, i;
324 ULONG totalFetched = 0;
325 HRESULT hr = S_OK;
327 if (!pSelection || !pcFetched)
328 return E_INVALIDARG;
330 *pcFetched = 0;
332 if (!This->connected)
333 return TF_E_DISCONNECTED;
335 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
336 return TF_E_NOLOCK;
338 if (!This->pITextStoreACP)
340 FIXME("Context does not have a ITextStoreACP\n");
341 return E_NOTIMPL;
344 cookie = get_Cookie_data(ec);
346 if (ulIndex == TF_DEFAULT_SELECTION)
347 count = 1;
348 else
349 count = ulCount;
351 for (i = 0; i < count; i++)
353 DWORD fetched;
354 TS_SELECTION_ACP acps;
356 hr = ITextStoreACP_GetSelection(This->pITextStoreACP, ulIndex + i,
357 1, &acps, &fetched);
359 if (hr == TS_E_NOLOCK)
360 return TF_E_NOLOCK;
361 else if (SUCCEEDED(hr))
363 pSelection[totalFetched].style.ase = acps.style.ase;
364 pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar;
365 Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range);
366 totalFetched ++;
368 else
369 break;
372 *pcFetched = totalFetched;
374 return hr;
377 static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
378 TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
380 Context *This = impl_from_ITfContext(iface);
381 TS_SELECTION_ACP *acp;
382 ULONG i;
383 HRESULT hr;
385 TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection);
387 if (!This->pITextStoreACP)
389 FIXME("Context does not have a ITextStoreACP\n");
390 return E_NOTIMPL;
393 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
394 return TF_E_NOLOCK;
396 acp = HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount);
397 if (!acp)
398 return E_OUTOFMEMORY;
400 for (i = 0; i < ulCount; i++)
401 if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i])))
403 TRACE("Selection Conversion Failed\n");
404 HeapFree(GetProcessHeap(), 0 , acp);
405 return E_FAIL;
408 hr = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp);
410 HeapFree(GetProcessHeap(), 0, acp);
412 return hr;
415 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
416 TfEditCookie ec, ITfRange **ppStart)
418 Context *This = impl_from_ITfContext(iface);
419 EditCookie *cookie;
420 TRACE("(%p) %i %p\n",This,ec,ppStart);
422 if (!ppStart)
423 return E_INVALIDARG;
425 *ppStart = NULL;
427 if (!This->connected)
428 return TF_E_DISCONNECTED;
430 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
431 return TF_E_NOLOCK;
433 cookie = get_Cookie_data(ec);
434 return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, 0, 0, ppStart);
437 static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
438 TfEditCookie ec, ITfRange **ppEnd)
440 Context *This = impl_from_ITfContext(iface);
441 EditCookie *cookie;
442 LONG end;
443 TRACE("(%p) %i %p\n",This,ec,ppEnd);
445 if (!ppEnd)
446 return E_INVALIDARG;
448 *ppEnd = NULL;
450 if (!This->connected)
451 return TF_E_DISCONNECTED;
453 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
454 return TF_E_NOLOCK;
456 if (!This->pITextStoreACP)
458 FIXME("Context does not have a ITextStoreACP\n");
459 return E_NOTIMPL;
462 cookie = get_Cookie_data(ec);
463 ITextStoreACP_GetEndACP(This->pITextStoreACP,&end);
465 return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, end, end, ppEnd);
468 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
469 ITfContextView **ppView)
471 Context *This = impl_from_ITfContext(iface);
472 FIXME("STUB:(%p)\n",This);
473 return E_NOTIMPL;
476 static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
477 IEnumTfContextViews **ppEnum)
479 Context *This = impl_from_ITfContext(iface);
480 FIXME("STUB:(%p)\n",This);
481 return E_NOTIMPL;
484 static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
485 TF_STATUS *pdcs)
487 Context *This = impl_from_ITfContext(iface);
488 TRACE("(%p) %p\n",This,pdcs);
490 if (!This->connected)
491 return TF_E_DISCONNECTED;
493 if (!pdcs)
494 return E_INVALIDARG;
496 if (!This->pITextStoreACP)
498 FIXME("Context does not have a ITextStoreACP\n");
499 return E_NOTIMPL;
502 ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
504 *pdcs = This->documentStatus;
506 return S_OK;
509 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
510 REFGUID guidProp, ITfProperty **ppProp)
512 Context *This = impl_from_ITfContext(iface);
513 FIXME("STUB:(%p)\n",This);
514 return E_NOTIMPL;
517 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
518 REFGUID guidProp, ITfReadOnlyProperty **ppProp)
520 Context *This = impl_from_ITfContext(iface);
521 FIXME("STUB:(%p)\n",This);
522 return E_NOTIMPL;
525 static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
526 const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
527 ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
529 Context *This = impl_from_ITfContext(iface);
530 FIXME("STUB:(%p)\n",This);
531 return E_NOTIMPL;
534 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
535 IEnumTfProperties **ppEnum)
537 Context *This = impl_from_ITfContext(iface);
538 FIXME("STUB:(%p)\n",This);
539 return E_NOTIMPL;
542 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
543 ITfDocumentMgr **ppDm)
545 Context *This = impl_from_ITfContext(iface);
546 TRACE("(%p) %p\n",This,ppDm);
548 if (!ppDm)
549 return E_INVALIDARG;
551 *ppDm = This->manager;
552 if (!This->manager)
553 return S_FALSE;
555 ITfDocumentMgr_AddRef(This->manager);
557 return S_OK;
560 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
561 TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
563 Context *This = impl_from_ITfContext(iface);
564 FIXME("STUB:(%p)\n",This);
565 return E_NOTIMPL;
568 static const ITfContextVtbl ContextVtbl =
570 Context_QueryInterface,
571 Context_AddRef,
572 Context_Release,
573 Context_RequestEditSession,
574 Context_InWriteSession,
575 Context_GetSelection,
576 Context_SetSelection,
577 Context_GetStart,
578 Context_GetEnd,
579 Context_GetActiveView,
580 Context_EnumViews,
581 Context_GetStatus,
582 Context_GetProperty,
583 Context_GetAppProperty,
584 Context_TrackProperties,
585 Context_EnumProperties,
586 Context_GetDocumentMgr,
587 Context_CreateRangeBackup
590 static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
592 Context *This = impl_from_ITfSource(iface);
593 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
596 static ULONG WINAPI ContextSource_AddRef(ITfSource *iface)
598 Context *This = impl_from_ITfSource(iface);
599 return ITfContext_AddRef(&This->ITfContext_iface);
602 static ULONG WINAPI ContextSource_Release(ITfSource *iface)
604 Context *This = impl_from_ITfSource(iface);
605 return ITfContext_Release(&This->ITfContext_iface);
608 /*****************************************************
609 * ITfSource functions
610 *****************************************************/
611 static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface,
612 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
614 Context *This = impl_from_ITfSource(iface);
615 ContextSink *es;
616 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
618 if (!riid || !punk || !pdwCookie)
619 return E_INVALIDARG;
621 if (IsEqualIID(riid, &IID_ITfTextEditSink))
623 es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
624 if (!es)
625 return E_OUTOFMEMORY;
626 if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&es->interfaces.pITfTextEditSink)))
628 HeapFree(GetProcessHeap(),0,es);
629 return CONNECT_E_CANNOTCONNECT;
631 list_add_head(&This->pTextEditSink ,&es->entry);
632 *pdwCookie = generate_Cookie(COOKIE_MAGIC_CONTEXTSINK, es);
634 else
636 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
637 return E_NOTIMPL;
640 TRACE("cookie %x\n",*pdwCookie);
641 return S_OK;
644 static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
646 Context *This = impl_from_ITfSource(iface);
647 ContextSink *sink;
649 TRACE("(%p) %x\n",This,pdwCookie);
651 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
652 return E_INVALIDARG;
654 sink = remove_Cookie(pdwCookie);
655 if (!sink)
656 return CONNECT_E_NOCONNECTION;
658 list_remove(&sink->entry);
659 free_sink(sink);
661 return S_OK;
664 static const ITfSourceVtbl ContextSourceVtbl =
666 ContextSource_QueryInterface,
667 ContextSource_AddRef,
668 ContextSource_Release,
669 ContextSource_AdviseSink,
670 ContextSource_UnadviseSink
673 /*****************************************************
674 * ITfInsertAtSelection functions
675 *****************************************************/
676 static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
678 Context *This = impl_from_ITfInsertAtSelection(iface);
679 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
682 static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface)
684 Context *This = impl_from_ITfInsertAtSelection(iface);
685 return ITfContext_AddRef(&This->ITfContext_iface);
688 static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
690 Context *This = impl_from_ITfInsertAtSelection(iface);
691 return ITfContext_Release(&This->ITfContext_iface);
694 static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection(
695 ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
696 const WCHAR *pchText, LONG cch, ITfRange **ppRange)
698 Context *This = impl_from_ITfInsertAtSelection(iface);
699 EditCookie *cookie;
700 LONG acpStart, acpEnd;
701 TS_TEXTCHANGE change;
702 HRESULT hr;
704 TRACE("(%p) %i %x %s %p\n",This, ec, dwFlags, debugstr_wn(pchText,cch), ppRange);
706 if (!This->connected)
707 return TF_E_DISCONNECTED;
709 if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
710 return TF_E_NOLOCK;
712 cookie = get_Cookie_data(ec);
714 if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE )
715 return TS_E_READONLY;
717 if (!This->pITextStoreACP)
719 FIXME("Context does not have a ITextStoreACP\n");
720 return E_NOTIMPL;
723 hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
724 if (SUCCEEDED(hr))
725 Range_Constructor(&This->ITfContext_iface, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
727 return hr;
730 static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection(
731 ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
732 IDataObject *pDataObject, ITfRange **ppRange)
734 Context *This = impl_from_ITfInsertAtSelection(iface);
735 FIXME("STUB:(%p)\n",This);
736 return E_NOTIMPL;
739 static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl =
741 InsertAtSelection_QueryInterface,
742 InsertAtSelection_AddRef,
743 InsertAtSelection_Release,
744 InsertAtSelection_InsertTextAtSelection,
745 InsertAtSelection_InsertEmbeddedAtSelection,
748 /*****************************************************
749 * ITfSourceSingle functions
750 *****************************************************/
751 static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
753 Context *This = impl_from_ITfSourceSingle(iface);
754 return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
757 static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface)
759 Context *This = impl_from_ITfSourceSingle(iface);
760 return ITfContext_AddRef(&This->ITfContext_iface);
763 static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface)
765 Context *This = impl_from_ITfSourceSingle(iface);
766 return ITfContext_Release(&This->ITfContext_iface);
769 static HRESULT WINAPI SourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
770 TfClientId tid, REFIID riid, IUnknown *punk)
772 Context *This = impl_from_ITfSourceSingle(iface);
773 FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
774 return E_NOTIMPL;
777 static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
778 TfClientId tid, REFIID riid)
780 Context *This = impl_from_ITfSourceSingle(iface);
781 FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
782 return E_NOTIMPL;
785 static const ITfSourceSingleVtbl ContextSourceSingleVtbl =
787 SourceSingle_QueryInterface,
788 SourceSingle_AddRef,
789 SourceSingle_Release,
790 SourceSingle_AdviseSingleSink,
791 SourceSingle_UnadviseSingleSink,
794 HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore)
796 Context *This;
797 EditCookie *cookie;
799 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
800 if (This == NULL)
801 return E_OUTOFMEMORY;
803 cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
804 if (cookie == NULL)
806 HeapFree(GetProcessHeap(),0,This);
807 return E_OUTOFMEMORY;
810 TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore);
812 This->ITfContext_iface.lpVtbl= &ContextVtbl;
813 This->ITfSource_iface.lpVtbl = &ContextSourceVtbl;
814 This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl;
815 This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl;
816 This->refCount = 1;
817 This->tidOwner = tidOwner;
818 This->connected = FALSE;
819 This->manager = mgr;
821 CompartmentMgr_Constructor((IUnknown*)&This->ITfContext_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
823 cookie->lockType = TF_ES_READ;
824 cookie->pOwningContext = This;
826 if (punk)
828 IUnknown_QueryInterface(punk, &IID_ITextStoreACP,
829 (LPVOID*)&This->pITextStoreACP);
831 IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink,
832 (LPVOID*)&This->pITfContextOwnerCompositionSink);
834 if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink)
835 FIXME("Unhandled pUnk\n");
838 This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie);
839 *pecTextStore = This->defaultCookie;
841 list_init(&This->pContextKeyEventSink);
842 list_init(&This->pEditTransactionSink);
843 list_init(&This->pStatusSink);
844 list_init(&This->pTextEditSink);
845 list_init(&This->pTextLayoutSink);
847 *ppOut = &This->ITfContext_iface;
848 TRACE("returning %p\n", *ppOut);
850 return S_OK;
853 HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
855 Context *This = impl_from_ITfContext(iface);
857 if (This->pITextStoreACP)
859 if (SUCCEEDED(TextStoreACPSink_Constructor(&This->pITextStoreACPSink, This)))
860 ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
861 (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
863 This->connected = TRUE;
864 This->manager = manager;
865 return S_OK;
868 HRESULT Context_Uninitialize(ITfContext *iface)
870 Context *This = impl_from_ITfContext(iface);
872 if (This->pITextStoreACPSink)
874 ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
875 if (ITextStoreACPSink_Release(This->pITextStoreACPSink) == 0)
876 This->pITextStoreACPSink = NULL;
878 This->connected = FALSE;
879 This->manager = NULL;
880 return S_OK;
883 /**************************************************************************
884 * ITextStoreACPSink
885 **************************************************************************/
887 static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
889 TRACE("destroying %p\n", This);
890 HeapFree(GetProcessHeap(),0,This);
893 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
895 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
896 *ppvOut = NULL;
898 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
900 *ppvOut = &This->ITextStoreACPSink_iface;
903 if (*ppvOut)
905 ITextStoreACPSink_AddRef(iface);
906 return S_OK;
909 WARN("unsupported interface: %s\n", debugstr_guid(iid));
910 return E_NOINTERFACE;
913 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
915 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
916 return InterlockedIncrement(&This->refCount);
919 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
921 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
922 ULONG ret;
924 ret = InterlockedDecrement(&This->refCount);
925 if (ret == 0)
926 TextStoreACPSink_Destructor(This);
927 return ret;
930 /*****************************************************
931 * ITextStoreACPSink functions
932 *****************************************************/
934 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
935 DWORD dwFlags, const TS_TEXTCHANGE *pChange)
937 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
938 FIXME("STUB:(%p)\n",This);
939 return E_NOTIMPL;
942 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
944 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
945 FIXME("STUB:(%p)\n",This);
946 return E_NOTIMPL;
949 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
950 TsLayoutCode lcode, TsViewCookie vcView)
952 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
953 FIXME("STUB:(%p)\n",This);
954 return E_NOTIMPL;
957 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
958 DWORD dwFlags)
960 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
961 HRESULT hr, hrSession;
963 TRACE("(%p) %x\n",This, dwFlags);
965 if (!This->pContext)
967 ERR("No context?\n");
968 return E_FAIL;
971 if (!This->pContext->pITextStoreACP)
973 FIXME("Context does not have a ITextStoreACP\n");
974 return E_NOTIMPL;
977 hr = ITextStoreACP_RequestLock(This->pContext->pITextStoreACP, TS_LF_READ, &hrSession);
979 if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
980 This->pContext->documentStatus.dwDynamicFlags = dwFlags;
982 return S_OK;
985 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
986 LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
988 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
989 FIXME("STUB:(%p)\n",This);
990 return E_NOTIMPL;
993 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
994 DWORD dwLockFlags)
996 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
997 HRESULT hr;
998 EditCookie *cookie,*sinkcookie;
999 TfEditCookie ec;
1000 struct list *cursor;
1002 TRACE("(%p) %x\n",This, dwLockFlags);
1004 if (!This->pContext)
1006 ERR("OnLockGranted called without a context\n");
1007 return E_FAIL;
1010 if (!This->pContext->currentEditSession)
1012 FIXME("OnLockGranted called for something other than an EditSession\n");
1013 return S_OK;
1016 cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
1017 if (!cookie)
1018 return E_OUTOFMEMORY;
1020 sinkcookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
1021 if (!sinkcookie)
1023 HeapFree(GetProcessHeap(), 0, cookie);
1024 return E_OUTOFMEMORY;
1027 cookie->lockType = dwLockFlags;
1028 cookie->pOwningContext = This->pContext;
1029 ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
1031 hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, ec);
1033 if ((dwLockFlags&TS_LF_READWRITE) == TS_LF_READWRITE)
1035 TfEditCookie sc;
1037 sinkcookie->lockType = TS_LF_READ;
1038 sinkcookie->pOwningContext = This->pContext;
1039 sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);
1041 /*TODO: implement ITfEditRecord */
1042 LIST_FOR_EACH(cursor, &This->pContext->pTextEditSink)
1044 ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
1045 ITfTextEditSink_OnEndEdit(sink->interfaces.pITfTextEditSink,
1046 (ITfContext*) &This->pContext, sc, NULL);
1048 sinkcookie = remove_Cookie(sc);
1050 HeapFree(GetProcessHeap(),0,sinkcookie);
1052 ITfEditSession_Release(This->pContext->currentEditSession);
1053 This->pContext->currentEditSession = NULL;
1055 /* Edit Cookie is only valid during the edit session */
1056 cookie = remove_Cookie(ec);
1057 HeapFree(GetProcessHeap(),0,cookie);
1059 return hr;
1062 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
1064 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
1065 FIXME("STUB:(%p)\n",This);
1066 return E_NOTIMPL;
1069 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
1071 TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
1072 FIXME("STUB:(%p)\n",This);
1073 return E_NOTIMPL;
1076 static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl =
1078 TextStoreACPSink_QueryInterface,
1079 TextStoreACPSink_AddRef,
1080 TextStoreACPSink_Release,
1081 TextStoreACPSink_OnTextChange,
1082 TextStoreACPSink_OnSelectionChange,
1083 TextStoreACPSink_OnLayoutChange,
1084 TextStoreACPSink_OnStatusChange,
1085 TextStoreACPSink_OnAttrsChange,
1086 TextStoreACPSink_OnLockGranted,
1087 TextStoreACPSink_OnStartEditTransaction,
1088 TextStoreACPSink_OnEndEditTransaction
1091 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
1093 TextStoreACPSink *This;
1095 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
1096 if (This == NULL)
1097 return E_OUTOFMEMORY;
1099 This->ITextStoreACPSink_iface.lpVtbl= &TextStoreACPSinkVtbl;
1100 This->refCount = 1;
1102 This->pContext = pContext;
1104 *ppOut = &This->ITextStoreACPSink_iface;
1105 TRACE("returning %p\n", *ppOut);
1106 return S_OK;