context.c 33.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 *  ITfContext implementation
 *
 *  Copyright 2009 Aric Stewart, CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#define COBJMACROS

#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winuser.h"
#include "shlwapi.h"
#include "winerror.h"
#include "objbase.h"
33
#include "olectl.h"
34 35 36 37 38 39 40

#include "msctf.h"
#include "msctf_internal.h"

WINE_DEFAULT_DEBUG_CHANNEL(msctf);

typedef struct tagContext {
41 42
    ITfContext ITfContext_iface;
    ITfSource ITfSource_iface;
43
    /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
44
    ITfContextOwnerCompositionServices ITfContextOwnerCompositionServices_iface;
45
    /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
46
    ITfInsertAtSelection ITfInsertAtSelection_iface;
47 48
    /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
    /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
49
    ITfSourceSingle ITfSourceSingle_iface;
50
    ITextStoreACPSink ITextStoreACPSink_iface;
51
    ITextStoreACPServices ITextStoreACPServices_iface;
52
    LONG refCount;
53
    BOOL connected;
54

55 56 57
    /* Aggregation */
    ITfCompartmentMgr  *CompartmentMgr;

58
    TfClientId tidOwner;
59
    TfEditCookie defaultCookie;
60
    TS_STATUS documentStatus;
61
    ITfDocumentMgr *manager;
62 63

    ITextStoreACP   *pITextStoreACP;
64
    ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
65

66
    ITfEditSession* currentEditSession;
67

68
    /* kept as separate lists to reduce unnecessary iterations */
69 70 71 72 73 74
    struct list     pContextKeyEventSink;
    struct list     pEditTransactionSink;
    struct list     pStatusSink;
    struct list     pTextEditSink;
    struct list     pTextLayoutSink;

75 76
} Context;

77 78 79 80
typedef struct tagEditCookie {
    DWORD lockType;
    Context *pOwningContext;
} EditCookie;
81

82
static inline Context *impl_from_ITfContext(ITfContext *iface)
83
{
84
    return CONTAINING_RECORD(iface, Context, ITfContext_iface);
85 86
}

87
static inline Context *impl_from_ITfSource(ITfSource *iface)
88
{
89
    return CONTAINING_RECORD(iface, Context, ITfSource_iface);
90 91
}

92 93 94 95 96
static inline Context *impl_from_ITfContextOwnerCompositionServices(ITfContextOwnerCompositionServices *iface)
{
    return CONTAINING_RECORD(iface, Context, ITfContextOwnerCompositionServices_iface);
}

97
static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface)
98
{
99 100 101 102 103 104 105 106
    return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface);
}

static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface)
{
    return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface);
}

107
static inline Context *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
108
{
109
    return CONTAINING_RECORD(iface, Context, ITextStoreACPSink_iface);
110 111
}

112 113 114 115 116
static inline Context *impl_from_ITextStoreACPServices(ITextStoreACPServices *iface)
{
    return CONTAINING_RECORD(iface, Context, ITextStoreACPServices_iface);
}

117 118
static void Context_Destructor(Context *This)
{
119
    EditCookie *cookie;
120
    TRACE("destroying %p\n", This);
121

122
    if (This->pITextStoreACP)
123
        ITextStoreACP_Release(This->pITextStoreACP);
124

125
    if (This->pITfContextOwnerCompositionSink)
126
        ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink);
127

128 129 130 131 132 133 134
    if (This->defaultCookie)
    {
        cookie = remove_Cookie(This->defaultCookie);
        HeapFree(GetProcessHeap(),0,cookie);
        This->defaultCookie = 0;
    }

135 136 137 138 139
    free_sinks(&This->pContextKeyEventSink);
    free_sinks(&This->pEditTransactionSink);
    free_sinks(&This->pStatusSink);
    free_sinks(&This->pTextEditSink);
    free_sinks(&This->pTextLayoutSink);
140

141
    CompartmentMgr_Destructor(This->CompartmentMgr);
