msctf: Add stub ITextStoreACPSink.
[wine] / dlls / msctf / context.c
1 /*
2  *  ITfContext 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 #include "olectl.h"
36
37 #include "wine/unicode.h"
38 #include "wine/list.h"
39
40 #include "msctf.h"
41 #include "msctf_internal.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
44
45 typedef struct tagContextSink {
46     struct list         entry;
47     union {
48         /* Context Sinks */
49         IUnknown            *pIUnknown;
50         /* ITfContextKeyEventSink  *pITfContextKeyEventSink; */
51         /* ITfEditTransactionSink  *pITfEditTransactionSink; */
52         /* ITfStatusSink           *pITfStatusSink; */
53         ITfTextEditSink     *pITfTextEditSink;
54         /* ITfTextLayoutSink       *pITfTextLayoutSink; */
55     } interfaces;
56 } ContextSink;
57
58 typedef struct tagContext {
59     const ITfContextVtbl *ContextVtbl;
60     const ITfSourceVtbl *SourceVtbl;
61     LONG refCount;
62
63     TfClientId tidOwner;
64     IUnknown *punk;  /* possible ITextStoreACP or ITfContextOwnerCompositionSink */
65
66     /* kept as seperate lists to reduce unnesseccary iterations */
67     struct list     pContextKeyEventSink;
68     struct list     pEditTransactionSink;
69     struct list     pStatusSink;
70     struct list     pTextEditSink;
71     struct list     pTextLayoutSink;
72
73 } Context;
74
75
76 typedef struct tagTextStoreACPSink {
77     const ITextStoreACPSinkVtbl *TextStoreACPSinkVtbl;
78     LONG refCount;
79
80     Context *pContext;
81 } TextStoreACPSink;
82
83
84 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
85
86 static inline Context *impl_from_ITfSourceVtbl(ITfSource *iface)
87 {
88     return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceVtbl));
89 }
90
91 static void free_sink(ContextSink *sink)
92 {
93         IUnknown_Release(sink->interfaces.pIUnknown);
94         HeapFree(GetProcessHeap(),0,sink);
95 }
96
97 static void Context_Destructor(Context *This)
98 {
99     struct list *cursor, *cursor2;
100     TRACE("destroying %p\n", This);
101
102     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
103     {
104         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
105         list_remove(cursor);
106         free_sink(sink);
107     }
108     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
109     {
110         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
111         list_remove(cursor);
112         free_sink(sink);
113     }
114     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
115     {
116         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
117         list_remove(cursor);
118         free_sink(sink);
119     }
120     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
121     {
122         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
123         list_remove(cursor);
124         free_sink(sink);
125     }
126     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
127     {
128         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
129         list_remove(cursor);
130         free_sink(sink);
131     }
132
133     HeapFree(GetProcessHeap(),0,This);
134 }
135
136 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
137 {
138     Context *This = (Context *)iface;
139     *ppvOut = NULL;
140
141     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
142     {
143         *ppvOut = This;
144     }
145     else if (IsEqualIID(iid, &IID_ITfSource))
146     {
147         *ppvOut = &This->SourceVtbl;
148     }
149
150     if (*ppvOut)
151     {
152         IUnknown_AddRef(iface);
153         return S_OK;
154     }
155
156     WARN("unsupported interface: %s\n", debugstr_guid(iid));
157     return E_NOINTERFACE;
158 }
159
160 static ULONG WINAPI Context_AddRef(ITfContext *iface)
161 {
162     Context *This = (Context *)iface;
163     return InterlockedIncrement(&This->refCount);
164 }
165
166 static ULONG WINAPI Context_Release(ITfContext *iface)
167 {
168     Context *This = (Context *)iface;
169     ULONG ret;
170
171     ret = InterlockedDecrement(&This->refCount);
172     if (ret == 0)
173         Context_Destructor(This);
174     return ret;
175 }
176
177 /*****************************************************
178  * ITfContext functions
179  *****************************************************/
180 static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
181         TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
182         HRESULT *phrSession)
183 {
184     Context *This = (Context *)iface;
185     FIXME("STUB:(%p)\n",This);
186     return E_NOTIMPL;
187 }
188
189 static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
190          TfClientId tid,
191          BOOL *pfWriteSession)
192 {
193     Context *This = (Context *)iface;
194     FIXME("STUB:(%p)\n",This);
195     return E_NOTIMPL;
196 }
197
198 static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
199         TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
200         TF_SELECTION *pSelection, ULONG *pcFetched)
201 {
202     Context *This = (Context *)iface;
203     FIXME("STUB:(%p)\n",This);
204     return E_NOTIMPL;
205 }
206
207 static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
208         TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
209 {
210     Context *This = (Context *)iface;
211     FIXME("STUB:(%p)\n",This);
212     return E_NOTIMPL;
213 }
214
215 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
216         TfEditCookie ec, ITfRange **ppStart)
217 {
218     Context *This = (Context *)iface;
219     FIXME("STUB:(%p)\n",This);
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
224         TfEditCookie ec, ITfRange **ppEnd)
225 {
226     Context *This = (Context *)iface;
227     FIXME("STUB:(%p)\n",This);
228     return E_NOTIMPL;
229 }
230
231 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
232   ITfContextView **ppView)
233 {
234     Context *This = (Context *)iface;
235     FIXME("STUB:(%p)\n",This);
236     return E_NOTIMPL;
237 }
238
239 static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
240         IEnumTfContextViews **ppEnum)
241 {
242     Context *This = (Context *)iface;
243     FIXME("STUB:(%p)\n",This);
244     return E_NOTIMPL;
245 }
246
247 static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
248         TF_STATUS *pdcs)
249 {
250     Context *This = (Context *)iface;
251     FIXME("STUB:(%p)\n",This);
252     return E_NOTIMPL;
253 }
254
255 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
256         REFGUID guidProp, ITfProperty **ppProp)
257 {
258     Context *This = (Context *)iface;
259     FIXME("STUB:(%p)\n",This);
260     return E_NOTIMPL;
261 }
262
263 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
264         REFGUID guidProp, ITfReadOnlyProperty **ppProp)
265 {
266     Context *This = (Context *)iface;
267     FIXME("STUB:(%p)\n",This);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
272         const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
273         ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
274 {
275     Context *This = (Context *)iface;
276     FIXME("STUB:(%p)\n",This);
277     return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
281         IEnumTfProperties **ppEnum)
282 {
283     Context *This = (Context *)iface;
284     FIXME("STUB:(%p)\n",This);
285     return E_NOTIMPL;
286 }
287
288 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
289         ITfDocumentMgr **ppDm)
290 {
291     Context *This = (Context *)iface;
292     FIXME("STUB:(%p)\n",This);
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
297         TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
298 {
299     Context *This = (Context *)iface;
300     FIXME("STUB:(%p)\n",This);
301     return E_NOTIMPL;
302 }
303
304 static const ITfContextVtbl Context_ContextVtbl =
305 {
306     Context_QueryInterface,
307     Context_AddRef,
308     Context_Release,
309
310     Context_RequestEditSession,
311     Context_InWriteSession,
312     Context_GetSelection,
313     Context_SetSelection,
314     Context_GetStart,
315     Context_GetEnd,
316     Context_GetActiveView,
317     Context_EnumViews,
318     Context_GetStatus,
319     Context_GetProperty,
320     Context_GetAppProperty,
321     Context_TrackProperties,
322     Context_EnumProperties,
323     Context_GetDocumentMgr,
324     Context_CreateRangeBackup
325 };
326
327 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
328 {
329     Context *This = impl_from_ITfSourceVtbl(iface);
330     return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
331 }
332
333 static ULONG WINAPI Source_AddRef(ITfSource *iface)
334 {
335     Context *This = impl_from_ITfSourceVtbl(iface);
336     return Context_AddRef((ITfContext *)This);
337 }
338
339 static ULONG WINAPI Source_Release(ITfSource *iface)
340 {
341     Context *This = impl_from_ITfSourceVtbl(iface);
342     return Context_Release((ITfContext *)This);
343 }
344
345 /*****************************************************
346  * ITfSource functions
347  *****************************************************/
348 static WINAPI HRESULT ContextSource_AdviseSink(ITfSource *iface,
349         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
350 {
351     ContextSink *es;
352     Context *This = impl_from_ITfSourceVtbl(iface);
353     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
354
355     if (!riid || !punk || !pdwCookie)
356         return E_INVALIDARG;
357
358     if (IsEqualIID(riid, &IID_ITfTextEditSink))
359     {
360         es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
361         if (!es)
362             return E_OUTOFMEMORY;
363         if (!SUCCEEDED(IUnknown_QueryInterface(punk, riid, (LPVOID*)&es->interfaces.pITfTextEditSink)))
364         {
365             HeapFree(GetProcessHeap(),0,es);
366             return CONNECT_E_CANNOTCONNECT;
367         }
368         list_add_head(&This->pTextEditSink ,&es->entry);
369         *pdwCookie = (DWORD)es;
370     }
371     else
372     {
373         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
374         return E_NOTIMPL;
375     }
376
377     TRACE("cookie %x\n",*pdwCookie);
378     return S_OK;
379 }
380
381 static WINAPI HRESULT ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
382 {
383     ContextSink *sink = (ContextSink*)pdwCookie;
384     Context *This = impl_from_ITfSourceVtbl(iface);
385     TRACE("(%p) %x\n",This,pdwCookie);
386
387     list_remove(&sink->entry);
388     free_sink(sink);
389
390     return S_OK;
391 }
392
393 static const ITfSourceVtbl Context_SourceVtbl =
394 {
395     Source_QueryInterface,
396     Source_AddRef,
397     Source_Release,
398
399     ContextSource_AdviseSink,
400     ContextSource_UnadviseSink,
401 };
402
403 HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **ppOut, TfEditCookie *pecTextStore)
404 {
405     Context *This;
406
407     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
408     if (This == NULL)
409         return E_OUTOFMEMORY;
410
411     This->ContextVtbl= &Context_ContextVtbl;
412     This->SourceVtbl = &Context_SourceVtbl;
413     This->refCount = 1;
414     This->tidOwner = tidOwner;
415     This->punk = punk;
416
417     TRACE("returning %p\n", This);
418     *ppOut = (ITfContext*)This;
419     /* FIXME */
420     *pecTextStore = 0xdeaddead;
421
422     list_init(&This->pContextKeyEventSink);
423     list_init(&This->pEditTransactionSink);
424     list_init(&This->pStatusSink);
425     list_init(&This->pTextEditSink);
426     list_init(&This->pTextLayoutSink);
427
428     return S_OK;
429 }
430
431 /**************************************************************************
432  *  ITextStoreACPSink
433  **************************************************************************/
434
435 static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
436 {
437     TRACE("destroying %p\n", This);
438     HeapFree(GetProcessHeap(),0,This);
439 }
440
441 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
442 {
443     TextStoreACPSink *This = (TextStoreACPSink *)iface;
444     *ppvOut = NULL;
445
446     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
447     {
448         *ppvOut = This;
449     }
450
451     if (*ppvOut)
452     {
453         IUnknown_AddRef(iface);
454         return S_OK;
455     }
456
457     WARN("unsupported interface: %s\n", debugstr_guid(iid));
458     return E_NOINTERFACE;
459 }
460
461 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
462 {
463     TextStoreACPSink *This = (TextStoreACPSink *)iface;
464     return InterlockedIncrement(&This->refCount);
465 }
466
467 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
468 {
469     TextStoreACPSink *This = (TextStoreACPSink *)iface;
470     ULONG ret;
471
472     ret = InterlockedDecrement(&This->refCount);
473     if (ret == 0)
474         TextStoreACPSink_Destructor(This);
475     return ret;
476 }
477
478 /*****************************************************
479  * ITextStoreACPSink functions
480  *****************************************************/
481
482 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
483         DWORD dwFlags, const TS_TEXTCHANGE *pChange)
484 {
485     TextStoreACPSink *This = (TextStoreACPSink *)iface;
486     FIXME("STUB:(%p)\n",This);
487     return E_NOTIMPL;
488 }
489
490 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
491 {
492     TextStoreACPSink *This = (TextStoreACPSink *)iface;
493     FIXME("STUB:(%p)\n",This);
494     return E_NOTIMPL;
495 }
496
497 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
498     TsLayoutCode lcode, TsViewCookie vcView)
499 {
500     TextStoreACPSink *This = (TextStoreACPSink *)iface;
501     FIXME("STUB:(%p)\n",This);
502     return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
506         DWORD dwFlags)
507 {
508     TextStoreACPSink *This = (TextStoreACPSink *)iface;
509     FIXME("STUB:(%p)\n",This);
510     return E_NOTIMPL;
511 }
512
513 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
514         LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
515 {
516     TextStoreACPSink *This = (TextStoreACPSink *)iface;
517     FIXME("STUB:(%p)\n",This);
518     return E_NOTIMPL;
519 }
520
521 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
522         DWORD dwLockFlags)
523 {
524     TextStoreACPSink *This = (TextStoreACPSink *)iface;
525     FIXME("STUB:(%p)\n",This);
526     return E_NOTIMPL;
527 }
528
529 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
530 {
531     TextStoreACPSink *This = (TextStoreACPSink *)iface;
532     FIXME("STUB:(%p)\n",This);
533     return E_NOTIMPL;
534 }
535
536 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
537 {
538     TextStoreACPSink *This = (TextStoreACPSink *)iface;
539     FIXME("STUB:(%p)\n",This);
540     return E_NOTIMPL;
541 }
542
543 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl =
544 {
545     TextStoreACPSink_QueryInterface,
546     TextStoreACPSink_AddRef,
547     TextStoreACPSink_Release,
548
549     TextStoreACPSink_OnTextChange,
550     TextStoreACPSink_OnSelectionChange,
551     TextStoreACPSink_OnLayoutChange,
552     TextStoreACPSink_OnStatusChange,
553     TextStoreACPSink_OnAttrsChange,
554     TextStoreACPSink_OnLockGranted,
555     TextStoreACPSink_OnStartEditTransaction,
556     TextStoreACPSink_OnEndEditTransaction
557 };
558
559 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
560 {
561     TextStoreACPSink *This;
562
563     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
564     if (This == NULL)
565         return E_OUTOFMEMORY;
566
567     This->TextStoreACPSinkVtbl= &TextStoreACPSink_TextStoreACPSinkVtbl;
568     This->refCount = 1;
569
570     This->pContext = pContext;
571
572     TRACE("returning %p\n", This);
573     *ppOut = (ITextStoreACPSink*)This;
574     return S_OK;
575 }