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