142 143 144 145 146
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
{
147
    Context *This = impl_from_ITfContext(iface);
148 149 150 151
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
    {
152
        *ppvOut = &This->ITfContext_iface;
153
    }
154 155
    else if (IsEqualIID(iid, &IID_ITfSource))
    {
156
        *ppvOut = &This->ITfSource_iface;
157
    }
158 159 160 161
    else if (IsEqualIID(iid, &IID_ITfContextOwnerCompositionServices))
    {
        *ppvOut = &This->ITfContextOwnerCompositionServices_iface;
    }
162 163
    else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
    {
164
        *ppvOut = &This->ITfInsertAtSelection_iface;
165
    }
166 167 168 169
    else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
    {
        *ppvOut = This->CompartmentMgr;
    }
170 171
    else if (IsEqualIID(iid, &IID_ITfSourceSingle))
    {
172
        *ppvOut = &This->ITfSourceSingle_iface;
173
    }
174 175 176

    if (*ppvOut)
    {
177
        ITfContext_AddRef(iface);
178 179 180 181 182 183 184 185 186
        return S_OK;
    }

    WARN("unsupported interface: %s\n", debugstr_guid(iid));
    return E_NOINTERFACE;
}

static ULONG WINAPI Context_AddRef(ITfContext *iface)
{
187
    Context *This = impl_from_ITfContext(iface);
188 189 190 191 192
    return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI Context_Release(ITfContext *iface)
{
193
    Context *This = impl_from_ITfContext(iface);
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
    ULONG ret;

    ret = InterlockedDecrement(&This->refCount);
    if (ret == 0)
        Context_Destructor(This);
    return ret;
}

/*****************************************************
 * ITfContext functions
 *****************************************************/
static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
        TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
        HRESULT *phrSession)
{
209
    Context *This = impl_from_ITfContext(iface);
210 211 212 213 214 215 216 217 218 219 220 221 222
    HRESULT hr;
    DWORD  dwLockFlags = 0x0;

    TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);

    if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE))
    {
        *phrSession = E_FAIL;
        return E_INVALIDARG;
    }

    if (!This->pITextStoreACP)
    {
223
        FIXME("No ITextStoreACP available\n");
224 225 226 227 228
        *phrSession = E_FAIL;
        return E_FAIL;
    }

    if (!(dwFlags & TF_ES_ASYNC))
229
        dwLockFlags |= TS_LF_SYNC;
230

231
    if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
232
        dwLockFlags |= TS_LF_READWRITE;
233 234
    else if (dwFlags & TF_ES_READ)
        dwLockFlags |= TS_LF_READ;
235

236 237
    if (!This->documentStatus.dwDynamicFlags)
        ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
238

239
    if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY))
240 241 242 243 244 245 246 247 248 249 250 251 252 253
    {
        *phrSession = TS_E_READONLY;
        return S_OK;
    }

    if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession)))
    {
        *phrSession = E_FAIL;
        return E_INVALIDARG;
    }

    hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession);

    return hr;
254 255 256 257 258 259
}

static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
         TfClientId tid,
         BOOL *pfWriteSession)
{
260
    Context *This = impl_from_ITfContext(iface);
261 262 263 264 265 266 267 268
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
        TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
        TF_SELECTION *pSelection, ULONG *pcFetched)
{
269
    Context *This = impl_from_ITfContext(iface);
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    ULONG count, i;
    ULONG totalFetched = 0;
    HRESULT hr = S_OK;

    if (!pSelection || !pcFetched)
        return E_INVALIDARG;

    *pcFetched = 0;

    if (!This->connected)
        return TF_E_DISCONNECTED;

    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
        return TF_E_NOLOCK;

    if (!This->pITextStoreACP)
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

    if (ulIndex == TF_DEFAULT_SELECTION)
        count = 1;
    else
        count = ulCount;

    for (i = 0; i < count; i++)
    {
        DWORD fetched;
        TS_SELECTION_ACP acps;

        hr = ITextStoreACP_GetSelection(This->pITextStoreACP, ulIndex + i,
                1, &acps, &fetched);

        if (hr == TS_E_NOLOCK)
            return TF_E_NOLOCK;
        else if (SUCCEEDED(hr))
        {
            pSelection[totalFetched].style.ase = acps.style.ase;
            pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar;
310
            Range_Constructor(iface, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range);
311 312 313 314 315 316 317 318 319
            totalFetched ++;
        }
        else
            break;
    }

    *pcFetched = totalFetched;

    return hr;
320 321 322 323 324
}

