context.c 31 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 33 34
/*
 *  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 "config.h"

#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"
35
#include "olectl.h"
36 37

#include "wine/unicode.h"
38
#include "wine/list.h"
39 40 41 42 43 44

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

WINE_DEFAULT_DEBUG_CHANNEL(msctf);

45 46 47 48 49 50 51 52 53 54 55 56 57
typedef struct tagContextSink {
    struct list         entry;
    union {
        /* Context Sinks */
        IUnknown            *pIUnknown;
        /* ITfContextKeyEventSink  *pITfContextKeyEventSink; */
        /* ITfEditTransactionSink  *pITfEditTransactionSink; */
        /* ITfStatusSink           *pITfStatusSink; */
        ITfTextEditSink     *pITfTextEditSink;
        /* ITfTextLayoutSink       *pITfTextLayoutSink; */
    } interfaces;
} ContextSink;

58
typedef struct tagContext {
59 60
    ITfContext ITfContext_iface;
    ITfSource ITfSource_iface;
61 62 63
    /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
    /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */
    /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
64
    ITfInsertAtSelection ITfInsertAtSelection_iface;
65 66
    /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
    /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
67
    ITfSourceSingle ITfSourceSingle_iface;
68
    LONG refCount;
69
    BOOL connected;
70

71 72 73
    /* Aggregation */
    ITfCompartmentMgr  *CompartmentMgr;

74
    TfClientId tidOwner;
75
    TfEditCookie defaultCookie;
76
    TS_STATUS documentStatus;
77
    ITfDocumentMgr *manager;
78 79

    ITextStoreACP   *pITextStoreACP;
80
    ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
81 82

    ITextStoreACPSink *pITextStoreACPSink;
83
    ITfEditSession* currentEditSession;
84

85
    /* kept as separate lists to reduce unnecessary iterations */
86 87 88 89 90 91
    struct list     pContextKeyEventSink;
    struct list     pEditTransactionSink;
    struct list     pStatusSink;
    struct list     pTextEditSink;
    struct list     pTextLayoutSink;

92 93
} Context;

94 95 96 97
typedef struct tagEditCookie {
    DWORD lockType;
    Context *pOwningContext;
} EditCookie;
98 99

typedef struct tagTextStoreACPSink {
100
    ITextStoreACPSink ITextStoreACPSink_iface;
101
    /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
102 103 104 105 106 107 108 109
    LONG refCount;

    Context *pContext;
} TextStoreACPSink;


static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);

110
static inline Context *impl_from_ITfContext(ITfContext *iface)
111
{
112
    return CONTAINING_RECORD(iface, Context, ITfContext_iface);
113 114
}

115
static inline Context *impl_from_ITfSource(ITfSource *iface)
116
{
117
    return CONTAINING_RECORD(iface, Context, ITfSource_iface);
118 119
}

120
static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface)
121
{
122 123 124 125 126 127 128 129 130 131 132
    return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface);
}

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

static inline TextStoreACPSink *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
{
    return CONTAINING_RECORD(iface, TextStoreACPSink, ITextStoreACPSink_iface);
133 134
}

135 136 137 138 139 140
static void free_sink(ContextSink *sink)
{
        IUnknown_Release(sink->interfaces.pIUnknown);
        HeapFree(GetProcessHeap(),0,sink);
}

141 142
static void Context_Destructor(Context *This)
{
143
    struct list *cursor, *cursor2;
144
    EditCookie *cookie;
145
    TRACE("destroying %p\n", This);
146

147 148 149 150 151 152 153
    if (This->pITextStoreACPSink)
    {
        ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
        ITextStoreACPSink_Release(This->pITextStoreACPSink);
    }

    if (This->pITextStoreACP)
154
        ITextStoreACP_Release(This->pITextStoreACP);
155

156
    if (This->pITfContextOwnerCompositionSink)
157
        ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink);
158

