[MSCMS] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msctf / documentmgr.c
1 /*
2 * ITfDocumentMgr 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 #include "msctf_internal.h"
22
23 typedef struct tagDocumentMgr {
24 ITfDocumentMgr ITfDocumentMgr_iface;
25 ITfSource ITfSource_iface;
26 LONG refCount;
27
28 /* Aggregation */
29 ITfCompartmentMgr *CompartmentMgr;
30
31 ITfContext* contextStack[2]; /* limit of 2 contexts */
32 ITfThreadMgrEventSink* ThreadMgrSink;
33
34 struct list TransitoryExtensionSink;
35 } DocumentMgr;
36
37 typedef struct tagEnumTfContext {
38 IEnumTfContexts IEnumTfContexts_iface;
39 LONG refCount;
40
41 DWORD index;
42 DocumentMgr *docmgr;
43 } EnumTfContext;
44
45 static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut);
46
47 static inline DocumentMgr *impl_from_ITfDocumentMgr(ITfDocumentMgr *iface)
48 {
49 return CONTAINING_RECORD(iface, DocumentMgr, ITfDocumentMgr_iface);
50 }
51
52 static inline DocumentMgr *impl_from_ITfSource(ITfSource *iface)
53 {
54 return CONTAINING_RECORD(iface, DocumentMgr, ITfSource_iface);
55 }
56
57 static inline EnumTfContext *impl_from_IEnumTfContexts(IEnumTfContexts *iface)
58 {
59 return CONTAINING_RECORD(iface, EnumTfContext, IEnumTfContexts_iface);
60 }
61
62 static void DocumentMgr_Destructor(DocumentMgr *This)
63 {
64 ITfThreadMgr *tm;
65 TRACE("destroying %p\n", This);
66
67 TF_GetThreadMgr(&tm);
68 ThreadMgr_OnDocumentMgrDestruction(tm, &This->ITfDocumentMgr_iface);
69
70 if (This->contextStack[0])
71 ITfContext_Release(This->contextStack[0]);
72 if (This->contextStack[1])
73 ITfContext_Release(This->contextStack[1]);
74 free_sinks(&This->TransitoryExtensionSink);
75 CompartmentMgr_Destructor(This->CompartmentMgr);
76 HeapFree(GetProcessHeap(),0,This);
77 }
78
79 static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID iid, LPVOID *ppvOut)
80 {
81 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
82 *ppvOut = NULL;
83
84 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfDocumentMgr))
85 {
86 *ppvOut = &This->ITfDocumentMgr_iface;
87 }
88 else if (IsEqualIID(iid, &IID_ITfSource))
89 {
90 *ppvOut = &This->ITfSource_iface;
91 }
92 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
93 {
94 *ppvOut = This->CompartmentMgr;
95 }
96
97 if (*ppvOut)
98 {
99 ITfDocumentMgr_AddRef(iface);
100 return S_OK;
101 }
102
103 WARN("unsupported interface: %s\n", debugstr_guid(iid));
104 return E_NOINTERFACE;
105 }
106
107 static ULONG WINAPI DocumentMgr_AddRef(ITfDocumentMgr *iface)
108 {
109 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
110 return InterlockedIncrement(&This->refCount);
111 }
112
113 static ULONG WINAPI DocumentMgr_Release(ITfDocumentMgr *iface)
114 {
115 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
116 ULONG ret;
117
118 ret = InterlockedDecrement(&This->refCount);
119 if (ret == 0)
120 DocumentMgr_Destructor(This);
121 return ret;
122 }
123
124 /*****************************************************
125 * ITfDocumentMgr functions
126 *****************************************************/
127 static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface,
128 TfClientId tidOwner,
129 DWORD dwFlags, IUnknown *punk, ITfContext **ppic,
130 TfEditCookie *pecTextStore)
131 {
132 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
133 TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore);
134 return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore);
135 }
136
137 static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic)
138 {
139 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
140 ITfContext *check;
141
142 TRACE("(%p) %p\n",This,pic);
143
144 if (This->contextStack[1]) /* FUll */
145 return TF_E_STACKFULL;
146
147 if (!pic || FAILED(ITfContext_QueryInterface(pic,&IID_ITfContext,(LPVOID*) &check)))
148 return E_INVALIDARG;
149
150 if (This->contextStack[0] == NULL)
151 ITfThreadMgrEventSink_OnInitDocumentMgr(This->ThreadMgrSink,iface);
152
153 This->contextStack[1] = This->contextStack[0];
154 This->contextStack[0] = check;
155
156 Context_Initialize(check, iface);
157 ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check);
158
159 return S_OK;
160 }
161
162 static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags)
163 {
164 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
165 TRACE("(%p) 0x%x\n",This,dwFlags);
166
167 if (dwFlags == TF_POPF_ALL)
168 {
169 int i;
170
171 for (i = 0; i < sizeof(This->contextStack)/sizeof(This->contextStack[0]); i++)
172 if (This->contextStack[i])
173 {
174 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink, This->contextStack[i]);
175 Context_Uninitialize(This->contextStack[i]);
176 ITfContext_Release(This->contextStack[i]);
177 This->contextStack[i] = NULL;
178 }
179
180 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface);
181 return S_OK;
182 }
183
184 if (dwFlags)
185 return E_INVALIDARG;
186
187 if (This->contextStack[1] == NULL) /* Cannot pop last context */
188 return E_FAIL;
189
190 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink,This->contextStack[0]);
191 Context_Uninitialize(This->contextStack[0]);
192 ITfContext_Release(This->contextStack[0]);
193 This->contextStack[0] = This->contextStack[1];
194 This->contextStack[1] = NULL;
195
196 if (This->contextStack[0] == NULL)
197 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface);
198
199 return S_OK;
200 }
201
202 static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic)
203 {
204 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
205 TRACE("(%p)\n",This);
206 if (!ppic)
207 return E_INVALIDARG;
208
209 if (This->contextStack[0])
210 ITfContext_AddRef(This->contextStack[0]);
211
212 *ppic = This->contextStack[0];
213
214 return S_OK;
215 }
216
217 static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **ppic)
218 {
219 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
220 ITfContext *tgt;
221
222 TRACE("(%p)\n",This);
223 if (!ppic)
224 return E_INVALIDARG;
225
226 if (This->contextStack[1])
227 tgt = This->contextStack[1];
228 else
229 tgt = This->contextStack[0];
230
231 if (tgt)
232 ITfContext_AddRef(tgt);
233
234 *ppic = tgt;
235
236 return S_OK;
237 }
238
239 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum)
240 {
241 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
242 TRACE("(%p) %p\n",This,ppEnum);
243 return EnumTfContext_Constructor(This, ppEnum);
244 }
245
246 static const ITfDocumentMgrVtbl DocumentMgrVtbl =
247 {
248 DocumentMgr_QueryInterface,
249 DocumentMgr_AddRef,
250 DocumentMgr_Release,
251 DocumentMgr_CreateContext,
252 DocumentMgr_Push,
253 DocumentMgr_Pop,
254 DocumentMgr_GetTop,
255 DocumentMgr_GetBase,
256 DocumentMgr_EnumContexts
257 };
258
259 static HRESULT WINAPI DocumentMgrSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
260 {
261 DocumentMgr *This = impl_from_ITfSource(iface);
262 return ITfDocumentMgr_QueryInterface(&This->ITfDocumentMgr_iface, iid, ppvOut);
263 }
264
265 static ULONG WINAPI DocumentMgrSource_AddRef(ITfSource *iface)
266 {
267 DocumentMgr *This = impl_from_ITfSource(iface);
268 return ITfDocumentMgr_AddRef(&This->ITfDocumentMgr_iface);
269 }
270
271 static ULONG WINAPI DocumentMgrSource_Release(ITfSource *iface)
272 {
273 DocumentMgr *This = impl_from_ITfSource(iface);
274 return ITfDocumentMgr_Release(&This->ITfDocumentMgr_iface);
275 }
276
277 /*****************************************************
278 * ITfSource functions
279 *****************************************************/
280 static HRESULT WINAPI DocumentMgrSource_AdviseSink(ITfSource *iface,
281 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
282 {
283 DocumentMgr *This = impl_from_ITfSource(iface);
284
285 TRACE("(%p) %s %p %p\n", This, debugstr_guid(riid), punk, pdwCookie);
286
287 if (!riid || !punk || !pdwCookie)
288 return E_INVALIDARG;
289
290 if (IsEqualIID(riid, &IID_ITfTransitoryExtensionSink))
291 {
292 WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n");
293 return advise_sink(&This->TransitoryExtensionSink, &IID_ITfTransitoryExtensionSink,
294 COOKIE_MAGIC_DMSINK, punk, pdwCookie);
295 }
296
297 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
298 return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI DocumentMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
302 {
303 DocumentMgr *This = impl_from_ITfSource(iface);
304
305 TRACE("(%p) %x\n",This,pdwCookie);
306
307 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_DMSINK)
308 return E_INVALIDARG;
309
310 return unadvise_sink(pdwCookie);
311 }
312
313 static const ITfSourceVtbl DocumentMgrSourceVtbl =
314 {
315 DocumentMgrSource_QueryInterface,
316 DocumentMgrSource_AddRef,
317 DocumentMgrSource_Release,
318 DocumentMgrSource_AdviseSink,
319 DocumentMgrSource_UnadviseSink,
320 };
321
322 HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut)
323 {
324 DocumentMgr *This;
325
326 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr));
327 if (This == NULL)
328 return E_OUTOFMEMORY;
329
330 This->ITfDocumentMgr_iface.lpVtbl = &DocumentMgrVtbl;
331 This->ITfSource_iface.lpVtbl = &DocumentMgrSourceVtbl;
332 This->refCount = 1;
333 This->ThreadMgrSink = ThreadMgrSink;
334 list_init(&This->TransitoryExtensionSink);
335
336 CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
337
338 *ppOut = &This->ITfDocumentMgr_iface;
339 TRACE("returning %p\n", *ppOut);
340 return S_OK;
341 }
342
343 /**************************************************
344 * IEnumTfContexts implementation
345 **************************************************/
346 static void EnumTfContext_Destructor(EnumTfContext *This)
347 {
348 TRACE("destroying %p\n", This);
349 HeapFree(GetProcessHeap(),0,This);
350 }
351
352 static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut)
353 {
354 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
355 *ppvOut = NULL;
356
357 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts))
358 {
359 *ppvOut = &This->IEnumTfContexts_iface;
360 }
361
362 if (*ppvOut)
363 {
364 IEnumTfContexts_AddRef(iface);
365 return S_OK;
366 }
367
368 WARN("unsupported interface: %s\n", debugstr_guid(iid));
369 return E_NOINTERFACE;
370 }
371
372 static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface)
373 {
374 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
375 return InterlockedIncrement(&This->refCount);
376 }
377
378 static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface)
379 {
380 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
381 ULONG ret;
382
383 ret = InterlockedDecrement(&This->refCount);
384 if (ret == 0)
385 EnumTfContext_Destructor(This);
386 return ret;
387 }
388
389 static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface,
390 ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched)
391 {
392 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
393 ULONG fetched = 0;
394
395 TRACE("(%p)\n",This);
396
397 if (rgContext == NULL) return E_POINTER;
398
399 while (fetched < ulCount)
400 {
401 if (This->index > 1)
402 break;
403
404 if (!This->docmgr->contextStack[This->index])
405 break;
406
407 *rgContext = This->docmgr->contextStack[This->index];
408 ITfContext_AddRef(*rgContext);
409
410 ++This->index;
411 ++fetched;
412 ++rgContext;
413 }
414
415 if (pcFetched) *pcFetched = fetched;
416 return fetched == ulCount ? S_OK : S_FALSE;
417 }
418
419 static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt)
420 {
421 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
422 TRACE("(%p)\n",This);
423 This->index += celt;
424 return S_OK;
425 }
426
427 static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface)
428 {
429 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
430 TRACE("(%p)\n",This);
431 This->index = 0;
432 return S_OK;
433 }
434
435 static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface,
436 IEnumTfContexts **ppenum)
437 {
438 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
439 HRESULT res;
440
441 TRACE("(%p)\n",This);
442
443 if (ppenum == NULL) return E_POINTER;
444
445 res = EnumTfContext_Constructor(This->docmgr, ppenum);
446 if (SUCCEEDED(res))
447 {
448 EnumTfContext *new_This = impl_from_IEnumTfContexts(*ppenum);
449 new_This->index = This->index;
450 }
451 return res;
452 }
453
454 static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={
455 EnumTfContext_QueryInterface,
456 EnumTfContext_AddRef,
457 EnumTfContext_Release,
458
459 EnumTfContext_Clone,
460 EnumTfContext_Next,
461 EnumTfContext_Reset,
462 EnumTfContext_Skip
463 };
464
465 static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut)
466 {
467 EnumTfContext *This;
468
469 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext));
470 if (This == NULL)
471 return E_OUTOFMEMORY;
472
473 This->IEnumTfContexts_iface.lpVtbl = &IEnumTfContexts_Vtbl;
474 This->refCount = 1;
475 This->docmgr = mgr;
476
477 *ppOut = &This->IEnumTfContexts_iface;
478 TRACE("returning %p\n", *ppOut);
479 return S_OK;
480 }