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