static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
        TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
{
325
    Context *This = impl_from_ITfContext(iface);
326
    TS_SELECTION_ACP *acp;
327
    ULONG i;
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    HRESULT hr;

    TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection);

    if (!This->pITextStoreACP)
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
        return TF_E_NOLOCK;

    acp = HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount);
    if (!acp)
        return E_OUTOFMEMORY;

    for (i = 0; i < ulCount; i++)
        if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i])))
        {
            TRACE("Selection Conversion Failed\n");
            HeapFree(GetProcessHeap(), 0 , acp);
            return E_FAIL;
        }

    hr = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp);

    HeapFree(GetProcessHeap(), 0, acp);

    return hr;
358 359 360 361 362
}

static HRESULT WINAPI Context_GetStart (ITfContext *iface,
        TfEditCookie ec, ITfRange **ppStart)
{
363
    Context *This = impl_from_ITfContext(iface);
364

365 366 367 368 369 370 371 372 373 374 375 376 377
    TRACE("(%p) %i %p\n",This,ec,ppStart);

    if (!ppStart)
        return E_INVALIDARG;

    *ppStart = NULL;

    if (!This->connected)
        return TF_E_DISCONNECTED;

    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
        return TF_E_NOLOCK;

378
    return Range_Constructor(iface, 0, 0, ppStart);
379 380 381 382 383
}

static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
        TfEditCookie ec, ITfRange **ppEnd)
{
384
    Context *This = impl_from_ITfContext(iface);
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    LONG end;
    TRACE("(%p) %i %p\n",This,ec,ppEnd);

    if (!ppEnd)
        return E_INVALIDARG;

    *ppEnd = NULL;

    if (!This->connected)
        return TF_E_DISCONNECTED;

    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
        return TF_E_NOLOCK;

    if (!This->pITextStoreACP)
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

    ITextStoreACP_GetEndACP(This->pITextStoreACP,&end);

407
    return Range_Constructor(iface, end, end, ppEnd);
408 409 410 411 412
}

static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
  ITfContextView **ppView)
{
413
    Context *This = impl_from_ITfContext(iface);
414 415 416 417 418 419 420
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
        IEnumTfContextViews **ppEnum)
{
421
    Context *This = impl_from_ITfContext(iface);
422 423 424 425 426 427 428
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
        TF_STATUS *pdcs)
{
429
    Context *This = impl_from_ITfContext(iface);
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    TRACE("(%p) %p\n",This,pdcs);

    if (!This->connected)
        return TF_E_DISCONNECTED;

    if (!pdcs)
        return E_INVALIDARG;

    if (!This->pITextStoreACP)
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

    ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);

    *pdcs = This->documentStatus;

    return S_OK;
449 450 451 452 453
}