159 160 161 162 163 164 165
    if (This->defaultCookie)
    {
        cookie = remove_Cookie(This->defaultCookie);
        HeapFree(GetProcessHeap(),0,cookie);
        This->defaultCookie = 0;
    }

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
    {
        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
    {
        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
    {
        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
    {
        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
    {
        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }

197
    CompartmentMgr_Destructor(This->CompartmentMgr);
198 199 200 201 202
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
{
203
    Context *This = impl_from_ITfContext(iface);
204 205 206 207
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
    {
208
        *ppvOut = &This->ITfContext_iface;
209
    }
210 211
    else if (IsEqualIID(iid, &IID_ITfSource))
    {
212
        *ppvOut = &This->ITfSource_iface;
213
    }
214 215
    else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
    {
216
        *ppvOut = &This->ITfInsertAtSelection_iface;
217
    }
218 219 220 221
    else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
    {
        *ppvOut = This->CompartmentMgr;
    }
222 223
    else if (IsEqualIID(iid, &IID_ITfSourceSingle))
    {
224
        *ppvOut = &This->ITfSourceSingle_iface;
225
    }
226 227 228

    if (*ppvOut)
    {
229
        ITfContext_AddRef(iface);
230 231 232 233 234 235 236 237 238
        return S_OK;
    }

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

static ULONG WINAPI Context_AddRef(ITfContext *iface)
{
239
    Context *This = impl_from_ITfContext(iface);
240 241 242 243 244
    return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI Context_Release(ITfContext *iface)
{
245
    Context *This = impl_from_ITfContext(iface);
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    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)
{
261
    Context *This = impl_from_ITfContext(iface);
262 263 264 265 266 267 268 269 270 271 272 273 274
    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)
    {
275
        FIXME("No ITextStoreACP available\n");
276 277 278 279 280
        *phrSession = E_FAIL;
        return E_FAIL;
    }

    if (!(dwFlags & TF_ES_ASYNC))
281
        dwLockFlags |= TS_LF_SYNC;
282

283
    if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
284
        dwLockFlags |= TS_LF_READWRITE;
285 286
    else if (dwFlags & TF_ES_READ)
        dwLockFlags |= TS_LF_READ;
287

288 289
    if (!This->documentStatus.dwDynamicFlags)
        ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
290

291
    if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY))
292 293 294 295 296 297 298 299 300 301 302 303 304 305
    {
        *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;
306 307 308 309 310 311
}

static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
         TfClientId tid,
         BOOL *pfWriteSession)
{
312
    Context *This = impl_from_ITfContext(iface);
313 314 315 316 317 318 319 320
    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)
{
321
    Context *This = impl_from_ITfContext(iface);
322 323 324 325 326 327 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 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    EditCookie *cookie;
    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;
    }

    cookie = get_Cookie_data(ec);

    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;
            Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range);
            totalFetched ++;
        }
        else
            break;
    }

    *pcFetched = totalFetched;

    return hr;
375 376 377 378 379
}

static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
        TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
{
380
    Context *This = impl_from_ITfContext(iface);
381
    TS_SELECTION_ACP *acp;
382
    ULONG i;
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    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;
413 414 415 416 417
}

static HRESULT WINAPI Context_GetStart (ITfContext *iface,
        TfEditCookie ec, ITfRange **ppStart)
{
418
    Context *This = impl_from_ITfContext(iface);
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    EditCookie *cookie;
    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;

    cookie = get_Cookie_data(ec);
    return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, 0, 0, ppStart);
435 436 437 438 439
}

static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
        TfEditCookie ec, ITfRange **ppEnd)
{
440
    Context *This = impl_from_ITfContext(iface);
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
    EditCookie *cookie;
    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;
    }

    cookie = get_Cookie_data(ec);
    ITextStoreACP_GetEndACP(This->pITextStoreACP,&end);

    return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, end, end, ppEnd);
466 467 468 469 470
}

