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