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