static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
  ITfContextView **ppView)
{
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_EnumViews (ITfContext *iface,
        IEnumTfContextViews **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_GetStatus (ITfContext *iface,
        TF_STATUS *pdcs)
{
487
    Context *This = impl_from_ITfContext(iface);
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
    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;
507 508 509 510 511
}

static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
        REFGUID guidProp, ITfProperty **ppProp)
{
512
    Context *This = impl_from_ITfContext(iface);
513 514 515 516 517 518 519
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
        REFGUID guidProp, ITfReadOnlyProperty **ppProp)
{
520
    Context *This = impl_from_ITfContext(iface);
521 522 523 524 525 526 527 528
    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)
{
529
    Context *This = impl_from_ITfContext(iface);
530 531 532 533 534 535 536
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
        IEnumTfProperties **ppEnum)
{
537
    Context *This = impl_from_ITfContext(iface);
538 539 540 541 542 543 544
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
        ITfDocumentMgr **ppDm)
{
545
    Context *This = impl_from_ITfContext(iface);
546 547 548 549 550 551 552 553
    TRACE("(%p) %p\n",This,ppDm);

    if (!ppDm)
        return E_INVALIDARG;

    *ppDm = This->manager;
    if (!This->manager)
        return S_FALSE;
554 555 556

    ITfDocumentMgr_AddRef(This->manager);

557
    return S_OK;
558 559 560 561 562
}

static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
        TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
{
563
    Context *This = impl_from_ITfContext(iface);
564 565 566 567
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

568
static const ITfContextVtbl ContextVtbl =
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
{
    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
};

590
static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
591
{
592
    Context *This = impl_from_ITfSource(iface);
593
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
594 595
}

596
static ULONG WINAPI ContextSource_AddRef(ITfSource *iface)
597
{
598 599
    Context *This = impl_from_ITfSource(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
600 601
}

602
static ULONG WINAPI ContextSource_Release(ITfSource *iface)
603
{
604 605
    Context *This = impl_from_ITfSource(iface);
    return ITfContext_Release(&This->ITfContext_iface);
606 607 608 609 610
}

/*****************************************************
 * ITfSource functions
 *****************************************************/
611
static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface,
612 613
        REFIID riid, IUnknown *punk, DWORD *pdwCookie)
{
614
    Context *This = impl_from_ITfSource(iface);
615 616 617 618 619 620 621 622 623 624 625
    ContextSink *es;
    TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);

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

    if (IsEqualIID(riid, &IID_ITfTextEditSink))
    {
        es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
        if (!es)
            return E_OUTOFMEMORY;
626
        if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&es->interfaces.pITfTextEditSink)))
627 628 629 630 631
        {
            HeapFree(GetProcessHeap(),0,es);
            return CONNECT_E_CANNOTCONNECT;
        }
        list_add_head(&This->pTextEditSink ,&es->entry);
632
        *pdwCookie = generate_Cookie(COOKIE_MAGIC_CONTEXTSINK, es);
633 634 635 636 637 638 639 640 641
    }
    else
    {
        FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
        return E_NOTIMPL;
    }

    TRACE("cookie %x\n",*pdwCookie);
    return S_OK;
642 643
}

644
static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
645
{
646
    Context *This = impl_from_ITfSource(iface);
647 648
    ContextSink *sink;

649 650
    TRACE("(%p) %x\n",This,pdwCookie);

651 652 653
    if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
        return E_INVALIDARG;

654
    sink = remove_Cookie(pdwCookie);
655 656 657
    if (!sink)
        return CONNECT_E_NOCONNECTION;

658 659 660 661
    list_remove(&sink->entry);
    free_sink(sink);

    return S_OK;
662 663
}

664
static const ITfSourceVtbl ContextSourceVtbl =
665
{
666 667 668
    ContextSource_QueryInterface,
    ContextSource_AddRef,
    ContextSource_Release,
669
    ContextSource_AdviseSink,
670
    ContextSource_UnadviseSink
671 672
};

673 674 675 676 677
/*****************************************************
 * ITfInsertAtSelection functions
 *****************************************************/
static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
{
678
    Context *This = impl_from_ITfInsertAtSelection(iface);
679
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
680 681 682 683
}

static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface)
{
684 685
    Context *This = impl_from_ITfInsertAtSelection(iface);
    return ITfContext_AddRef(&This->ITfContext_iface);
686 687 688 689
}

static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
{
690 691
    Context *This = impl_from_ITfInsertAtSelection(iface);
    return ITfContext_Release(&This->ITfContext_iface);
692 693
}

694
static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection(
695 696 697
        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
        const WCHAR *pchText, LONG cch, ITfRange **ppRange)
{
698
    Context *This = impl_from_ITfInsertAtSelection(iface);
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
    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))
725
        Range_Constructor(&This->ITfContext_iface, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
726 727

    return hr;
728 729
}

