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