static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
        REFGUID guidProp, ITfProperty **ppProp)
{
454
    Context *This = impl_from_ITfContext(iface);
455 456 457 458 459 460 461
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
        REFGUID guidProp, ITfReadOnlyProperty **ppProp)
{
462
    Context *This = impl_from_ITfContext(iface);
463 464 465 466 467 468 469 470
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
        const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
        ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
{
471
    Context *This = impl_from_ITfContext(iface);
472 473 474 475 476 477 478
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
        IEnumTfProperties **ppEnum)
{
479
    Context *This = impl_from_ITfContext(iface);
480 481 482 483 484 485 486
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
        ITfDocumentMgr **ppDm)
{
487
    Context *This = impl_from_ITfContext(iface);
488 489 490 491 492 493 494 495
    TRACE("(%p) %p\n",This,ppDm);

    if (!ppDm)
        return E_INVALIDARG;

    *ppDm = This->manager;
    if (!This->manager)
        return S_FALSE;
496 497 498

    ITfDocumentMgr_AddRef(This->manager);

499
    return S_OK;
500 501 502 503 504
}

static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
        TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
{
505
    Context *This = impl_from_ITfContext(iface);
506 507 508 509
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

510
static const ITfContextVtbl ContextVtbl =
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
{
    Context_QueryInterface,
    Context_AddRef,
    Context_Release,
    Context_RequestEditSession,
    Context_InWriteSession,
    Context_GetSelection,
    Context_SetSelection,
    Context_GetStart,
    Context_GetEnd,
    Context_GetActiveView,
    Context_EnumViews,
    Context_GetStatus,
    Context_GetProperty,
    Context_GetAppProperty,
    Context_TrackProperties,
    Context_EnumProperties,
    Context_GetDocumentMgr,
    Context_CreateRangeBackup
};

532 533 534
/*****************************************************
 * ITfSource functions
 *****************************************************/
535
static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
536
{
537
    Context *This = impl_from_ITfSource(iface);
538
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
539 540
}

541
static ULONG WINAPI ContextSource_AddRef(ITfSource *iface)
542
{
543 544
    Context *This = impl_from_ITfSource(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
545 546
}

547
static ULONG WINAPI ContextSource_Release(ITfSource *iface)
548
{
549 550
    Context *This = impl_from_ITfSource(iface);
    return ITfContext_Release(&This->ITfContext_iface);
551 552
}

553
static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface,
554 555
        REFIID riid, IUnknown *punk, DWORD *pdwCookie)
{
556
    Context *This = impl_from_ITfSource(iface);
557

558 559 560 561 562 563
    TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);

    if (!riid || !punk || !pdwCookie)
        return E_INVALIDARG;

    if (IsEqualIID(riid, &IID_ITfTextEditSink))
564
        return advise_sink(&This->pTextEditSink, &IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie);
565

566 567
    FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
    return E_NOTIMPL;
568 569
}

570
static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
571
{
572
    Context *This = impl_from_ITfSource(iface);
573

574 575
    TRACE("(%p) %x\n",This,pdwCookie);

576 577 578
    if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
        return E_INVALIDARG;

579
    return unadvise_sink(pdwCookie);
580 581
}

582
static const ITfSourceVtbl ContextSourceVtbl =
583
{
584 585 586
    ContextSource_QueryInterface,
    ContextSource_AddRef,
    ContextSource_Release,
587
    ContextSource_AdviseSink,
588
    ContextSource_UnadviseSink
589 590
};

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
/*****************************************************
 * ITfContextOwnerCompositionServices functions
 *****************************************************/
static HRESULT WINAPI ContextOwnerCompositionServices_QueryInterface(ITfContextOwnerCompositionServices *iface,
        REFIID iid, LPVOID *ppvOut)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
}

static ULONG WINAPI ContextOwnerCompositionServices_AddRef(ITfContextOwnerCompositionServices *iface)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
}

static ULONG WINAPI ContextOwnerCompositionServices_Release(ITfContextOwnerCompositionServices *iface)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    return ITfContext_Release(&This->ITfContext_iface);
}

static HRESULT WINAPI ContextOwnerCompositionServices_StartComposition(ITfContextOwnerCompositionServices *iface,
        TfEditCookie ecWrite, ITfRange *pCompositionRange, ITfCompositionSink *pSink, ITfComposition **ppComposition)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    FIXME("STUB:(%p) %#x %p %p %p\n", This, ecWrite, pCompositionRange, pSink, ppComposition);
    return E_NOTIMPL;
}

static HRESULT WINAPI ContextOwnerCompositionServices_EnumCompositions(ITfContextOwnerCompositionServices *iface,
        IEnumITfCompositionView **ppEnum)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    FIXME("STUB:(%p) %p\n", This, ppEnum);
    return E_NOTIMPL;
}

