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_READ
)
247 dwLockFlags
|= TS_LF_READ
;
248 else if ((dwFlags
& TF_ES_READWRITE
) == TF_ES_READWRITE
)
249 dwLockFlags
|= TS_LF_READWRITE
;
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
;
302 FIXME("STUB:(%p)\n",This
);
306 static HRESULT WINAPI
Context_GetEnd (ITfContext
*iface
,
307 TfEditCookie ec
, ITfRange
**ppEnd
)
309 Context
*This
= (Context
*)iface
;
310 FIXME("STUB:(%p)\n",This
);
314 static HRESULT WINAPI
Context_GetActiveView (ITfContext
*iface
,
315 ITfContextView
**ppView
)
317 Context
*This
= (Context
*)iface
;
318 FIXME("STUB:(%p)\n",This
);
322 static HRESULT WINAPI
Context_EnumViews (ITfContext
*iface
,
323 IEnumTfContextViews
**ppEnum
)
325 Context
*This
= (Context
*)iface
;
326 FIXME("STUB:(%p)\n",This
);
330 static HRESULT WINAPI
Context_GetStatus (ITfContext
*iface
,
333 Context
*This
= (Context
*)iface
;
334 FIXME("STUB:(%p)\n",This
);
338 static HRESULT WINAPI
Context_GetProperty (ITfContext
*iface
,
339 REFGUID guidProp
, ITfProperty
**ppProp
)
341 Context
*This
= (Context
*)iface
;
342 FIXME("STUB:(%p)\n",This
);
346 static HRESULT WINAPI
Context_GetAppProperty (ITfContext
*iface
,
347 REFGUID guidProp
, ITfReadOnlyProperty
**ppProp
)
349 Context
*This
= (Context
*)iface
;
350 FIXME("STUB:(%p)\n",This
);
354 static HRESULT WINAPI
Context_TrackProperties (ITfContext
*iface
,
355 const GUID
**prgProp
, ULONG cProp
, const GUID
**prgAppProp
,
356 ULONG cAppProp
, ITfReadOnlyProperty
**ppProperty
)
358 Context
*This
= (Context
*)iface
;
359 FIXME("STUB:(%p)\n",This
);
363 static HRESULT WINAPI
Context_EnumProperties (ITfContext
*iface
,
364 IEnumTfProperties
**ppEnum
)
366 Context
*This
= (Context
*)iface
;
367 FIXME("STUB:(%p)\n",This
);
371 static HRESULT WINAPI
Context_GetDocumentMgr (ITfContext
*iface
,
372 ITfDocumentMgr
**ppDm
)
374 Context
*This
= (Context
*)iface
;
375 FIXME("STUB:(%p)\n",This
);
379 static HRESULT WINAPI
Context_CreateRangeBackup (ITfContext
*iface
,
380 TfEditCookie ec
, ITfRange
*pRange
, ITfRangeBackup
**ppBackup
)
382 Context
*This
= (Context
*)iface
;
383 FIXME("STUB:(%p)\n",This
);
387 static const ITfContextVtbl Context_ContextVtbl
=
389 Context_QueryInterface
,
393 Context_RequestEditSession
,
394 Context_InWriteSession
,
395 Context_GetSelection
,
396 Context_SetSelection
,
399 Context_GetActiveView
,
403 Context_GetAppProperty
,
404 Context_TrackProperties
,
405 Context_EnumProperties
,
406 Context_GetDocumentMgr
,
407 Context_CreateRangeBackup
410 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
412 Context
*This
= impl_from_ITfSourceVtbl(iface
);
413 return Context_QueryInterface((ITfContext
*)This
, iid
, *ppvOut
);
416 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
418 Context
*This
= impl_from_ITfSourceVtbl(iface
);
419 return Context_AddRef((ITfContext
*)This
);
422 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
424 Context
*This
= impl_from_ITfSourceVtbl(iface
);
425 return Context_Release((ITfContext
*)This
);
428 /*****************************************************
429 * ITfSource functions
430 *****************************************************/
431 static WINAPI HRESULT
ContextSource_AdviseSink(ITfSource
*iface
,
432 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
435 Context
*This
= impl_from_ITfSourceVtbl(iface
);
436 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
438 if (!riid
|| !punk
|| !pdwCookie
)
441 if (IsEqualIID(riid
, &IID_ITfTextEditSink
))
443 es
= HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink
));
445 return E_OUTOFMEMORY
;
446 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&es
->interfaces
.pITfTextEditSink
)))
448 HeapFree(GetProcessHeap(),0,es
);
449 return CONNECT_E_CANNOTCONNECT
;
451 list_add_head(&This
->pTextEditSink
,&es
->entry
);
452 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_CONTEXTSINK
, es
);
456 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
460 TRACE("cookie %x\n",*pdwCookie
);
464 static WINAPI HRESULT
ContextSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
467 Context
*This
= impl_from_ITfSourceVtbl(iface
);
469 TRACE("(%p) %x\n",This
,pdwCookie
);
471 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_CONTEXTSINK
)
474 sink
= (ContextSink
*)remove_Cookie(pdwCookie
);
476 return CONNECT_E_NOCONNECTION
;
478 list_remove(&sink
->entry
);
484 static const ITfSourceVtbl Context_SourceVtbl
=
486 Source_QueryInterface
,
490 ContextSource_AdviseSink
,
491 ContextSource_UnadviseSink
,
494 HRESULT
Context_Constructor(TfClientId tidOwner
, IUnknown
*punk
, ITfContext
**ppOut
, TfEditCookie
*pecTextStore
)
499 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Context
));
501 return E_OUTOFMEMORY
;
503 cookie
= HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie
));
506 HeapFree(GetProcessHeap(),0,This
);
507 return E_OUTOFMEMORY
;
510 TRACE("(%p) %x %p %p %p\n",This
, tidOwner
, punk
, ppOut
, pecTextStore
);
512 This
->ContextVtbl
= &Context_ContextVtbl
;
513 This
->SourceVtbl
= &Context_SourceVtbl
;
515 This
->tidOwner
= tidOwner
;
516 This
->connected
= FALSE
;
518 cookie
->lockType
= TF_ES_READ
;
519 cookie
->pOwningContext
= This
;
523 IUnknown_QueryInterface(punk
, &IID_ITextStoreACP
,
524 (LPVOID
*)&This
->pITextStoreACP
);
526 IUnknown_QueryInterface(punk
, &IID_ITfContextOwnerCompositionSink
,
527 (LPVOID
*)&This
->pITfContextOwnerCompositionSink
);
529 if (!This
->pITextStoreACP
&& !This
->pITfContextOwnerCompositionSink
)
530 FIXME("Unhandled pUnk\n");
533 This
->defaultCookie
= generate_Cookie(COOKIE_MAGIC_EDITCOOKIE
,cookie
);
534 *pecTextStore
= This
->defaultCookie
;
536 list_init(&This
->pContextKeyEventSink
);
537 list_init(&This
->pEditTransactionSink
);
538 list_init(&This
->pStatusSink
);
539 list_init(&This
->pTextEditSink
);
540 list_init(&This
->pTextLayoutSink
);
542 *ppOut
= (ITfContext
*)This
;
543 TRACE("returning %p\n", This
);
548 HRESULT
Context_Initialize(ITfContext
*iface
)
550 Context
*This
= (Context
*)iface
;
552 if (This
->pITextStoreACP
)
554 if (SUCCEEDED(TextStoreACPSink_Constructor(&This
->pITextStoreACPSink
, This
)))
555 ITextStoreACP_AdviseSink(This
->pITextStoreACP
, &IID_ITextStoreACPSink
,
556 (IUnknown
*)This
->pITextStoreACPSink
, TS_AS_ALL_SINKS
);
558 This
->connected
= TRUE
;
562 HRESULT
Context_Uninitialize(ITfContext
*iface
)
564 Context
*This
= (Context
*)iface
;
566 if (This
->pITextStoreACPSink
)
568 ITextStoreACP_UnadviseSink(This
->pITextStoreACP
, (IUnknown
*)This
->pITextStoreACPSink
);
569 if (ITextStoreACPSink_Release(This
->pITextStoreACPSink
) == 0)
570 This
->pITextStoreACPSink
= NULL
;
572 This
->connected
= FALSE
;
576 /**************************************************************************
578 **************************************************************************/
580 static void TextStoreACPSink_Destructor(TextStoreACPSink
*This
)
582 TRACE("destroying %p\n", This
);
583 HeapFree(GetProcessHeap(),0,This
);
586 static HRESULT WINAPI
TextStoreACPSink_QueryInterface(ITextStoreACPSink
*iface
, REFIID iid
, LPVOID
*ppvOut
)
588 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
591 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITextStoreACPSink
))
598 IUnknown_AddRef(iface
);
602 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
603 return E_NOINTERFACE
;
606 static ULONG WINAPI
TextStoreACPSink_AddRef(ITextStoreACPSink
*iface
)
608 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
609 return InterlockedIncrement(&This
->refCount
);
612 static ULONG WINAPI
TextStoreACPSink_Release(ITextStoreACPSink
*iface
)
614 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
617 ret
= InterlockedDecrement(&This
->refCount
);
619 TextStoreACPSink_Destructor(This
);
623 /*****************************************************
624 * ITextStoreACPSink functions
625 *****************************************************/
627 static HRESULT WINAPI
TextStoreACPSink_OnTextChange(ITextStoreACPSink
*iface
,
628 DWORD dwFlags
, const TS_TEXTCHANGE
*pChange
)
630 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
631 FIXME("STUB:(%p)\n",This
);
635 static HRESULT WINAPI
TextStoreACPSink_OnSelectionChange(ITextStoreACPSink
*iface
)
637 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
638 FIXME("STUB:(%p)\n",This
);
642 static HRESULT WINAPI
TextStoreACPSink_OnLayoutChange(ITextStoreACPSink
*iface
,
643 TsLayoutCode lcode
, TsViewCookie vcView
)
645 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
646 FIXME("STUB:(%p)\n",This
);
650 static HRESULT WINAPI
TextStoreACPSink_OnStatusChange(ITextStoreACPSink
*iface
,
653 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
654 FIXME("STUB:(%p)\n",This
);
658 static HRESULT WINAPI
TextStoreACPSink_OnAttrsChange(ITextStoreACPSink
*iface
,
659 LONG acpStart
, LONG acpEnd
, ULONG cAttrs
, const TS_ATTRID
*paAttrs
)
661 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
662 FIXME("STUB:(%p)\n",This
);
666 static HRESULT WINAPI
TextStoreACPSink_OnLockGranted(ITextStoreACPSink
*iface
,
669 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
672 TRACE("(%p) %x\n",This
, dwLockFlags
);
674 if (!This
->pContext
|| !This
->pContext
->currentEditSession
)
676 ERR("OnLockGranted called on a context without a current edit session\n");
680 /* TODO: generate and use an edit cookie */
681 hr
= ITfEditSession_DoEditSession(This
->pContext
->currentEditSession
, 0xdeadcafe);
683 ITfEditSession_Release(This
->pContext
->currentEditSession
);
684 This
->pContext
->currentEditSession
= NULL
;
689 static HRESULT WINAPI
TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink
*iface
)
691 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
692 FIXME("STUB:(%p)\n",This
);
696 static HRESULT WINAPI
TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink
*iface
)
698 TextStoreACPSink
*This
= (TextStoreACPSink
*)iface
;
699 FIXME("STUB:(%p)\n",This
);
703 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl
=
705 TextStoreACPSink_QueryInterface
,
706 TextStoreACPSink_AddRef
,
707 TextStoreACPSink_Release
,
709 TextStoreACPSink_OnTextChange
,
710 TextStoreACPSink_OnSelectionChange
,
711 TextStoreACPSink_OnLayoutChange
,
712 TextStoreACPSink_OnStatusChange
,
713 TextStoreACPSink_OnAttrsChange
,
714 TextStoreACPSink_OnLockGranted
,
715 TextStoreACPSink_OnStartEditTransaction
,
716 TextStoreACPSink_OnEndEditTransaction
719 static HRESULT
TextStoreACPSink_Constructor(ITextStoreACPSink
**ppOut
, Context
*pContext
)
721 TextStoreACPSink
*This
;
723 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(TextStoreACPSink
));
725 return E_OUTOFMEMORY
;
727 This
->TextStoreACPSinkVtbl
= &TextStoreACPSink_TextStoreACPSinkVtbl
;
730 This
->pContext
= pContext
;
732 TRACE("returning %p\n", This
);
733 *ppOut
= (ITextStoreACPSink
*)This
;