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