static HRESULT WINAPI ContextOwnerCompositionServices_FindComposition(ITfContextOwnerCompositionServices *iface,
        TfEditCookie ecRead, ITfRange *pTestRange, IEnumITfCompositionView **ppEnum)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    FIXME("STUB:(%p) %#x %p %p\n", This, ecRead, pTestRange, ppEnum);
    return E_NOTIMPL;
}

static HRESULT WINAPI ContextOwnerCompositionServices_TakeOwnership(ITfContextOwnerCompositionServices *iface,
        TfEditCookie ecWrite, ITfCompositionView *pComposition, ITfCompositionSink *pSink, ITfComposition **ppComposition)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    FIXME("STUB:(%p) %#x %p %p %p\n", This, ecWrite, pComposition, pSink, ppComposition);
    return E_NOTIMPL;
}

static HRESULT WINAPI ContextOwnerCompositionServices_TerminateComposition(ITfContextOwnerCompositionServices *iface,
        ITfCompositionView *pComposition)
{
    Context *This = impl_from_ITfContextOwnerCompositionServices(iface);
    FIXME("STUB:(%p) %p\n", This, pComposition);
    return E_NOTIMPL;
}

static const ITfContextOwnerCompositionServicesVtbl ContextOwnerCompositionServicesVtbl =
{
    ContextOwnerCompositionServices_QueryInterface,
    ContextOwnerCompositionServices_AddRef,
    ContextOwnerCompositionServices_Release,
    ContextOwnerCompositionServices_StartComposition,
    ContextOwnerCompositionServices_EnumCompositions,
    ContextOwnerCompositionServices_FindComposition,
    ContextOwnerCompositionServices_TakeOwnership,
    ContextOwnerCompositionServices_TerminateComposition
};

665 666 667 668 669
/*****************************************************
 * ITfInsertAtSelection functions
 *****************************************************/
static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
{
670
    Context *This = impl_from_ITfInsertAtSelection(iface);
671
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
672 673 674 675
}

static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface)
{
676 677
    Context *This = impl_from_ITfInsertAtSelection(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
678 679 680 681
}

static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
{
682 683
    Context *This = impl_from_ITfInsertAtSelection(iface);
    return ITfContext_Release(&This->ITfContext_iface);
684 685
}

686
static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection(
687 688 689
        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
        const WCHAR *pchText, LONG cch, ITfRange **ppRange)
{
690
    Context *This = impl_from_ITfInsertAtSelection(iface);
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
    EditCookie *cookie;
    LONG acpStart, acpEnd;
    TS_TEXTCHANGE change;
    HRESULT hr;

    TRACE("(%p) %i %x %s %p\n",This, ec, dwFlags, debugstr_wn(pchText,cch), ppRange);

    if (!This->connected)
        return TF_E_DISCONNECTED;

    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
        return TF_E_NOLOCK;

    cookie = get_Cookie_data(ec);

    if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE )
        return TS_E_READONLY;

    if (!This->pITextStoreACP)
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

    hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
    if (SUCCEEDED(hr))
717
        Range_Constructor(&This->ITfContext_iface, change.acpStart, change.acpNewEnd, ppRange);
718 719

    return hr;
720 721
}

722
static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection(
723 724 725
        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
        IDataObject *pDataObject, ITfRange **ppRange)
{
726
    Context *This = impl_from_ITfInsertAtSelection(iface);
727 728 729 730
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

731
static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl =
732 733 734 735 736 737 738 739
{
    InsertAtSelection_QueryInterface,
    InsertAtSelection_AddRef,
    InsertAtSelection_Release,
    InsertAtSelection_InsertTextAtSelection,
    InsertAtSelection_InsertEmbeddedAtSelection,
};

740 741 742 743 744
/*****************************************************
 * ITfSourceSingle functions
 *****************************************************/
static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
{
745
    Context *This = impl_from_ITfSourceSingle(iface);
746
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
747 748 749 750
}

static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface)
{
751
    Context *This = impl_from_ITfSourceSingle(iface);
752
    return ITfContext_AddRef(&This->ITfContext_iface);
753 754 755 756
}

