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; */
72 TfEditCookie defaultCookie
;
74 ITextStoreACP
*pITextStoreACP
;
75 ITfContextOwnerCompositionSink
*pITfContextOwnerCompositionSink
;
77 ITextStoreACPSink
*pITextStoreACPSink
;
78 ITfEditSession
* currentEditSession
;
80 /* kept as separate lists to reduce unnecessary iterations */
81 struct list pContextKeyEventSink
;
82 struct list pEditTransactionSink
;
83 struct list pStatusSink
;
84 struct list pTextEditSink
;
85 struct list pTextLayoutSink
;
89 typedef struct tagEditCookie
{
91 Context
*pOwningContext
;
94 typedef struct tagTextStoreACPSink
{
95 const ITextStoreACPSinkVtbl
*TextStoreACPSinkVtbl
;
96 /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
103 static HRESULT
TextStoreACPSink_Constructor(ITextStoreACPSink
**ppOut
, Context
*pContext
);
105 static inline Context
*impl_from_ITfSourceVtbl(ITfSource
*iface
)
107 return (Context
*)((char *)iface
- FIELD_OFFSET(Context
,SourceVtbl
));
110 static void free_sink(ContextSink
*sink
)
112 IUnknown_Release(sink
->interfaces
.pIUnknown
);
113 HeapFree(GetProcessHeap(),0,sink
);
116 static void Context_Destructor(Context
*This
)
118 struct list
*cursor
, *cursor2
;
120 TRACE("destroying %p\n", This
);
122 if (This
->pITextStoreACPSink
)
124 ITextStoreACP_UnadviseSink(This
->pITextStoreACP
, (IUnknown
*)This
->pITextStoreACPSink
);
125 ITextStoreACPSink_Release(This
->pITextStoreACPSink
);
128 if (This
->pITextStoreACP
)
129 ITextStoreACPSink_Release(This
->pITextStoreACP
);
131 if (This
->pITfContextOwnerCompositionSink
)
132 ITextStoreACPSink_Release(This
->pITfContextOwnerCompositionSink
);
134 if (This
->defaultCookie
)
136 cookie
= remove_Cookie(This
->defaultCookie
);
137 HeapFree(GetProcessHeap(),0,cookie
);
138 This
->defaultCookie
= 0;
141 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pContextKeyEventSink
)
143 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
147 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pEditTransactionSink
)
149 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
153 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pStatusSink
)
155 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
159 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pTextEditSink
)
161 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
165 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->pTextLayoutSink
)
167 ContextSink
* sink
= LIST_ENTRY(cursor
,ContextSink
,entry
);
172 HeapFree(GetProcessHeap(),0,This
);
175 static HRESULT WINAPI
Context_QueryInterface(ITfContext
*iface
, REFIID iid
, LPVOID
*ppvOut
)
177 Context
*This
= (Context
*)iface
;
180 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfContext
))
184 else if (IsEqualIID(iid
, &IID_ITfSource
))
186 *ppvOut
= &This
->SourceVtbl
;
191 IUnknown_AddRef(iface
);
195 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
196 return E_NOINTERFACE
;
199 static ULONG WINAPI
Context_AddRef(ITfContext
*iface
)
201 Context
*This
= (Context
*)iface
;
202 return InterlockedIncrement(&This
->refCount
);
205 static ULONG WINAPI
Context_Release(ITfContext
*iface
)
207 Context
*This
= (Context
*)iface
;
210 ret
= InterlockedDecrement(&This
->refCount
);
212 Context_Destructor(This
);
216 /*****************************************************
217 * ITfContext functions
218 *****************************************************/
219 static HRESULT WINAPI
Context_RequestEditSession (ITfContext
*iface
,
220 TfClientId tid
, ITfEditSession
*pes
, DWORD dwFlags
,
224 Context
*This
= (Context
*)iface
;
225 DWORD dwLockFlags
= 0x0;
228 TRACE("(%p) %i %p %x %p\n",This
, tid
, pes
, dwFlags
, phrSession
);
230 if (!(dwFlags
& TF_ES_READ
) && !(dwFlags
& TF_ES_READWRITE
))
232 *phrSession
= E_FAIL
;
236 if (!This
->pITextStoreACP
)
238 FIXME("No ITextStoreACP avaliable\n");
239 *phrSession
= E_FAIL
;
243 if (!(dwFlags
& TF_ES_ASYNC
))
244 dwLockFlags
|= TS_LF_SYNC
;
246 if ((dwFlags
& TF_ES_READWRITE
) == TF_ES_READWRITE
)
247 dwLockFlags
|= TS_LF_READWRITE
;
248 else if (dwFlags
& TF_ES_READ
)
249 dwLockFlags
|= TS_LF_READ
;
251 /* TODO: cache this */
252 ITextStoreACP_GetStatus(This
->pITextStoreACP
, &status
);
254 if (((dwFlags
& TF_ES_READWRITE
) == TF_ES_READWRITE
) && (status
.dwDynamicFlags
& TS_SD_READONLY
))
256 *phrSession
= TS_E_READONLY
;
260 if (FAILED (ITfEditSession_QueryInterface(pes
, &IID_ITfEditSession
, (LPVOID
*)&This
->currentEditSession
)))
262 *phrSession
= E_FAIL
;
267 hr
= ITextStoreACP_RequestLock(This
->pITextStoreACP
, dwLockFlags
, phrSession
);
272 static HRESULT WINAPI
Context_InWriteSession (ITfContext
*iface
,
274 BOOL
*pfWriteSession
)
276 Context
*This
= (Context
*)iface
;
277 FIXME("STUB:(%p)\n",This
);
281 static HRESULT WINAPI
Context_GetSelection (ITfContext
*iface
,
282 TfEditCookie ec
, ULONG ulIndex
, ULONG ulCount
,
283 TF_SELECTION
*pSelection
, ULONG
*pcFetched
)
285 Context
*This
= (Context
*)iface
;
286 FIXME("STUB:(%p)\n",This
);
290 static HRESULT WINAPI
Context_SetSelection (ITfContext
*iface
,
291 TfEditCookie ec
, ULONG ulCount
, const TF_SELECTION
*pSelection
)
293 Context
*This
= (Context
*)iface
;
294 FIXME("STUB:(%p)\n",This
);
298 static HRESULT WINAPI
Context_GetStart (ITfContext
*iface
,
299 TfEditCookie ec
, ITfRange
**ppStart
)
301 Context
*This
= (Context
*)iface
;
303 TRACE("(%p) %i %p\n",This
,ec
,ppStart
);
310 if (!This
->connected
)
311 return TF_E_DISCONNECTED
;
313 if (get_Cookie_magic(ec
)!=COOKIE_MAGIC_EDITCOOKIE
)
316 cookie
= get_Cookie_data(ec
);
317 return Range_Constructor(iface
, This
->pITextStoreACP
, cookie
->lockType
, 0, 0, ppStart
);
320 static HRESULT WINAPI
Context_GetEnd (ITfContext
*iface
,
321 TfEditCookie ec
, ITfRange
**ppEnd
)
323 Context
*This
= (Context
*)iface
;
324 FIXME("STUB:(%p)\n",This
);
328 static HRESULT WINAPI
Context_GetActiveView (ITfContext
*iface
,
329 ITfContextView
**ppView
)
331 Context
*This
= (Context
*)iface
;
332 FIXME("STUB:(%p)\n",This
);
336 static HRESULT WINAPI
Context_EnumViews (ITfContext
*iface
,
337 IEnumTfContextViews
**ppEnum
)
339 Context
*This
= (Context
*)iface
;
340 FIXME("STUB:(%p)\n",This
);
344 static HRESULT WINAPI
Context_GetStatus (ITfContext
*iface
,
347 Context
*This
= (Context
*)iface
;
348 FIXME("STUB:(%p)\n",This
);
352 static HRESULT WINAPI
Context_GetProperty (ITfContext
*iface
,
353 REFGUID guidProp
, ITfProperty
**ppProp
)
355 Context
*This
= (Context
*)iface
;
356 FIXME("STUB:(%p)\n",This
);
360 static HRESULT WINAPI
Context_GetAppProperty (ITfContext
*iface
,
361 REFGUID guidProp
, ITfReadOnlyProperty
**ppProp
)
363 Context
*This
= (Context
*)iface
;
364 FIXME("STUB:(%p)\n",This
);
368 static HRESULT WINAPI
Context_TrackProperties (ITfContext
*iface
,
369 const GUID
**prgProp
, ULONG cProp
, const GUID
**prgAppProp
,
370 ULONG cAppProp
, ITfReadOnlyProperty
**ppProperty
)
372 Context
*This
= (Context
*)iface
;
373 FIXME("STUB:(%p)\n",This
);
377 static HRESULT WINAPI
Context_EnumProperties (ITfContext
*iface
,
378 IEnumTfProperties
**ppEnum
)
380 Context
*This
= (Context
*)iface
;
381 FIXME("STUB:(%p)\n",This
);
385 static HRESULT WINAPI
Context_GetDocumentMgr (ITfContext
*iface
,
386 ITfDocumentMgr
**ppDm
)
388 Context
*This
= (Context
*)iface
;
389 FIXME("STUB:(%p)\n",This
);
393 static HRESULT WINAPI
Context_CreateRangeBackup (ITfContext
*iface
,
394 TfEditCookie ec
, ITfRange
*pRange
, ITfRangeBackup
**ppBackup
)
396 Context
*This
= (Context
*)iface
;
397 FIXME("STUB:(%p)\n",This
);
401 static const ITfContextVtbl Context_ContextVtbl
=
403 Context_QueryInterface
,
407 Context_RequestEditSession
,
408 Context_InWriteSession
,
409 Context_GetSelection
,
410 Context_SetSelection
,
413 Context_GetActiveView
,
417 Context_GetAppProperty
,
418 Context_TrackProperties
,
419 Context_EnumProperties
,
420 Context_GetDocumentMgr
,
421 Context_CreateRangeBackup
424 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
426 Context
*This
= impl_from_ITfSourceVtbl(iface
);
427 return Context_QueryInterface((ITfContext
*)This
, iid
, *ppvOut
);
430 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
432 Context
*This
= impl_from_ITfSourceVtbl(iface
);
433 return Context_AddRef((ITfContext
*)This
);
436 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
438 Context
*This
= impl_from_ITfSourceVtbl(iface
);
439 return Context_Release((ITfContext
*)This
);
442 /*****************************************************
443 * ITfSource functions
444 *****************************************************/
445 static WINAPI HRESULT
ContextSource_AdviseSink(ITfSource
*iface
,
446 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
449 Context
*This
= impl_from_ITfSourceVtbl(iface
);
450 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
452 if (!riid
|| !punk
|| !pdwCookie
)
455 if (IsEqualIID(riid
, &IID_ITfTextEditSink
))
457 es
= HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink
));
459 return E_OUTOFMEMORY
;
460 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&es
->interfaces
.pITfTextEditSink
)))
462 HeapFree(GetProcessHeap(),0,es
);
463 return CONNECT_E_CANNOTCONNECT
;
465 list_add_head(&This
->pTextEditSink
,&es
->entry
);
466 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_CONTEXTSINK
, es
);
470 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
474 TRACE("cookie %x\n",*pdwCookie
);
478 static WINAPI HRESULT
ContextSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
481 Context
*This
= impl_from_ITfSourceVtbl(iface
);
483 TRACE("(%p) %x\n",This
,pdwCookie
);
485 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_CONTEXTSINK
)
488 sink
= (ContextSink
*)remove_Cookie(pdwCookie
);
490 return CONNECT_E_NOCONNECTION
;
492 list_remove(&sink
->entry
);
498 static const ITfSourceVtbl Context_SourceVtbl
=
500 Source_QueryInterface
,
504 ContextSource_AdviseSink
,
505 ContextSource_UnadviseSink
,
508 HRESULT
Context_Constructor(TfClientId tidOwner
, IUnknown
*punk
, ITfContext
**ppOut
, TfEditCookie
*pecTextStore
)
513 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Context
));
515 return E_OUTOFMEMORY
;
517 cookie
= HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie
));
520 HeapFree(GetProcessHeap(),0,This
);
521 return E_OUTOFMEMORY
;
524 TRACE("(%p) %x %p %p %p\n",This
, tidOwner
, punk
, ppOut
, pecTextStore
);
526 This
->ContextVtbl
= &Context_ContextVtbl
;
527 This
->SourceVtbl
= &Context_SourceVtbl
;
529 This
->tidOwner
= tidOwner
;
530 This
->connected
= FALSE
;
532 cookie
->lockType
= TF_ES_READ
;
533 cookie
->pOwningContext
= This
;
537 IUnknown_QueryInterface(punk
, &IID_ITextStoreACP
,
538 (LPVOID
*)&This
->pITextStoreACP
);
540 IUnknown_QueryInterface(punk
, &IID_ITfContextOwnerCompositionSink
,
541 (LPVOID
*)&This
->pITfContextOwnerCompositionSink
);
543 if (!This
->pITextStoreACP
&& !This
->pITfContextOwnerCompositionSink
)
544 FIXME("Unhandled pUnk\n");
547 This
->defaultCookie
= generate_Cookie(COOKIE_MAGIC_EDITCOOKIE
,cookie
);
548 *pecTextStore
= This
->defaultCookie
;
550 list_init(&This
->pContextKeyEventSink
);
551 list_init(&This
->pEditTransactionSink
);
552 list_init(&This
->pStatusSink
);
553 list_init(&This
->pTextEditSink
);
554 list_init(&This
->pTextLayoutSink
);
556 *ppOut
= (ITfContext
*)This
;
557 TRACE("returning %p\n", This
);
562 HRESULT
Context_Initialize(ITfContext
*iface
)
564 Context
*This
= (Context
*)iface
;
566 if (This
->pITextStoreACP
)
568 if (SUCCEEDED(TextStoreACPSink_Constructor(&This
->pITextStoreACPSink
, This
)))
569 ITextStoreACP_AdviseSink(This
->pITextStoreACP
, &IID_ITextStoreACPSink
,
570 (IUnknown
*)This
->pITextStoreACPSink
, TS_AS_ALL_SINKS
);
572 This
->connected
= TRUE
;
576 HRESULT
Context_Uninitialize(ITfContext
*iface
)
578 Context
*This
= (Context
*)iface
;
580 if (This
->pITextStoreACPSink
)
582 ITextStoreACP_UnadviseSink(This
->pITextStoreACP
, (IUnknown
*)This
->pITextStoreACPSink
);
583 if (ITextStoreACPSink_Release(This
->pITextStoreACPSink
) == 0)
584 This
->pITextStoreACPSink
= NULL
;
586 This
->connected
= FALSE
;
590 /**************************************************************************
592 **************************************************************************/
594 static void TextStoreACPSink_Destructor(TextStoreACPSink
*This
)
596 TRACE("destroying %p\n", This
);
597 HeapFree(GetProcessHeap(),0,This
);
600 static HRESULT WINAPI
TextStoreACPSink_QueryInterface(ITextStoreACPSink
*iface
, REFIID iid
, LPVOID
*ppvOut
)
602 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
605 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITextStoreACPSink
))
612 IUnknown_AddRef(iface
);
616 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
617 return E_NOINTERFACE
;
620 static ULONG WINAPI
TextStoreACPSink_AddRef(ITextStoreACPSink
*iface
)
622 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
623 return InterlockedIncrement(&This
->refCount
);
626 static ULONG WINAPI
TextStoreACPSink_Release(ITextStoreACPSink
*iface
)
628 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
631 ret
= InterlockedDecrement(&This
->refCount
);
633 TextStoreACPSink_Destructor(This
);
637 /*****************************************************
638 * ITextStoreACPSink functions
639 *****************************************************/
641 static HRESULT WINAPI
TextStoreACPSink_OnTextChange(ITextStoreACPSink
*iface
,
642 DWORD dwFlags
, const TS_TEXTCHANGE
*pChange
)
644 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
645 FIXME("STUB:(%p)\n",This
);
649 static HRESULT WINAPI
TextStoreACPSink_OnSelectionChange(ITextStoreACPSink
*iface
)
651 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
652 FIXME("STUB:(%p)\n",This
);
656 static HRESULT WINAPI
TextStoreACPSink_OnLayoutChange(ITextStoreACPSink
*iface
,
657 TsLayoutCode lcode
, TsViewCookie vcView
)
659 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
660 FIXME("STUB:(%p)\n",This
);
664 static HRESULT WINAPI
TextStoreACPSink_OnStatusChange(ITextStoreACPSink
*iface
,
667 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
668 FIXME("STUB:(%p)\n",This
);
672 static HRESULT WINAPI
TextStoreACPSink_OnAttrsChange(ITextStoreACPSink
*iface
,
673 LONG acpStart
, LONG acpEnd
, ULONG cAttrs
, const TS_ATTRID
*paAttrs
)
675 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
676 FIXME("STUB:(%p)\n",This
);
680 static HRESULT WINAPI
TextStoreACPSink_OnLockGranted(ITextStoreACPSink
*iface
,
683 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
688 TRACE("(%p) %x\n",This
, dwLockFlags
);
690 if (!This
->pContext
|| !This
->pContext
->currentEditSession
)
692 ERR("OnLockGranted called on a context without a current edit session\n");
696 cookie
= HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie
));
698 return E_OUTOFMEMORY
;
700 cookie
->lockType
= dwLockFlags
;
701 cookie
->pOwningContext
= This
->pContext
;
702 ec
= generate_Cookie(COOKIE_MAGIC_EDITCOOKIE
, cookie
);
704 hr
= ITfEditSession_DoEditSession(This
->pContext
->currentEditSession
, ec
);
706 ITfEditSession_Release(This
->pContext
->currentEditSession
);
707 This
->pContext
->currentEditSession
= NULL
;
709 /* Edit Cookie is only valid during the edit session */
710 cookie
= remove_Cookie(ec
);
711 HeapFree(GetProcessHeap(),0,cookie
);
716 static HRESULT WINAPI
TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink
*iface
)
718 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
719 FIXME("STUB:(%p)\n",This
);
723 static HRESULT WINAPI
TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink
*iface
)
725 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
726 FIXME("STUB:(%p)\n",This
);
730 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl
=
732 TextStoreACPSink_QueryInterface
,
733 TextStoreACPSink_AddRef
,
734 TextStoreACPSink_Release
,
736 TextStoreACPSink_OnTextChange
,
737 TextStoreACPSink_OnSelectionChange
,
738 TextStoreACPSink_OnLayoutChange
,
739 TextStoreACPSink_OnStatusChange
,
740 TextStoreACPSink_OnAttrsChange
,
741 TextStoreACPSink_OnLockGranted
,
742 TextStoreACPSink_OnStartEditTransaction
,
743 TextStoreACPSink_OnEndEditTransaction
746 static HRESULT
TextStoreACPSink_Constructor(ITextStoreACPSink
**ppOut
, Context
*pContext
)
748 TextStoreACPSink
*This
;
750 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(TextStoreACPSink
));
752 return E_OUTOFMEMORY
;
754 This
->TextStoreACPSinkVtbl
= &TextStoreACPSink_TextStoreACPSinkVtbl
;
757 This
->pContext
= pContext
;
759 TRACE("returning %p\n", This
);
760 *ppOut
= (ITextStoreACPSink
*)This
;