2 * ITfContext implementation
4 * Copyright 2009 Aric Stewart, CodeWeavers
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.
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.
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
27 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "wine/list.h"
41 #include "msctf_internal.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf
);
45 typedef struct tagContextSink
{
50 /* ITfContextKeyEventSink *pITfContextKeyEventSink; */
51 /* ITfEditTransactionSink *pITfEditTransactionSink; */
52 /* ITfStatusSink *pITfStatusSink; */
53 ITfTextEditSink
*pITfTextEditSink
;
54 /* ITfTextLayoutSink *pITfTextLayoutSink; */
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; */
73 ITextStoreACP
*pITextStoreACP
;
74 ITfContextOwnerCompositionSink
*pITfContextOwnerCompositionSink
;
76 ITextStoreACPSink
*pITextStoreACPSink
;
77 ITfEditSession
* currentEditSession
;
79 /* kept as separate lists to reduce unnecessary iterations */
80 struct list pContextKeyEventSink
;
81 struct list pEditTransactionSink
;
82 struct list pStatusSink
;
83 struct list pTextEditSink
;
84 struct list pTextLayoutSink
;
89 typedef struct tagTextStoreACPSink
{
90 const ITextStoreACPSinkVtbl
*TextStoreACPSinkVtbl
;
91 /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
98 static HRESULT
TextStoreACPSink_Constructor(ITextStoreACPSink
**ppOut
, Context
*pContext
);
100 static inline Context
*impl_from_ITfSourceVtbl(ITfSource
*iface
)
102 return (Context
*)((char *)iface
- FIELD_OFFSET(Context
,SourceVtbl
));
105 static void free_sink(ContextSink
*sink
)
107 IUnknown_Release(sink
->interfaces
.pIUnknown
);
108 HeapFree(GetProcessHeap(),0,sink
);
111 static void Context_Destructor(Context
*This
)
113 struct list
*cursor
, *cursor2
;
114 TRACE("destroying %p\n", This
);
116 if (This
->pITextStoreACPSink
)
118 ITextStoreACP_UnadviseSink(This
->pITextStoreACP
, (IUnknown
*)This
->pITextStoreACPSink
);
119 ITextStoreACPSink_Release(This
->pITextStoreACPSink
);
122 if (This
->pITextStoreACP
)
123 ITextStoreACPSink_Release(This
->pITextStoreACP
);
125 if (This
->pITfContextOwnerCompositionSink
)
126 ITextStoreACPSink_Release(This
->pITfContextOwnerCompositionSink
);
128 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pContextKeyEventSink
)
130 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
134 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pEditTransactionSink
)
136 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
140 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pStatusSink
)
142 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
146 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pTextEditSink
)
148 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
152 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pTextLayoutSink
)
154 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
159 HeapFree(GetProcessHeap(),0,This
);
162 static HRESULT WINAPI
Context_QueryInterface(ITfContext
*iface
, REFIID iid
, LPVOID
*ppvOut
)
164 Context
*This
= (Context
*)iface
;
167 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfContext
))
171 else if (IsEqualIID(iid
, &IID_ITfSource
))
173 *ppvOut
= &This
->SourceVtbl
;
178 IUnknown_AddRef(iface
);
182 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
183 return E_NOINTERFACE
;
186 static ULONG WINAPI
Context_AddRef(ITfContext
*iface
)
188 Context
*This
= (Context
*)iface
;
189 return InterlockedIncrement(&This
->refCount
);
192 static ULONG WINAPI
Context_Release(ITfContext
*iface
)
194 Context
*This
= (Context
*)iface
;
197 ret
= InterlockedDecrement(&This
->refCount
);
199 Context_Destructor(This
);
203 /*****************************************************
204 * ITfContext functions
205 *****************************************************/
206 static HRESULT WINAPI
Context_RequestEditSession (ITfContext
*iface
,
207 TfClientId tid
, ITfEditSession
*pes
, DWORD dwFlags
,
211 Context
*This
= (Context
*)iface
;
212 DWORD dwLockFlags
= 0x0;
215 TRACE("(%p) %i %p %x %p\n",This
, tid
, pes
, dwFlags
, phrSession
);
217 if (!(dwFlags
& TF_ES_READ
) && !(dwFlags
& TF_ES_READWRITE
))
219 *phrSession
= E_FAIL
;
223 if (!This
->pITextStoreACP
)
225 FIXME("No ITextStoreACP avaliable\n");
226 *phrSession
= E_FAIL
;
230 if (!(dwFlags
& TF_ES_ASYNC
))
231 dwLockFlags
&= TS_LF_SYNC
;
233 if (dwFlags
& TF_ES_READ
)
234 dwLockFlags
&= TS_LF_READ
;
235 else if ((dwFlags
& TF_ES_READWRITE
) == TF_ES_READWRITE
)
236 dwLockFlags
&= TS_LF_READWRITE
;
238 /* TODO: cache this */
239 ITextStoreACP_GetStatus(This
->pITextStoreACP
, &status
);
241 if (((dwFlags
& TF_ES_READWRITE
) == TF_ES_READWRITE
) && (status
.dwDynamicFlags
& TS_SD_READONLY
))
243 *phrSession
= TS_E_READONLY
;
247 if (FAILED (ITfEditSession_QueryInterface(pes
, &IID_ITfEditSession
, (LPVOID
*)&This
->currentEditSession
)))
249 *phrSession
= E_FAIL
;
254 hr
= ITextStoreACP_RequestLock(This
->pITextStoreACP
, dwLockFlags
, phrSession
);
259 static HRESULT WINAPI
Context_InWriteSession (ITfContext
*iface
,
261 BOOL
*pfWriteSession
)
263 Context
*This
= (Context
*)iface
;
264 FIXME("STUB:(%p)\n",This
);
268 static HRESULT WINAPI
Context_GetSelection (ITfContext
*iface
,
269 TfEditCookie ec
, ULONG ulIndex
, ULONG ulCount
,
270 TF_SELECTION
*pSelection
, ULONG
*pcFetched
)
272 Context
*This
= (Context
*)iface
;
273 FIXME("STUB:(%p)\n",This
);
277 static HRESULT WINAPI
Context_SetSelection (ITfContext
*iface
,
278 TfEditCookie ec
, ULONG ulCount
, const TF_SELECTION
*pSelection
)
280 Context
*This
= (Context
*)iface
;
281 FIXME("STUB:(%p)\n",This
);
285 static HRESULT WINAPI
Context_GetStart (ITfContext
*iface
,
286 TfEditCookie ec
, ITfRange
**ppStart
)
288 Context
*This
= (Context
*)iface
;
289 FIXME("STUB:(%p)\n",This
);
293 static HRESULT WINAPI
Context_GetEnd (ITfContext
*iface
,
294 TfEditCookie ec
, ITfRange
**ppEnd
)
296 Context
*This
= (Context
*)iface
;
297 FIXME("STUB:(%p)\n",This
);
301 static HRESULT WINAPI
Context_GetActiveView (ITfContext
*iface
,
302 ITfContextView
**ppView
)
304 Context
*This
= (Context
*)iface
;
305 FIXME("STUB:(%p)\n",This
);
309 static HRESULT WINAPI
Context_EnumViews (ITfContext
*iface
,
310 IEnumTfContextViews
**ppEnum
)
312 Context
*This
= (Context
*)iface
;
313 FIXME("STUB:(%p)\n",This
);
317 static HRESULT WINAPI
Context_GetStatus (ITfContext
*iface
,
320 Context
*This
= (Context
*)iface
;
321 FIXME("STUB:(%p)\n",This
);
325 static HRESULT WINAPI
Context_GetProperty (ITfContext
*iface
,
326 REFGUID guidProp
, ITfProperty
**ppProp
)
328 Context
*This
= (Context
*)iface
;
329 FIXME("STUB:(%p)\n",This
);
333 static HRESULT WINAPI
Context_GetAppProperty (ITfContext
*iface
,
334 REFGUID guidProp
, ITfReadOnlyProperty
**ppProp
)
336 Context
*This
= (Context
*)iface
;
337 FIXME("STUB:(%p)\n",This
);
341 static HRESULT WINAPI
Context_TrackProperties (ITfContext
*iface
,
342 const GUID
**prgProp
, ULONG cProp
, const GUID
**prgAppProp
,
343 ULONG cAppProp
, ITfReadOnlyProperty
**ppProperty
)
345 Context
*This
= (Context
*)iface
;
346 FIXME("STUB:(%p)\n",This
);
350 static HRESULT WINAPI
Context_EnumProperties (ITfContext
*iface
,
351 IEnumTfProperties
**ppEnum
)
353 Context
*This
= (Context
*)iface
;
354 FIXME("STUB:(%p)\n",This
);
358 static HRESULT WINAPI
Context_GetDocumentMgr (ITfContext
*iface
,
359 ITfDocumentMgr
**ppDm
)
361 Context
*This
= (Context
*)iface
;
362 FIXME("STUB:(%p)\n",This
);
366 static HRESULT WINAPI
Context_CreateRangeBackup (ITfContext
*iface
,
367 TfEditCookie ec
, ITfRange
*pRange
, ITfRangeBackup
**ppBackup
)
369 Context
*This
= (Context
*)iface
;
370 FIXME("STUB:(%p)\n",This
);
374 static const ITfContextVtbl Context_ContextVtbl
=
376 Context_QueryInterface
,
380 Context_RequestEditSession
,
381 Context_InWriteSession
,
382 Context_GetSelection
,
383 Context_SetSelection
,
386 Context_GetActiveView
,
390 Context_GetAppProperty
,
391 Context_TrackProperties
,
392 Context_EnumProperties
,
393 Context_GetDocumentMgr
,
394 Context_CreateRangeBackup
397 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
399 Context
*This
= impl_from_ITfSourceVtbl(iface
);
400 return Context_QueryInterface((ITfContext
*)This
, iid
, *ppvOut
);
403 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
405 Context
*This
= impl_from_ITfSourceVtbl(iface
);
406 return Context_AddRef((ITfContext
*)This
);
409 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
411 Context
*This
= impl_from_ITfSourceVtbl(iface
);
412 return Context_Release((ITfContext
*)This
);
415 /*****************************************************
416 * ITfSource functions
417 *****************************************************/
418 static WINAPI HRESULT
ContextSource_AdviseSink(ITfSource
*iface
,
419 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
422 Context
*This
= impl_from_ITfSourceVtbl(iface
);
423 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
425 if (!riid
|| !punk
|| !pdwCookie
)
428 if (IsEqualIID(riid
, &IID_ITfTextEditSink
))
430 es
= HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink
));
432 return E_OUTOFMEMORY
;
433 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&es
->interfaces
.pITfTextEditSink
)))
435 HeapFree(GetProcessHeap(),0,es
);
436 return CONNECT_E_CANNOTCONNECT
;
438 list_add_head(&This
->pTextEditSink
,&es
->entry
);
439 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_CONTEXTSINK
, es
);
443 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
447 TRACE("cookie %x\n",*pdwCookie
);
451 static WINAPI HRESULT
ContextSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
454 Context
*This
= impl_from_ITfSourceVtbl(iface
);
456 TRACE("(%p) %x\n",This
,pdwCookie
);
458 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_CONTEXTSINK
)
461 sink
= (ContextSink
*)remove_Cookie(pdwCookie
);
463 return CONNECT_E_NOCONNECTION
;
465 list_remove(&sink
->entry
);
471 static const ITfSourceVtbl Context_SourceVtbl
=
473 Source_QueryInterface
,
477 ContextSource_AdviseSink
,
478 ContextSource_UnadviseSink
,
481 HRESULT
Context_Constructor(TfClientId tidOwner
, IUnknown
*punk
, ITfContext
**ppOut
, TfEditCookie
*pecTextStore
)
485 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Context
));
487 return E_OUTOFMEMORY
;
489 TRACE("(%p) %x %p %p %p\n",This
, tidOwner
, punk
, ppOut
, pecTextStore
);
491 This
->ContextVtbl
= &Context_ContextVtbl
;
492 This
->SourceVtbl
= &Context_SourceVtbl
;
494 This
->tidOwner
= tidOwner
;
495 This
->connected
= FALSE
;
499 IUnknown_QueryInterface(punk
, &IID_ITextStoreACP
,
500 (LPVOID
*)&This
->pITextStoreACP
);
502 IUnknown_QueryInterface(punk
, &IID_ITfContextOwnerCompositionSink
,
503 (LPVOID
*)&This
->pITfContextOwnerCompositionSink
);
505 if (!This
->pITextStoreACP
&& !This
->pITfContextOwnerCompositionSink
)
506 FIXME("Unhandled pUnk\n");
509 TRACE("returning %p\n", This
);
510 *ppOut
= (ITfContext
*)This
;
512 *pecTextStore
= 0xdeaddead;
514 list_init(&This
->pContextKeyEventSink
);
515 list_init(&This
->pEditTransactionSink
);
516 list_init(&This
->pStatusSink
);
517 list_init(&This
->pTextEditSink
);
518 list_init(&This
->pTextLayoutSink
);
523 HRESULT
Context_Initialize(ITfContext
*iface
)
525 Context
*This
= (Context
*)iface
;
527 if (This
->pITextStoreACP
)
529 if (SUCCEEDED(TextStoreACPSink_Constructor(&This
->pITextStoreACPSink
, This
)))
530 ITextStoreACP_AdviseSink(This
->pITextStoreACP
, &IID_ITextStoreACPSink
,
531 (IUnknown
*)This
->pITextStoreACPSink
, TS_AS_ALL_SINKS
);
533 This
->connected
= TRUE
;
537 HRESULT
Context_Uninitialize(ITfContext
*iface
)
539 Context
*This
= (Context
*)iface
;
541 if (This
->pITextStoreACPSink
)
543 ITextStoreACP_UnadviseSink(This
->pITextStoreACP
, (IUnknown
*)This
->pITextStoreACPSink
);
544 if (ITextStoreACPSink_Release(This
->pITextStoreACPSink
) == 0)
545 This
->pITextStoreACPSink
= NULL
;
547 This
->connected
= FALSE
;
551 /**************************************************************************
553 **************************************************************************/
555 static void TextStoreACPSink_Destructor(TextStoreACPSink
*This
)
557 TRACE("destroying %p\n", This
);
558 HeapFree(GetProcessHeap(),0,This
);
561 static HRESULT WINAPI
TextStoreACPSink_QueryInterface(ITextStoreACPSink
*iface
, REFIID iid
, LPVOID
*ppvOut
)
563 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
566 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITextStoreACPSink
))
573 IUnknown_AddRef(iface
);
577 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
578 return E_NOINTERFACE
;
581 static ULONG WINAPI
TextStoreACPSink_AddRef(ITextStoreACPSink
*iface
)
583 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
584 return InterlockedIncrement(&This
->refCount
);
587 static ULONG WINAPI
TextStoreACPSink_Release(ITextStoreACPSink
*iface
)
589 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
592 ret
= InterlockedDecrement(&This
->refCount
);
594 TextStoreACPSink_Destructor(This
);
598 /*****************************************************
599 * ITextStoreACPSink functions
600 *****************************************************/
602 static HRESULT WINAPI
TextStoreACPSink_OnTextChange(ITextStoreACPSink
*iface
,
603 DWORD dwFlags
, const TS_TEXTCHANGE
*pChange
)
605 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
606 FIXME("STUB:(%p)\n",This
);
610 static HRESULT WINAPI
TextStoreACPSink_OnSelectionChange(ITextStoreACPSink
*iface
)
612 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
613 FIXME("STUB:(%p)\n",This
);
617 static HRESULT WINAPI
TextStoreACPSink_OnLayoutChange(ITextStoreACPSink
*iface
,
618 TsLayoutCode lcode
, TsViewCookie vcView
)
620 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
621 FIXME("STUB:(%p)\n",This
);
625 static HRESULT WINAPI
TextStoreACPSink_OnStatusChange(ITextStoreACPSink
*iface
,
628 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
629 FIXME("STUB:(%p)\n",This
);
633 static HRESULT WINAPI
TextStoreACPSink_OnAttrsChange(ITextStoreACPSink
*iface
,
634 LONG acpStart
, LONG acpEnd
, ULONG cAttrs
, const TS_ATTRID
*paAttrs
)
636 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
637 FIXME("STUB:(%p)\n",This
);
641 static HRESULT WINAPI
TextStoreACPSink_OnLockGranted(ITextStoreACPSink
*iface
,
644 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
647 TRACE("(%p) %x\n",This
, dwLockFlags
);
649 if (!This
->pContext
|| !This
->pContext
->currentEditSession
)
651 ERR("OnLockGranted called on a context without a current edit session\nZ");
655 /* TODO: generate and use an edit cookie */
656 hr
= ITfEditSession_DoEditSession(This
->pContext
->currentEditSession
, 0xdeadcafe);
658 ITfEditSession_Release(This
->pContext
->currentEditSession
);
659 This
->pContext
->currentEditSession
= NULL
;
664 static HRESULT WINAPI
TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink
*iface
)
666 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
667 FIXME("STUB:(%p)\n",This
);
671 static HRESULT WINAPI
TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink
*iface
)
673 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
674 FIXME("STUB:(%p)\n",This
);
678 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl
=
680 TextStoreACPSink_QueryInterface
,
681 TextStoreACPSink_AddRef
,
682 TextStoreACPSink_Release
,
684 TextStoreACPSink_OnTextChange
,
685 TextStoreACPSink_OnSelectionChange
,
686 TextStoreACPSink_OnLayoutChange
,
687 TextStoreACPSink_OnStatusChange
,
688 TextStoreACPSink_OnAttrsChange
,
689 TextStoreACPSink_OnLockGranted
,
690 TextStoreACPSink_OnStartEditTransaction
,
691 TextStoreACPSink_OnEndEditTransaction
694 static HRESULT
TextStoreACPSink_Constructor(ITextStoreACPSink
**ppOut
, Context
*pContext
)
696 TextStoreACPSink
*This
;
698 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(TextStoreACPSink
));
700 return E_OUTOFMEMORY
;
702 This
->TextStoreACPSinkVtbl
= &TextStoreACPSink_TextStoreACPSinkVtbl
;
705 This
->pContext
= pContext
;
707 TRACE("returning %p\n", This
);
708 *ppOut
= (ITextStoreACPSink
*)This
;