static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface)
{
757
    Context *This = impl_from_ITfSourceSingle(iface);
758
    return ITfContext_Release(&This->ITfContext_iface);
759 760
}

761
static HRESULT WINAPI SourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
762 763
    TfClientId tid, REFIID riid, IUnknown *punk)
{
764
    Context *This = impl_from_ITfSourceSingle(iface);
765 766 767 768
    FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
    return E_NOTIMPL;
}

769
static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
770 771
    TfClientId tid, REFIID riid)
{
772
    Context *This = impl_from_ITfSourceSingle(iface);
773 774 775 776
    FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
    return E_NOTIMPL;
}

777
static const ITfSourceSingleVtbl ContextSourceSingleVtbl =
778 779 780 781 782 783 784 785
{
    SourceSingle_QueryInterface,
    SourceSingle_AddRef,
    SourceSingle_Release,
    SourceSingle_AdviseSingleSink,
    SourceSingle_UnadviseSingleSink,
};

786 787 788 789 790 791
/**************************************************************************
 *  ITextStoreACPSink
 **************************************************************************/

static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
{
792 793
    Context *This = impl_from_ITextStoreACPSink(iface);

794 795 796 797
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
    {
798
        *ppvOut = &This->ITextStoreACPSink_iface;
799
    }
800 801
    else if (IsEqualIID(iid, &IID_ITextStoreACPServices))
        *ppvOut = &This->ITextStoreACPServices_iface;
802 803 804

    if (*ppvOut)
    {
805
        ITextStoreACPSink_AddRef(iface);
806 807 808 809 810 811 812 813 814
        return S_OK;
    }

    WARN("unsupported interface: %s\n", debugstr_guid(iid));
    return E_NOINTERFACE;
}

static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
{
815 816
    Context *This = impl_from_ITextStoreACPSink(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
817 818 819 820
}

static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
{
821 822
    Context *This = impl_from_ITextStoreACPSink(iface);
    return ITfContext_Release(&This->ITfContext_iface);
823 824 825 826 827 828 829 830 831
}

/*****************************************************
 * ITextStoreACPSink functions
 *****************************************************/

static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
        DWORD dwFlags, const TS_TEXTCHANGE *pChange)
{
832
    Context *This = impl_from_ITextStoreACPSink(iface);
833
    FIXME("STUB:(%p)\n",This);
834
    return S_OK;
835 836 837 838
}

static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
{
839
    Context *This = impl_from_ITextStoreACPSink(iface);
840
    FIXME("STUB:(%p)\n",This);
841
    return S_OK;
842 843 844 845 846
}

static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
    TsLayoutCode lcode, TsViewCookie vcView)
{
847
    Context *This = impl_from_ITextStoreACPSink(iface);
848
    FIXME("STUB:(%p)\n",This);
849
    return S_OK;
850 851 852 853 854
}

static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
        DWORD dwFlags)
{
855
    Context *This = impl_from_ITextStoreACPSink(iface);
856 857 858 859
    HRESULT hr, hrSession;

    TRACE("(%p) %x\n",This, dwFlags);

860
    if (!This->pITextStoreACP)
861 862 863 864 865
    {
        FIXME("Context does not have a ITextStoreACP\n");
        return E_NOTIMPL;
    }

866
    hr = ITextStoreACP_RequestLock(This->pITextStoreACP, TS_LF_READ, &hrSession);
867 868

    if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
869
        This->documentStatus.dwDynamicFlags = dwFlags;
870 871

    return S_OK;
872 873 874 875 876
}

