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