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