static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
        LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
{
877
    Context *This = impl_from_ITextStoreACPSink(iface);
878 879 880 881 882 883 884
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
        DWORD dwLockFlags)
{
885
    Context *This = impl_from_ITextStoreACPSink(iface);
886
    HRESULT hr;
887
    EditCookie *cookie,*sinkcookie;
888
    TfEditCookie ec;
889
    struct list *cursor;
890 891 892

    TRACE("(%p) %x\n",This, dwLockFlags);

893
    if (!This->currentEditSession)
894 895 896 897 898
    {
        FIXME("OnLockGranted called for something other than an EditSession\n");
        return S_OK;
    }

899 900 901 902
    cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (!cookie)
        return E_OUTOFMEMORY;

903 904
    sinkcookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (!sinkcookie)
905 906
    {
        HeapFree(GetProcessHeap(), 0, cookie);
907
        return E_OUTOFMEMORY;
908
    }
909

910
    cookie->lockType = dwLockFlags;
911
    cookie->pOwningContext = This;
912 913
    ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);

914
    hr = ITfEditSession_DoEditSession(This->currentEditSession, ec);
915

916 917
    if ((dwLockFlags&TS_LF_READWRITE) == TS_LF_READWRITE)
    {
918
        ITfTextEditSink *sink;
919 920 921
        TfEditCookie sc;

        sinkcookie->lockType = TS_LF_READ;
922
        sinkcookie->pOwningContext = This;
923 924 925
        sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);

        /*TODO: implement ITfEditRecord */
926
        SINK_FOR_EACH(cursor, &This->pTextEditSink, ITfTextEditSink, sink)
927
        {
928
            ITfTextEditSink_OnEndEdit(sink, &This->ITfContext_iface, sc, NULL);
929 930 931 932 933
        }
        sinkcookie = remove_Cookie(sc);
    }
    HeapFree(GetProcessHeap(),0,sinkcookie);

934 935
    ITfEditSession_Release(This->currentEditSession);
    This->currentEditSession = NULL;
936

937 938 939 940
    /* Edit Cookie is only valid during the edit session */
    cookie = remove_Cookie(ec);
    HeapFree(GetProcessHeap(),0,cookie);

941
    return hr;
942 943 944 945
}

