gdi32: Move the text metrics cache into the generic font structure.
[wine/zf.git] / dlls / msctf / compartmentmgr.c
blob4cc25f3f9ab54fc4142c243bb57ae6aa5d7c87f9
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 <stdarg.h>
23 #define COBJMACROS
25 #include "wine/debug.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "shlwapi.h"
31 #include "winerror.h"
32 #include "objbase.h"
33 #include "oleauto.h"
34 #include "olectl.h"
36 #include "msctf.h"
37 #include "msctf_internal.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
41 typedef struct tagCompartmentValue {
42 struct list entry;
43 GUID guid;
44 TfClientId owner;
45 ITfCompartment *compartment;
46 } CompartmentValue;
48 typedef struct tagCompartmentMgr {
49 ITfCompartmentMgr ITfCompartmentMgr_iface;
50 LONG refCount;
52 IUnknown *pUnkOuter;
54 struct list values;
55 } CompartmentMgr;
57 typedef struct tagCompartmentEnumGuid {
58 IEnumGUID IEnumGUID_iface;
59 LONG refCount;
61 struct list *values;
62 struct list *cursor;
63 } CompartmentEnumGuid;
65 typedef struct tagCompartment {
66 ITfCompartment ITfCompartment_iface;
67 ITfSource ITfSource_iface;
68 LONG refCount;
70 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
71 VARIANT variant;
72 CompartmentValue *valueData;
73 struct list CompartmentEventSink;
74 } Compartment;
76 static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
77 static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
79 static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface)
81 return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface);
84 static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface)
86 return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface);
89 static inline Compartment *impl_from_ITfSource(ITfSource *iface)
91 return CONTAINING_RECORD(iface, Compartment, ITfSource_iface);
94 static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface)
96 return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface);
99 HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
101 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
102 struct list *cursor, *cursor2;
104 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
106 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
107 list_remove(cursor);
108 ITfCompartment_Release(value->compartment);
109 HeapFree(GetProcessHeap(),0,value);
112 HeapFree(GetProcessHeap(),0,This);
113 return S_OK;
116 /*****************************************************
117 * ITfCompartmentMgr functions
118 *****************************************************/
119 static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
121 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
122 if (This->pUnkOuter)
123 return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut);
124 else
126 *ppvOut = NULL;
128 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
130 *ppvOut = &This->ITfCompartmentMgr_iface;
133 if (*ppvOut)
135 ITfCompartmentMgr_AddRef(iface);
136 return S_OK;
139 WARN("unsupported interface: %s\n", debugstr_guid(iid));
140 return E_NOINTERFACE;
144 static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
146 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
147 if (This->pUnkOuter)
148 return IUnknown_AddRef(This->pUnkOuter);
149 else
150 return InterlockedIncrement(&This->refCount);
153 static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
155 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
156 if (This->pUnkOuter)
157 return IUnknown_Release(This->pUnkOuter);
158 else
160 ULONG ret;
162 ret = InterlockedDecrement(&This->refCount);
163 if (ret == 0)
164 CompartmentMgr_Destructor(iface);
165 return ret;
169 static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
170 REFGUID rguid, ITfCompartment **ppcomp)
172 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
173 CompartmentValue* value;
174 struct list *cursor;
175 HRESULT hr;
177 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),ppcomp);
179 LIST_FOR_EACH(cursor, &This->values)
181 value = LIST_ENTRY(cursor,CompartmentValue,entry);
182 if (IsEqualGUID(rguid,&value->guid))
184 ITfCompartment_AddRef(value->compartment);
185 *ppcomp = value->compartment;
186 return S_OK;
190 value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
191 value->guid = *rguid;
192 value->owner = 0;
193 hr = Compartment_Constructor(value,&value->compartment);
194 if (SUCCEEDED(hr))
196 list_add_head(&This->values,&value->entry);
197 ITfCompartment_AddRef(value->compartment);
198 *ppcomp = value->compartment;
200 else
202 HeapFree(GetProcessHeap(),0,value);
203 *ppcomp = NULL;
205 return hr;
208 static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
209 TfClientId tid, REFGUID rguid)
211 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
212 struct list *cursor;
214 TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));
216 LIST_FOR_EACH(cursor, &This->values)
218 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
219 if (IsEqualGUID(rguid,&value->guid))
221 if (value->owner && tid != value->owner)
222 return E_UNEXPECTED;
223 list_remove(cursor);
224 ITfCompartment_Release(value->compartment);
225 HeapFree(GetProcessHeap(),0,value);
226 return S_OK;
230 return CONNECT_E_NOCONNECTION;
233 static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
234 IEnumGUID **ppEnum)
236 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
238 TRACE("(%p) %p\n",This,ppEnum);
239 if (!ppEnum)
240 return E_INVALIDARG;
241 return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
244 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl =
246 CompartmentMgr_QueryInterface,
247 CompartmentMgr_AddRef,
248 CompartmentMgr_Release,
249 CompartmentMgr_GetCompartment,
250 CompartmentMgr_ClearCompartment,
251 CompartmentMgr_EnumCompartments
254 HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
256 CompartmentMgr *This;
258 if (!ppOut)
259 return E_POINTER;
261 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
262 return CLASS_E_NOAGGREGATION;
264 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
265 if (This == NULL)
266 return E_OUTOFMEMORY;
268 This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl;
269 This->pUnkOuter = pUnkOuter;
270 list_init(&This->values);
272 if (pUnkOuter)
274 *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface;
275 TRACE("returning %p\n", *ppOut);
276 return S_OK;
278 else
280 HRESULT hr;
281 hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut);
282 if (FAILED(hr))
283 HeapFree(GetProcessHeap(),0,This);
284 return hr;
288 /**************************************************
289 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
290 **************************************************/
291 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
293 TRACE("destroying %p\n", This);
294 HeapFree(GetProcessHeap(),0,This);
297 static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
299 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
300 *ppvOut = NULL;
302 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
304 *ppvOut = &This->IEnumGUID_iface;
307 if (*ppvOut)
309 IEnumGUID_AddRef(iface);
310 return S_OK;
313 WARN("unsupported interface: %s\n", debugstr_guid(iid));
314 return E_NOINTERFACE;
317 static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
319 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
320 return InterlockedIncrement(&This->refCount);
323 static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
325 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
326 ULONG ret;
328 ret = InterlockedDecrement(&This->refCount);
329 if (ret == 0)
330 CompartmentEnumGuid_Destructor(This);
331 return ret;
334 /*****************************************************
335 * IEnumGuid functions
336 *****************************************************/
337 static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface,
338 ULONG celt, GUID *rgelt, ULONG *pceltFetched)
340 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
341 ULONG fetched = 0;
343 TRACE("(%p)\n",This);
345 if (rgelt == NULL) return E_POINTER;
347 while (fetched < celt && This->cursor)
349 CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
350 if (!value)
351 break;
353 This->cursor = list_next(This->values,This->cursor);
354 *rgelt = value->guid;
356 ++fetched;
357 ++rgelt;
360 if (pceltFetched) *pceltFetched = fetched;
361 return fetched == celt ? S_OK : S_FALSE;
364 static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt)
366 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
367 TRACE("(%p)\n",This);
369 This->cursor = list_next(This->values,This->cursor);
370 return S_OK;
373 static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface)
375 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
376 TRACE("(%p)\n",This);
377 This->cursor = list_head(This->values);
378 return S_OK;
381 static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface,
382 IEnumGUID **ppenum)
384 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
385 HRESULT res;
387 TRACE("(%p)\n",This);
389 if (ppenum == NULL) return E_POINTER;
391 res = CompartmentEnumGuid_Constructor(This->values, ppenum);
392 if (SUCCEEDED(res))
394 CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum);
395 new_This->cursor = This->cursor;
397 return res;
400 static const IEnumGUIDVtbl EnumGUIDVtbl =
402 CompartmentEnumGuid_QueryInterface,
403 CompartmentEnumGuid_AddRef,
404 CompartmentEnumGuid_Release,
405 CompartmentEnumGuid_Next,
406 CompartmentEnumGuid_Skip,
407 CompartmentEnumGuid_Reset,
408 CompartmentEnumGuid_Clone
411 static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
413 CompartmentEnumGuid *This;
415 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
416 if (This == NULL)
417 return E_OUTOFMEMORY;
419 This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl;
420 This->refCount = 1;
422 This->values = values;
423 This->cursor = list_head(values);
425 *ppOut = &This->IEnumGUID_iface;
426 TRACE("returning %p\n", *ppOut);
427 return S_OK;
430 /**************************************************
431 * ITfCompartment
432 **************************************************/
433 static void Compartment_Destructor(Compartment *This)
435 TRACE("destroying %p\n", This);
436 VariantClear(&This->variant);
437 free_sinks(&This->CompartmentEventSink);
438 HeapFree(GetProcessHeap(),0,This);
441 static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
443 Compartment *This = impl_from_ITfCompartment(iface);
445 *ppvOut = NULL;
447 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
449 *ppvOut = &This->ITfCompartment_iface;
451 else if (IsEqualIID(iid, &IID_ITfSource))
453 *ppvOut = &This->ITfSource_iface;
456 if (*ppvOut)
458 ITfCompartment_AddRef(iface);
459 return S_OK;
462 WARN("unsupported interface: %s\n", debugstr_guid(iid));
463 return E_NOINTERFACE;
466 static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
468 Compartment *This = impl_from_ITfCompartment(iface);
469 return InterlockedIncrement(&This->refCount);
472 static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
474 Compartment *This = impl_from_ITfCompartment(iface);
475 ULONG ret;
477 ret = InterlockedDecrement(&This->refCount);
478 if (ret == 0)
479 Compartment_Destructor(This);
480 return ret;
483 static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
484 TfClientId tid, const VARIANT *pvarValue)
486 Compartment *This = impl_from_ITfCompartment(iface);
487 ITfCompartmentEventSink *sink;
488 struct list *cursor;
490 TRACE("(%p) %i %p\n",This,tid,pvarValue);
492 if (!pvarValue)
493 return E_INVALIDARG;
495 if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
496 V_VT(pvarValue) == VT_UNKNOWN))
497 return E_INVALIDARG;
499 if (!This->valueData->owner)
500 This->valueData->owner = tid;
502 VariantClear(&This->variant);
504 /* Shallow copy of value and type */
505 This->variant = *pvarValue;
507 if (V_VT(pvarValue) == VT_BSTR)
508 V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
509 SysStringByteLen(V_BSTR(pvarValue)));
510 else if (V_VT(pvarValue) == VT_UNKNOWN)
511 IUnknown_AddRef(V_UNKNOWN(&This->variant));
513 SINK_FOR_EACH(cursor, &This->CompartmentEventSink, ITfCompartmentEventSink, sink)
515 ITfCompartmentEventSink_OnChange(sink, &This->valueData->guid);
518 return S_OK;
521 static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
522 VARIANT *pvarValue)
524 Compartment *This = impl_from_ITfCompartment(iface);
525 TRACE("(%p) %p\n",This, pvarValue);
527 if (!pvarValue)
528 return E_INVALIDARG;
530 VariantInit(pvarValue);
531 if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
532 return VariantCopy(pvarValue,&This->variant);
535 static const ITfCompartmentVtbl CompartmentVtbl =
537 Compartment_QueryInterface,
538 Compartment_AddRef,
539 Compartment_Release,
540 Compartment_SetValue,
541 Compartment_GetValue
544 /*****************************************************
545 * ITfSource functions
546 *****************************************************/
548 static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
550 Compartment *This = impl_from_ITfSource(iface);
551 return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut);
554 static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface)
556 Compartment *This = impl_from_ITfSource(iface);
557 return ITfCompartment_AddRef(&This->ITfCompartment_iface);
560 static ULONG WINAPI CompartmentSource_Release(ITfSource *iface)
562 Compartment *This = impl_from_ITfSource(iface);
563 return ITfCompartment_Release(&This->ITfCompartment_iface);
566 static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface,
567 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
569 Compartment *This = impl_from_ITfSource(iface);
571 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
573 if (!riid || !punk || !pdwCookie)
574 return E_INVALIDARG;
576 if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
577 return advise_sink(&This->CompartmentEventSink, &IID_ITfCompartmentEventSink,
578 COOKIE_MAGIC_COMPARTMENTSINK, punk, pdwCookie);
580 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
581 return E_NOTIMPL;
584 static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
586 Compartment *This = impl_from_ITfSource(iface);
588 TRACE("(%p) %x\n",This,pdwCookie);
590 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
591 return E_INVALIDARG;
593 return unadvise_sink(pdwCookie);
596 static const ITfSourceVtbl CompartmentSourceVtbl =
598 CompartmentSource_QueryInterface,
599 CompartmentSource_AddRef,
600 CompartmentSource_Release,
601 CompartmentSource_AdviseSink,
602 CompartmentSource_UnadviseSink,
605 static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
607 Compartment *This;
609 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
610 if (This == NULL)
611 return E_OUTOFMEMORY;
613 This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl;
614 This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl;
615 This->refCount = 1;
617 This->valueData = valueData;
618 VariantInit(&This->variant);
620 list_init(&This->CompartmentEventSink);
622 *ppOut = &This->ITfCompartment_iface;
623 TRACE("returning %p\n", *ppOut);
624 return S_OK;