730
static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection(
731 732 733
        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
        IDataObject *pDataObject, ITfRange **ppRange)
{
734
    Context *This = impl_from_ITfInsertAtSelection(iface);
735 736 737 738
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

739
static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl =
740 741 742 743 744 745 746 747
{
    InsertAtSelection_QueryInterface,
    InsertAtSelection_AddRef,
    InsertAtSelection_Release,
    InsertAtSelection_InsertTextAtSelection,
    InsertAtSelection_InsertEmbeddedAtSelection,
};

748 749 750 751 752
/*****************************************************
 * ITfSourceSingle functions
 *****************************************************/
static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
{
753
    Context *This = impl_from_ITfSourceSingle(iface);
754
    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
755 756 757 758
}

static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface)
{
759
    Context *This = impl_from_ITfSourceSingle(iface);
760
    return ITfContext_AddRef(&This->ITfContext_iface);
761 762 763 764
}

static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface)
{
765
    Context *This = impl_from_ITfSourceSingle(iface);
766
    return ITfContext_Release(&This->ITfContext_iface);
767 768
}

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

777
static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
778 779
    TfClientId tid, REFIID riid)
{
780
    Context *This = impl_from_ITfSourceSingle(iface);
781 782 783 784
    FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
    return E_NOTIMPL;
}

785
static const ITfSourceSingleVtbl ContextSourceSingleVtbl =
786 787 788 789 790 791 792 793
{
    SourceSingle_QueryInterface,
    SourceSingle_AddRef,
    SourceSingle_Release,
    SourceSingle_AdviseSingleSink,
    SourceSingle_UnadviseSingleSink,
};

794
HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore)
795 796
{
    Context *This;
797
    EditCookie *cookie;
798 799 800 801 802

    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
    if (This == NULL)
        return E_OUTOFMEMORY;

803 804 805 806 807 808 809
    cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (cookie == NULL)
    {
        HeapFree(GetProcessHeap(),0,This);
        return E_OUTOFMEMORY;
    }

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

812 813 814 815
    This->ITfContext_iface.lpVtbl= &ContextVtbl;
    This->ITfSource_iface.lpVtbl = &ContextSourceVtbl;
    This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl;
    This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl;
816 817
    This->refCount = 1;
    This->tidOwner = tidOwner;
818
    This->connected = FALSE;
819
    This->manager = mgr;
820

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

823 824 825
    cookie->lockType = TF_ES_READ;
    cookie->pOwningContext = This;

826
    if (punk)
827
    {
828 829
        IUnknown_QueryInterface(punk, &IID_ITextStoreACP,
                          (LPVOID*)&This->pITextStoreACP);
830 831 832 833 834 835

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

        if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink)
            FIXME("Unhandled pUnk\n");
836
    }
837

838 839
    This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie);
    *pecTextStore = This->defaultCookie;
840 841 842 843 844 845 846

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

847 848
    *ppOut = &This->ITfContext_iface;
    TRACE("returning %p\n", *ppOut);
849

850 851
    return S_OK;
}
852