static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
{
946
    Context *This = impl_from_ITextStoreACPSink(iface);
947 948 949 950 951 952
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
{
953
    Context *This = impl_from_ITextStoreACPSink(iface);
954 955 956 957
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

958
static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl =
959 960 961 962 963 964 965 966 967 968 969 970 971 972
{
    TextStoreACPSink_QueryInterface,
    TextStoreACPSink_AddRef,
    TextStoreACPSink_Release,
    TextStoreACPSink_OnTextChange,
    TextStoreACPSink_OnSelectionChange,
    TextStoreACPSink_OnLayoutChange,
    TextStoreACPSink_OnStatusChange,
    TextStoreACPSink_OnAttrsChange,
    TextStoreACPSink_OnLockGranted,
    TextStoreACPSink_OnStartEditTransaction,
    TextStoreACPSink_OnEndEditTransaction
};

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
static HRESULT WINAPI TextStoreACPServices_QueryInterface(ITextStoreACPServices *iface, REFIID riid, void **obj)
{
    Context *This = impl_from_ITextStoreACPServices(iface);
    return ITextStoreACPSink_QueryInterface(&This->ITextStoreACPSink_iface, riid, obj);
}

static ULONG WINAPI TextStoreACPServices_AddRef(ITextStoreACPServices *iface)
{
    Context *This = impl_from_ITextStoreACPServices(iface);
    return ITextStoreACPSink_AddRef(&This->ITextStoreACPSink_iface);
}

static ULONG WINAPI TextStoreACPServices_Release(ITextStoreACPServices *iface)
{
    Context *This = impl_from_ITextStoreACPServices(iface);
    return ITextStoreACPSink_Release(&This->ITextStoreACPSink_iface);
}

static HRESULT WINAPI TextStoreACPServices_Serialize(ITextStoreACPServices *iface, ITfProperty *prop, ITfRange *range,
    TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream)
{
    Context *This = impl_from_ITextStoreACPServices(iface);

    FIXME("stub: %p %p %p %p %p\n", This, prop, range, header, stream);

    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPServices_Unserialize(ITextStoreACPServices *iface, ITfProperty *prop,
    const TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream, ITfPersistentPropertyLoaderACP *loader)
{
    Context *This = impl_from_ITextStoreACPServices(iface);

    FIXME("stub: %p %p %p %p %p\n", This, prop, header, stream, loader);

    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPServices_ForceLoadProperty(ITextStoreACPServices *iface, ITfProperty *prop)
{
    Context *This = impl_from_ITextStoreACPServices(iface);

    FIXME("stub: %p %p\n", This, prop);

    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPServices_CreateRange(ITextStoreACPServices *iface,
    LONG start, LONG end, ITfRangeACP **range)
{
    Context *This = impl_from_ITextStoreACPServices(iface);

1025
    TRACE("%p, %d, %d, %p.\n", This, start, end, range);
1026

1027
    return Range_Constructor(&This->ITfContext_iface, start, end, (ITfRange **)range);
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
}

static const ITextStoreACPServicesVtbl TextStoreACPServicesVtbl =
{
    TextStoreACPServices_QueryInterface,
    TextStoreACPServices_AddRef,
    TextStoreACPServices_Release,
    TextStoreACPServices_Serialize,
    TextStoreACPServices_Unserialize,
    TextStoreACPServices_ForceLoadProperty,
    TextStoreACPServices_CreateRange
};

1041
HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore)
1042
{
1043 1044
    Context *This;
    EditCookie *cookie;
1045

1046
    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
1047 1048 1049
    if (This == NULL)
        return E_OUTOFMEMORY;

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (cookie == NULL)
    {
        HeapFree(GetProcessHeap(),0,This);
        return E_OUTOFMEMORY;
    }

    TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore);

    This->ITfContext_iface.lpVtbl= &ContextVtbl;
    This->ITfSource_iface.lpVtbl = &ContextSourceVtbl;
1061
    This->ITfContextOwnerCompositionServices_iface.lpVtbl = &ContextOwnerCompositionServicesVtbl;
1062 1063 1064
    This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl;
    This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl;
    This->ITextStoreACPSink_iface.lpVtbl = &TextStoreACPSinkVtbl;
1065
    This->ITextStoreACPServices_iface.lpVtbl = &TextStoreACPServicesVtbl;
1066
    This->refCount = 1;
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
    This->tidOwner = tidOwner;
    This->connected = FALSE;
    This->manager = mgr;

    CompartmentMgr_Constructor((IUnknown*)&This->ITfContext_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);

    cookie->lockType = TF_ES_READ;
    cookie->pOwningContext = This;

    if (punk)
    {
        IUnknown_QueryInterface(punk, &IID_ITextStoreACP,
                          (LPVOID*)&This->pITextStoreACP);

        IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink,
                                (LPVOID*)&This->pITfContextOwnerCompositionSink);
1083

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink)
            FIXME("Unhandled pUnk\n");
    }

    This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie);
    *pecTextStore = This->defaultCookie;

    list_init(&This->pContextKeyEventSink);
    list_init(&This->pEditTransactionSink);
    list_init(&This->pStatusSink);
    list_init(&This->pTextEditSink);
    list_init(&This->pTextLayoutSink);
1096

1097
    *ppOut = &This->ITfContext_iface;
1098
    TRACE("returning %p\n", *ppOut);
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122

    return S_OK;
}

HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
{
    Context *This = impl_from_ITfContext(iface);

    if (This->pITextStoreACP)
        ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
            (IUnknown*)&This->ITextStoreACPSink_iface, TS_AS_ALL_SINKS);
    This->connected = TRUE;
    This->manager = manager;
    return S_OK;
}

HRESULT Context_Uninitialize(ITfContext *iface)
{
    Context *This = impl_from_ITfContext(iface);

    if (This->pITextStoreACP)
        ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)&This->ITextStoreACPSink_iface);
    This->connected = FALSE;
    This->manager = NULL;
1123 1124
    return S_OK;
}