xref: /reactos/dll/ime/msctfime/sinks.cpp (revision c5e64563)
1 /*
2  * PROJECT:     ReactOS msctfime.ime
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     The sinks of msctfime.ime
5  * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include "msctfime.h"
9 
10 WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
11 
12 /// @implemented
CCompartmentEventSink(FN_EVENTSINK fnEventSink,LPVOID pUserData)13 CCompartmentEventSink::CCompartmentEventSink(FN_EVENTSINK fnEventSink, LPVOID pUserData)
14     : m_array()
15     , m_cRefs(1)
16     , m_fnEventSink(fnEventSink)
17     , m_pUserData(pUserData)
18 {
19 }
20 
21 /// @implemented
~CCompartmentEventSink()22 CCompartmentEventSink::~CCompartmentEventSink()
23 {
24 }
25 
26 /// @implemented
QueryInterface(REFIID riid,LPVOID * ppvObj)27 STDMETHODIMP CCompartmentEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
28 {
29     static const QITAB c_tab[] =
30     {
31         QITABENT(CCompartmentEventSink, ITfCompartmentEventSink),
32         { NULL }
33     };
34     return ::QISearch(this, c_tab, riid, ppvObj);
35 }
36 
37 /// @implemented
STDMETHODIMP_(ULONG)38 STDMETHODIMP_(ULONG) CCompartmentEventSink::AddRef()
39 {
40     return ::InterlockedIncrement(&m_cRefs);
41 }
42 
43 /// @implemented
STDMETHODIMP_(ULONG)44 STDMETHODIMP_(ULONG) CCompartmentEventSink::Release()
45 {
46     if (::InterlockedDecrement(&m_cRefs) == 0)
47     {
48         delete this;
49         return 0;
50     }
51     return m_cRefs;
52 }
53 
54 /// @implemented
OnChange(REFGUID rguid)55 STDMETHODIMP CCompartmentEventSink::OnChange(REFGUID rguid)
56 {
57     return m_fnEventSink(m_pUserData, rguid);
58 }
59 
60 /// @implemented
61 HRESULT
_Advise(IUnknown * pUnknown,REFGUID rguid,BOOL bThread)62 CCompartmentEventSink::_Advise(IUnknown *pUnknown, REFGUID rguid, BOOL bThread)
63 {
64     CESMAP *pCesMap = m_array.Append(1);
65     if (!pCesMap)
66         return E_OUTOFMEMORY;
67 
68     ITfSource *pSource = NULL;
69 
70     HRESULT hr = GetCompartment(pUnknown, rguid, &pCesMap->m_pComp, bThread);
71     if (FAILED(hr))
72     {
73         hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource);
74         if (FAILED(hr))
75         {
76             hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &pCesMap->m_dwCookie);
77             if (FAILED(hr))
78             {
79                 if (pCesMap->m_pComp)
80                 {
81                     pCesMap->m_pComp->Release();
82                     pCesMap->m_pComp = NULL;
83                 }
84                 m_array.Remove(m_array.size() - 1, 1);
85             }
86             else
87             {
88                 hr = S_OK;
89             }
90         }
91     }
92 
93     if (pSource)
94         pSource->Release();
95 
96     return hr;
97 }
98 
99 /// @implemented
_Unadvise()100 HRESULT CCompartmentEventSink::_Unadvise()
101 {
102     CESMAP *pCesMap = m_array.data();
103     size_t cItems = m_array.size();
104     if (!cItems)
105         return S_OK;
106 
107     do
108     {
109         ITfSource *pSource = NULL;
110         HRESULT hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource);
111         if (SUCCEEDED(hr))
112             pSource->UnadviseSink(pCesMap->m_dwCookie);
113 
114         if (pCesMap->m_pComp)
115         {
116             pCesMap->m_pComp->Release();
117             pCesMap->m_pComp = NULL;
118         }
119 
120         if (pSource)
121             pSource->Release();
122 
123         ++pCesMap;
124         --cItems;
125     } while (cItems);
126 
127     return S_OK;
128 }
129 
130 /***********************************************************************/
131 
132 /// @implemented
CTextEventSink(FN_ENDEDIT fnEndEdit,LPVOID pCallbackPV)133 CTextEventSink::CTextEventSink(FN_ENDEDIT fnEndEdit, LPVOID pCallbackPV)
134 {
135     m_cRefs = 1;
136     m_pUnknown = NULL;
137     m_dwEditSinkCookie = (DWORD)-1;
138     m_dwLayoutSinkCookie = (DWORD)-1;
139     m_fnLayoutChange = NULL;
140     m_fnEndEdit = fnEndEdit;
141     m_pCallbackPV = pCallbackPV;
142 }
143 
144 /// @implemented
~CTextEventSink()145 CTextEventSink::~CTextEventSink()
146 {
147 }
148 
149 /// @implemented
QueryInterface(REFIID riid,LPVOID * ppvObj)150 STDMETHODIMP CTextEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
151 {
152     static const QITAB c_tab[] =
153     {
154         QITABENT(CTextEventSink, ITfTextEditSink),
155         QITABENT(CTextEventSink, ITfTextLayoutSink),
156         { NULL }
157     };
158     return ::QISearch(this, c_tab, riid, ppvObj);
159 }
160 
161 /// @implemented
STDMETHODIMP_(ULONG)162 STDMETHODIMP_(ULONG) CTextEventSink::AddRef()
163 {
164     return ::InterlockedIncrement(&m_cRefs);
165 }
166 
167 /// @implemented
STDMETHODIMP_(ULONG)168 STDMETHODIMP_(ULONG) CTextEventSink::Release()
169 {
170     if (::InterlockedDecrement(&m_cRefs) == 0)
171     {
172         delete this;
173         return 0;
174     }
175     return m_cRefs;
176 }
177 
178 struct TEXT_EVENT_SINK_END_EDIT
179 {
180     TfEditCookie m_ecReadOnly;
181     ITfEditRecord *m_pEditRecord;
182     ITfContext *m_pContext;
183 };
184 
185 /// @implemented
OnEndEdit(ITfContext * pic,TfEditCookie ecReadOnly,ITfEditRecord * pEditRecord)186 STDMETHODIMP CTextEventSink::OnEndEdit(
187     ITfContext *pic,
188     TfEditCookie ecReadOnly,
189     ITfEditRecord *pEditRecord)
190 {
191     TEXT_EVENT_SINK_END_EDIT Data = { ecReadOnly, pEditRecord, pic };
192     return m_fnEndEdit(1, m_pCallbackPV, (LPVOID)&Data);
193 }
194 
195 /// @implemented
OnLayoutChange(ITfContext * pContext,TfLayoutCode lcode,ITfContextView * pContextView)196 STDMETHODIMP CTextEventSink::OnLayoutChange(
197     ITfContext *pContext,
198     TfLayoutCode lcode,
199     ITfContextView *pContextView)
200 {
201     switch (lcode)
202     {
203         case TF_LC_CREATE:
204             return m_fnLayoutChange(3, m_fnEndEdit, pContextView);
205         case TF_LC_CHANGE:
206             return m_fnLayoutChange(2, m_fnEndEdit, pContextView);
207         case TF_LC_DESTROY:
208             return m_fnLayoutChange(4, m_fnEndEdit, pContextView);
209         default:
210             return E_INVALIDARG;
211     }
212 }
213 
214 /// @implemented
_Advise(IUnknown * pUnknown,UINT uFlags)215 HRESULT CTextEventSink::_Advise(IUnknown *pUnknown, UINT uFlags)
216 {
217     m_pUnknown = NULL;
218     m_uFlags = uFlags;
219 
220     ITfSource *pSource = NULL;
221     HRESULT hr = pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
222     if (SUCCEEDED(hr))
223     {
224         ITfTextEditSink *pSink = static_cast<ITfTextEditSink*>(this);
225         if (uFlags & 1)
226             hr = pSource->AdviseSink(IID_ITfTextEditSink, pSink, &m_dwEditSinkCookie);
227         if (SUCCEEDED(hr) && (uFlags & 2))
228             hr = pSource->AdviseSink(IID_ITfTextLayoutSink, pSink, &m_dwLayoutSinkCookie);
229 
230         if (SUCCEEDED(hr))
231         {
232             m_pUnknown = pUnknown;
233             pUnknown->AddRef();
234         }
235         else
236         {
237             pSource->UnadviseSink(m_dwEditSinkCookie);
238         }
239     }
240 
241     if (pSource)
242         pSource->Release();
243 
244     return hr;
245 }
246 
247 /// @implemented
_Unadvise()248 HRESULT CTextEventSink::_Unadvise()
249 {
250     if (!m_pUnknown)
251         return E_FAIL;
252 
253     ITfSource *pSource = NULL;
254     HRESULT hr = m_pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
255     if (SUCCEEDED(hr))
256     {
257         if (m_uFlags & 1)
258             hr = pSource->UnadviseSink(m_dwEditSinkCookie);
259         if (m_uFlags & 2)
260             hr = pSource->UnadviseSink(m_dwLayoutSinkCookie);
261 
262         pSource->Release();
263     }
264 
265     m_pUnknown->Release();
266     m_pUnknown = NULL;
267 
268     return E_NOTIMPL;
269 }
270 
271 /***********************************************************************/
272 
273 /// @implemented
CThreadMgrEventSink(_In_ FN_INITDOCMGR fnInit,_In_ FN_PUSHPOP fnPushPop,_Inout_ LPVOID pvCallbackPV)274 CThreadMgrEventSink::CThreadMgrEventSink(
275     _In_ FN_INITDOCMGR fnInit,
276     _In_ FN_PUSHPOP fnPushPop,
277     _Inout_ LPVOID pvCallbackPV)
278 {
279     m_fnInit = fnInit;
280     m_fnPushPop = fnPushPop;
281     m_pCallbackPV = pvCallbackPV;
282     m_cRefs = 1;
283 }
284 
285 /// @implemented
QueryInterface(REFIID riid,LPVOID * ppvObj)286 STDMETHODIMP CThreadMgrEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
287 {
288     static const QITAB c_tab[] =
289     {
290         QITABENT(CThreadMgrEventSink, ITfThreadMgrEventSink),
291         { NULL }
292     };
293     return ::QISearch(this, c_tab, riid, ppvObj);
294 }
295 
296 /// @implemented
STDMETHODIMP_(ULONG)297 STDMETHODIMP_(ULONG) CThreadMgrEventSink::AddRef()
298 {
299     return ::InterlockedIncrement(&m_cRefs);
300 }
301 
302 /// @implemented
STDMETHODIMP_(ULONG)303 STDMETHODIMP_(ULONG) CThreadMgrEventSink::Release()
304 {
305     if (::InterlockedDecrement(&m_cRefs) == 0)
306     {
307         delete this;
308         return 0;
309     }
310     return m_cRefs;
311 }
312 
313 INT CALLBACK
DIMCallback(UINT nCode,ITfDocumentMgr * pDocMgr1,ITfDocumentMgr * pDocMgr2,LPVOID pUserData)314 CThreadMgrEventSink::DIMCallback(
315     UINT nCode,
316     ITfDocumentMgr *pDocMgr1,
317     ITfDocumentMgr *pDocMgr2,
318     LPVOID pUserData)
319 {
320     return E_NOTIMPL;
321 }
322 
OnInitDocumentMgr(ITfDocumentMgr * pdim)323 STDMETHODIMP CThreadMgrEventSink::OnInitDocumentMgr(ITfDocumentMgr *pdim)
324 {
325     if (!m_fnInit)
326         return S_OK;
327     return m_fnInit(0, pdim, NULL, m_pCallbackPV);
328 }
329 
OnUninitDocumentMgr(ITfDocumentMgr * pdim)330 STDMETHODIMP CThreadMgrEventSink::OnUninitDocumentMgr(ITfDocumentMgr *pdim)
331 {
332     if (!m_fnInit)
333         return S_OK;
334     return m_fnInit(1, pdim, NULL, m_pCallbackPV);
335 }
336 
337 STDMETHODIMP
OnSetFocus(ITfDocumentMgr * pdimFocus,ITfDocumentMgr * pdimPrevFocus)338 CThreadMgrEventSink::OnSetFocus(ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus)
339 {
340     if (!m_fnInit)
341         return S_OK;
342     return m_fnInit(2, pdimFocus, pdimPrevFocus, m_pCallbackPV);
343 }
344 
OnPushContext(ITfContext * pic)345 STDMETHODIMP CThreadMgrEventSink::OnPushContext(ITfContext *pic)
346 {
347     if (!m_fnPushPop)
348         return S_OK;
349     return m_fnPushPop(3, pic, m_pCallbackPV);
350 }
351 
OnPopContext(ITfContext * pic)352 STDMETHODIMP CThreadMgrEventSink::OnPopContext(ITfContext *pic)
353 {
354     if (!m_fnPushPop)
355         return S_OK;
356     return m_fnPushPop(4, pic, m_pCallbackPV);
357 }
358 
SetCallbackPV(_Inout_ LPVOID pv)359 void CThreadMgrEventSink::SetCallbackPV(_Inout_ LPVOID pv)
360 {
361     if (!m_pCallbackPV)
362         m_pCallbackPV = pv;
363 }
364 
_Advise(ITfThreadMgr * pThreadMgr)365 HRESULT CThreadMgrEventSink::_Advise(ITfThreadMgr *pThreadMgr)
366 {
367     m_pThreadMgr = NULL;
368 
369     HRESULT hr = E_FAIL;
370     ITfSource *pSource = NULL;
371     if (pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK &&
372         pSource->AdviseSink(IID_ITfThreadMgrEventSink, this, &m_dwCookie) == S_OK)
373     {
374         m_pThreadMgr = pThreadMgr;
375         pThreadMgr->AddRef();
376         hr = S_OK;
377     }
378 
379     if (pSource)
380         pSource->Release();
381 
382     return hr;
383 }
384 
_Unadvise()385 HRESULT CThreadMgrEventSink::_Unadvise()
386 {
387     HRESULT hr = E_FAIL;
388     ITfSource *pSource = NULL;
389 
390     if (m_pThreadMgr)
391     {
392         if (m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK &&
393             pSource->UnadviseSink(m_dwCookie) == S_OK)
394         {
395             hr = S_OK;
396         }
397 
398         if (pSource)
399             pSource->Release();
400     }
401 
402     if (m_pThreadMgr)
403     {
404         m_pThreadMgr->Release();
405         m_pThreadMgr = NULL;
406     }
407 
408     return hr;
409 }
410 
411 /***********************************************************************/
412 
413 /// @implemented
CActiveLanguageProfileNotifySink(_In_ FN_COMPARE fnCompare,_Inout_opt_ void * pUserData)414 CActiveLanguageProfileNotifySink::CActiveLanguageProfileNotifySink(
415     _In_ FN_COMPARE fnCompare,
416     _Inout_opt_ void *pUserData)
417 {
418     m_dwConnection = (DWORD)-1;
419     m_fnCompare = fnCompare;
420     m_cRefs = 1;
421     m_pUserData = pUserData;
422 }
423 
424 /// @implemented
~CActiveLanguageProfileNotifySink()425 CActiveLanguageProfileNotifySink::~CActiveLanguageProfileNotifySink()
426 {
427 }
428 
429 /// @implemented
QueryInterface(REFIID riid,LPVOID * ppvObj)430 STDMETHODIMP CActiveLanguageProfileNotifySink::QueryInterface(REFIID riid, LPVOID* ppvObj)
431 {
432     static const QITAB c_tab[] =
433     {
434         QITABENT(CActiveLanguageProfileNotifySink, ITfActiveLanguageProfileNotifySink),
435         { NULL }
436     };
437     return ::QISearch(this, c_tab, riid, ppvObj);
438 }
439 
440 /// @implemented
STDMETHODIMP_(ULONG)441 STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::AddRef()
442 {
443     return ::InterlockedIncrement(&m_cRefs);
444 }
445 
446 /// @implemented
STDMETHODIMP_(ULONG)447 STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::Release()
448 {
449     if (::InterlockedDecrement(&m_cRefs) == 0)
450     {
451         delete this;
452         return 0;
453     }
454     return m_cRefs;
455 }
456 
457 /// @implemented
458 STDMETHODIMP
OnActivated(REFCLSID clsid,REFGUID guidProfile,BOOL fActivated)459 CActiveLanguageProfileNotifySink::OnActivated(
460     REFCLSID clsid,
461     REFGUID guidProfile,
462     BOOL fActivated)
463 {
464     if (!m_fnCompare)
465         return 0;
466 
467     return m_fnCompare(clsid, guidProfile, fActivated, m_pUserData);
468 }
469 
470 /// @implemented
471 HRESULT
_Advise(ITfThreadMgr * pThreadMgr)472 CActiveLanguageProfileNotifySink::_Advise(
473     ITfThreadMgr *pThreadMgr)
474 {
475     m_pThreadMgr = NULL;
476 
477     ITfSource *pSource = NULL;
478     HRESULT hr = pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
479     if (FAILED(hr))
480         return E_FAIL;
481 
482     hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, this, &m_dwConnection);
483     if (SUCCEEDED(hr))
484     {
485         m_pThreadMgr = pThreadMgr;
486         pThreadMgr->AddRef();
487         hr = S_OK;
488     }
489     else
490     {
491         hr = E_FAIL;
492     }
493 
494     if (pSource)
495         pSource->Release();
496 
497     return hr;
498 }
499 
500 /// @implemented
501 HRESULT
_Unadvise()502 CActiveLanguageProfileNotifySink::_Unadvise()
503 {
504     if (!m_pThreadMgr)
505         return E_FAIL;
506 
507     ITfSource *pSource = NULL;
508     HRESULT hr = m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
509     if (SUCCEEDED(hr))
510     {
511         hr = pSource->UnadviseSink(m_dwConnection);
512         if (SUCCEEDED(hr))
513             hr = S_OK;
514     }
515 
516     if (pSource)
517         pSource->Release();
518 
519     if (m_pThreadMgr)
520     {
521         m_pThreadMgr->Release();
522         m_pThreadMgr = NULL;
523     }
524 
525     return hr;
526 }
527