853
HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
854
{
855
    Context *This = impl_from_ITfContext(iface);
856 857 858 859 860 861 862 863

    if (This->pITextStoreACP)
    {
        if (SUCCEEDED(TextStoreACPSink_Constructor(&This->pITextStoreACPSink, This)))
            ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
                            (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
    }
    This->connected = TRUE;
864
    This->manager = manager;
865 866 867 868 869
    return S_OK;
}

HRESULT Context_Uninitialize(ITfContext *iface)
{
870
    Context *This = impl_from_ITfContext(iface);
871 872 873 874 875 876 877 878

    if (This->pITextStoreACPSink)
    {
        ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
        if (ITextStoreACPSink_Release(This->pITextStoreACPSink) == 0)
            This->pITextStoreACPSink = NULL;
    }
    This->connected = FALSE;
879
    This->manager = NULL;
880 881 882
    return S_OK;
}

883 884 885 886 887 888 889 890 891 892 893 894
/**************************************************************************
 *  ITextStoreACPSink
 **************************************************************************/

static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
{
    TRACE("destroying %p\n", This);
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
{
895
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
896 897 898 899
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
    {
900
        *ppvOut = &This->ITextStoreACPSink_iface;
901 902 903 904
    }

    if (*ppvOut)
    {
905
        ITextStoreACPSink_AddRef(iface);
906 907 908 909 910 911 912 913 914
        return S_OK;
    }

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

static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
{
915
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
916 917 918 919 920
    return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
{
921
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
    ULONG ret;

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

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

static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
        DWORD dwFlags, const TS_TEXTCHANGE *pChange)
{
937
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
938 939 940 941 942 943
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

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

static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
    TsLayoutCode lcode, TsViewCookie vcView)
{
952
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
953 954 955 956 957 958 959
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
        DWORD dwFlags)
{
960
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
    HRESULT hr, hrSession;

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

    if (!This->pContext)
    {
        ERR("No context?\n");
        return E_FAIL;
    }

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

    hr = ITextStoreACP_RequestLock(This->pContext->pITextStoreACP, TS_LF_READ, &hrSession);

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

    return S_OK;
983 984 985 986 987
}

static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
        LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
{
988
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
989 990 991 992 993 994 995
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
        DWORD dwLockFlags)
{
996
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
997
    HRESULT hr;
998
    EditCookie *cookie,*sinkcookie;
999
    TfEditCookie ec;
1000
    struct list *cursor;
1001 1002 1003

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

1004
    if (!This->pContext)
1005
    {
1006
        ERR("OnLockGranted called without a context\n");
1007 1008 1009
        return E_FAIL;
    }

1010 1011 1012 1013 1014 1015
    if (!This->pContext->currentEditSession)
    {
        FIXME("OnLockGranted called for something other than an EditSession\n");
        return S_OK;
    }

1016 1017 1018 1019
    cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (!cookie)
        return E_OUTOFMEMORY;

1020 1021
    sinkcookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
    if (!sinkcookie)
1022 1023
    {
        HeapFree(GetProcessHeap(), 0, cookie);
1024
        return E_OUTOFMEMORY;
1025
    }
1026

1027 1028 1029 1030 1031
    cookie->lockType = dwLockFlags;
    cookie->pOwningContext = This->pContext;
    ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);

    hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, ec);
1032

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
    if ((dwLockFlags&TS_LF_READWRITE) == TS_LF_READWRITE)
    {
        TfEditCookie sc;

        sinkcookie->lockType = TS_LF_READ;
        sinkcookie->pOwningContext = This->pContext;
        sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);

        /*TODO: implement ITfEditRecord */
        LIST_FOR_EACH(cursor, &This->pContext->pTextEditSink)
        {
            ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
            ITfTextEditSink_OnEndEdit(sink->interfaces.pITfTextEditSink,
                                      (ITfContext*) &This->pContext, sc, NULL);
        }
        sinkcookie = remove_Cookie(sc);
    }
    HeapFree(GetProcessHeap(),0,sinkcookie);

1052 1053 1054
    ITfEditSession_Release(This->pContext->currentEditSession);
    This->pContext->currentEditSession = NULL;

1055 1056 1057 1058
    /* Edit Cookie is only valid during the edit session */
    cookie = remove_Cookie(ec);
    HeapFree(GetProcessHeap(),0,cookie);

1059
    return hr;
1060 1061 1062 1063
}

static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
{
1064
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
1065 1066 1067 1068 1069 1070
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
{
1071
    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
1072 1073 1074 1075
    FIXME("STUB:(%p)\n",This);
    return E_NOTIMPL;
}

1076
static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl =
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
{
    TextStoreACPSink_QueryInterface,
    TextStoreACPSink_AddRef,
    TextStoreACPSink_Release,
    TextStoreACPSink_OnTextChange,
    TextStoreACPSink_OnSelectionChange,
    TextStoreACPSink_OnLayoutChange,
    TextStoreACPSink_OnStatusChange,
    TextStoreACPSink_OnAttrsChange,
    TextStoreACPSink_OnLockGranted,
    TextStoreACPSink_OnStartEditTransaction,
    TextStoreACPSink_OnEndEditTransaction
};

static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
{
    TextStoreACPSink *This;

    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
    if (This == NULL)
        return E_OUTOFMEMORY;

1099
    This->ITextStoreACPSink_iface.lpVtbl= &TextStoreACPSinkVtbl;
1100 1101 1102 1103
    This->refCount = 1;

    This->pContext = pContext;

1104
    *ppOut = &This->ITextStoreACPSink_iface;
1105
    TRACE("returning %p\n", *ppOut);
1106 1107
    return S_OK;
}