wordpad: Add a dropdown menu to the bullet button.
[wine.git] / dlls / msctf / compartmentmgr.c
blob4fe7b82f94f8f4757b4afe683eb3c6cd994a0759
1 /*
2 * ITfCompartmentMgr implementation
4 * Copyright 2009 Aric Stewart, CodeWeavers
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.
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.
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
21 #include "config.h"
23 #include <stdarg.h>
25 #define COBJMACROS
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 "oleauto.h"
36 #include "olectl.h"
38 #include "wine/unicode.h"
40 #include "msctf.h"
41 #include "msctf_internal.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
45 typedef struct tagCompartmentValue {
46 struct list entry;
47 GUID guid;
48 TfClientId owner;
49 ITfCompartment *compartment;
50 } CompartmentValue;
52 typedef struct tagCompartmentMgr {
53 ITfCompartmentMgr ITfCompartmentMgr_iface;
54 LONG refCount;
56 IUnknown *pUnkOuter;
58 struct list values;
59 } CompartmentMgr;
61 typedef struct tagCompartmentEnumGuid {
62 IEnumGUID IEnumGUID_iface;
63 LONG refCount;
65 struct list *values;
66 struct list *cursor;
67 } CompartmentEnumGuid;
69 typedef struct tagCompartment {
70 ITfCompartment ITfCompartment_iface;
71 ITfSource ITfSource_iface;
72 LONG refCount;
74 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
75 VARIANT variant;
76 CompartmentValue *valueData;
77 struct list CompartmentEventSink;
78 } Compartment;
80 static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
81 static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
83 static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface)
85 return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface);
88 static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface)
90 return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface);
93 static inline Compartment *impl_from_ITfSource(ITfSource *iface)
95 return CONTAINING_RECORD(iface, Compartment, ITfSource_iface);
98 static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface)
100 return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface);
103 HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
105 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
106 struct list *cursor, *cursor2;
108 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
110 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
111 list_remove(cursor);
112 ITfCompartment_Release(value->compartment);
113 HeapFree(GetProcessHeap(),0,value);
116 HeapFree(GetProcessHeap(),0,This);
117 return S_OK;
120 /*****************************************************
121 * ITfCompartmentMgr functions
122 *****************************************************/
123 static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
125 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
126 if (This->pUnkOuter)
127 return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut);
128 else
130 *ppvOut = NULL;
132 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
134 *ppvOut = &This->ITfCompartmentMgr_iface;
137 if (*ppvOut)
139 ITfCompartmentMgr_AddRef(iface);
140 return S_OK;
143 WARN("unsupported interface: %s\n", debugstr_guid(iid));
144 return E_NOINTERFACE;
148 static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
150 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
151 if (This->pUnkOuter)
152 return IUnknown_AddRef(This->pUnkOuter);
153 else
154 return InterlockedIncrement(&This->refCount);
157 static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
159 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
160 if (This->pUnkOuter)
161 return IUnknown_Release(This->pUnkOuter);
162 else
164 ULONG ret;
166 ret = InterlockedDecrement(&This->refCount);
167 if (ret == 0)
168 CompartmentMgr_Destructor(iface);
169 return ret;
173 static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
174 REFGUID rguid, ITfCompartment **ppcomp)
176 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
177 CompartmentValue* value;
178 struct list *cursor;
179 HRESULT hr;
181 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),ppcomp);
183 LIST_FOR_EACH(cursor, &This->values)
185 value = LIST_ENTRY(cursor,CompartmentValue,entry);
186 if (IsEqualGUID(rguid,&value->guid))
188 ITfCompartment_AddRef(value->compartment);
189 *ppcomp = value->compartment;
190 return S_OK;
194 value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
195 value->guid = *rguid;
196 value->owner = 0;
197 hr = Compartment_Constructor(value,&value->compartment);
198 if (SUCCEEDED(hr))
200 list_add_head(&This->values,&value->entry);
201 ITfCompartment_AddRef(value->compartment);
202 *ppcomp = value->compartment;
204 else
206 HeapFree(GetProcessHeap(),0,value);
207 *ppcomp = NULL;
209 return hr;
212 static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
213 TfClientId tid, REFGUID rguid)
215 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
216 struct list *cursor;
218 TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));
220 LIST_FOR_EACH(cursor, &This->values)
222 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
223 if (IsEqualGUID(rguid,&value->guid))
225 if (value->owner && tid != value->owner)
226 return E_UNEXPECTED;
227 list_remove(cursor);
228 ITfCompartment_Release(value->compartment);
229 HeapFree(GetProcessHeap(),0,value);
230 return S_OK;
234 return CONNECT_E_NOCONNECTION;
237 static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
238 IEnumGUID **ppEnum)
240 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
242 TRACE("(%p) %p\n",This,ppEnum);
243 if (!ppEnum)
244 return E_INVALIDARG;
245 return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
248 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl =
250 CompartmentMgr_QueryInterface,
251 CompartmentMgr_AddRef,
252 CompartmentMgr_Release,
253 CompartmentMgr_GetCompartment,
254 CompartmentMgr_ClearCompartment,
255 CompartmentMgr_EnumCompartments
258 HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
260 CompartmentMgr *This;
262 if (!ppOut)
263 return E_POINTER;
265 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
266 return CLASS_E_NOAGGREGATION;
268 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
269 if (This == NULL)
270 return E_OUTOFMEMORY;
272 This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl;
273 This->pUnkOuter = pUnkOuter;
274 list_init(&This->values);
276 if (pUnkOuter)
278 *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface;
279 TRACE("returning %p\n", *ppOut);
280 return S_OK;
282 else
284 HRESULT hr;
285 hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut);
286 if (FAILED(hr))
287 HeapFree(GetProcessHeap(),0,This);
288 return hr;
292 /**************************************************
293 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
294 **************************************************/
295 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
297 TRACE("destroying %p\n", This);
298 HeapFree(GetProcessHeap(),0,This);
301 static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
303 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
304 *ppvOut = NULL;
306 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
308 *ppvOut = &This->IEnumGUID_iface;
311 if (*ppvOut)
313 IEnumGUID_AddRef(iface);
314 return S_OK;
317 WARN("unsupported interface: %s\n", debugstr_guid(iid));
318 return E_NOINTERFACE;
321 static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
323 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
324 return InterlockedIncrement(&This->refCount);
327 static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
329 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
330 ULONG ret;
332 ret = InterlockedDecrement(&This->refCount);
333 if (ret == 0)
334 CompartmentEnumGuid_Destructor(This);
335 return ret;
338 /*****************************************************
339 * IEnumGuid functions
340 *****************************************************/
341 static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface,
342 ULONG celt, GUID *rgelt, ULONG *pceltFetched)
344 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
345 ULONG fetched = 0;
347 TRACE("(%p)\n",This);
349 if (rgelt == NULL) return E_POINTER;
351 while (fetched < celt && This->cursor)
353 CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
354 if (!value)
355 break;
357 This->cursor = list_next(This->values,This->cursor);
358 *rgelt = value->guid;
360 ++fetched;
361 ++rgelt;
364 if (pceltFetched) *pceltFetched = fetched;
365 return fetched == celt ? S_OK : S_FALSE;
368 static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt)
370 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
371 TRACE("(%p)\n",This);
373 This->cursor = list_next(This->values,This->cursor);
374 return S_OK;
377 static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface)
379 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
380 TRACE("(%p)\n",This);
381 This->cursor = list_head(This->values);
382 return S_OK;
385 static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface,
386 IEnumGUID **ppenum)
388 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
389 HRESULT res;
391 TRACE("(%p)\n",This);
393 if (ppenum == NULL) return E_POINTER;
395 res = CompartmentEnumGuid_Constructor(This->values, ppenum);
396 if (SUCCEEDED(res))
398 CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum);
399 new_This->cursor = This->cursor;
401 return res;
404 static const IEnumGUIDVtbl EnumGUIDVtbl =
406 CompartmentEnumGuid_QueryInterface,
407 CompartmentEnumGuid_AddRef,
408 CompartmentEnumGuid_Release,
409 CompartmentEnumGuid_Next,
410 CompartmentEnumGuid_Skip,
411 CompartmentEnumGuid_Reset,
412 CompartmentEnumGuid_Clone
415 static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
417 CompartmentEnumGuid *This;
419 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
420 if (This == NULL)
421 return E_OUTOFMEMORY;
423 This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl;
424 This->refCount = 1;
426 This->values = values;
427 This->cursor = list_head(values);
429 *ppOut = &This->IEnumGUID_iface;
430 TRACE("returning %p\n", *ppOut);
431 return S_OK;
434 /**************************************************
435 * ITfCompartment
436 **************************************************/
437 static void Compartment_Destructor(Compartment *This)
439 TRACE("destroying %p\n", This);
440 VariantClear(&This->variant);
441 free_sinks(&This->CompartmentEventSink);
442 HeapFree(GetProcessHeap(),0,This);
445 static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
447 Compartment *This = impl_from_ITfCompartment(iface);
449 *ppvOut = NULL;
451 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
453 *ppvOut = &This->ITfCompartment_iface;
455 else if (IsEqualIID(iid, &IID_ITfSource))
457 *ppvOut = &This->ITfSource_iface;
460 if (*ppvOut)
462 ITfCompartment_AddRef(iface);
463 return S_OK;
466 WARN("unsupported interface: %s\n", debugstr_guid(iid));
467 return E_NOINTERFACE;
470 static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
472 Compartment *This = impl_from_ITfCompartment(iface);
473 return InterlockedIncrement(&This->refCount);
476 static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
478 Compartment *This = impl_from_ITfCompartment(iface);
479 ULONG ret;
481 ret = InterlockedDecrement(&This->refCount);
482 if (ret == 0)
483 Compartment_Destructor(This);
484 return ret;
487 static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
488 TfClientId tid, const VARIANT *pvarValue)
490 Compartment *This = impl_from_ITfCompartment(iface);
491 ITfCompartmentEventSink *sink;
492 struct list *cursor;
494 TRACE("(%p) %i %p\n",This,tid,pvarValue);
496 if (!pvarValue)
497 return E_INVALIDARG;
499 if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
500 V_VT(pvarValue) == VT_UNKNOWN))
501 return E_INVALIDARG;
503 if (!This->valueData->owner)
504 This->valueData->owner = tid;
506 VariantClear(&This->variant);
508 /* Shallow copy of value and type */
509 This->variant = *pvarValue;
511 if (V_VT(pvarValue) == VT_BSTR)
512 V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
513 SysStringByteLen(V_BSTR(pvarValue)));
514 else if (V_VT(pvarValue) == VT_UNKNOWN)
515 IUnknown_AddRef(V_UNKNOWN(&This->variant));
517 SINK_FOR_EACH(cursor, &This->CompartmentEventSink, ITfCompartmentEventSink, sink)
519 ITfCompartmentEventSink_OnChange(sink, &This->valueData->guid);
522 return S_OK;
525 static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
526 VARIANT *pvarValue)
528 Compartment *This = impl_from_ITfCompartment(iface);
529 TRACE("(%p) %p\n",This, pvarValue);
531 if (!pvarValue)
532 return E_INVALIDARG;
534 VariantInit(pvarValue);
535 if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
536 return VariantCopy(pvarValue,&This->variant);
539 static const ITfCompartmentVtbl CompartmentVtbl =
541 Compartment_QueryInterface,
542 Compartment_AddRef,
543 Compartment_Release,
544 Compartment_SetValue,
545 Compartment_GetValue
548 /*****************************************************
549 * ITfSource functions
550 *****************************************************/
552 static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
554 Compartment *This = impl_from_ITfSource(iface);
555 return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut);
558 static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface)
560 Compartment *This = impl_from_ITfSource(iface);
561 return ITfCompartment_AddRef(&This->ITfCompartment_iface);
564 static ULONG WINAPI CompartmentSource_Release(ITfSource *iface)
566 Compartment *This = impl_from_ITfSource(iface);
567 return ITfCompartment_Release(&This->ITfCompartment_iface);
570 static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface,
571 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
573 Compartment *This = impl_from_ITfSource(iface);
575 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
577 if (!riid || !punk || !pdwCookie)
578 return E_INVALIDARG;
580 if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
581 return advise_sink(&This->CompartmentEventSink, &IID_ITfCompartmentEventSink,
582 COOKIE_MAGIC_COMPARTMENTSINK, punk, pdwCookie);
584 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
585 return E_NOTIMPL;
588 static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
590 Compartment *This = impl_from_ITfSource(iface);
592 TRACE("(%p) %x\n",This,pdwCookie);
594 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
595 return E_INVALIDARG;
597 return unadvise_sink(pdwCookie);
600 static const ITfSourceVtbl CompartmentSourceVtbl =
602 CompartmentSource_QueryInterface,
603 CompartmentSource_AddRef,
604 CompartmentSource_Release,
605 CompartmentSource_AdviseSink,
606 CompartmentSource_UnadviseSink,
609 static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
611 Compartment *This;
613 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
614 if (This == NULL)
615 return E_OUTOFMEMORY;
617 This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl;
618 This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl;
619 This->refCount = 1;
621 This->valueData = valueData;
622 VariantInit(&This->variant);
624 list_init(&This->CompartmentEventSink);
626 *ppOut = &This->ITfCompartment_iface;
627 TRACE("returning %p\n", *ppOut);
628 return S_OK;