|
|
//
// snoop.cpp
//
// CSnoopWnd implementation.
//
#include "globals.h"
#include "snoop.h"
#include "case.h"
#include "editsess.h"
class CUpdateTextEditSession : public CEditSessionBase { public: CUpdateTextEditSession(ITfContext *pContext, ITfRange *pRange, CSnoopWnd *pSnoopWnd) : CEditSessionBase(pContext) { _pSnoopWnd = pSnoopWnd; _pRange = pRange; if (_pRange != NULL) { _pRange->AddRef(); } } ~CUpdateTextEditSession() { SafeRelease(_pRange); }
// ITfEditSession
STDMETHODIMP DoEditSession(TfEditCookie ec);
private: CSnoopWnd *_pSnoopWnd; ITfRange *_pRange; };
#define SNOOP_X_POS 0
#define SNOOP_Y_POS 0
#define SNOOP_WIDTH 300
#define SNOOP_HEIGHT (SNOOP_WIDTH / 3)
ATOM CSnoopWnd::_atomWndClass = 0;
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CSnoopWnd::CSnoopWnd(CCaseTextService *pCase) { _pCase = pCase; // no AddRef because CSnoopWnd is contained in the
// pCase lifetime
_hWnd = NULL; _cchText = 0; }
//+---------------------------------------------------------------------------
//
// _InitClass
//
//----------------------------------------------------------------------------
/* static */ BOOL CSnoopWnd::_InitClass() { WNDCLASS wc;
wc.style = 0; wc.lpfnWndProc = CSnoopWnd::_WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("SnoopWndClass");
_atomWndClass = RegisterClass(&wc);
return (_atomWndClass != 0); }
//+---------------------------------------------------------------------------
//
// _UninitClass
//
//----------------------------------------------------------------------------
/* static */ void CSnoopWnd::_UninitClass() { if (_atomWndClass != 0) { UnregisterClass((LPCTSTR)_atomWndClass, g_hInst); } }
//+---------------------------------------------------------------------------
//
// _Init
//
//----------------------------------------------------------------------------
BOOL CSnoopWnd::_Init() { // nb: on windows 2000, you can use WS_EX_NOACTIVATE to prevent windows
// from taking the foreground. We don't use that here for compatibility.
// Instead, we use WS_DISABLED, which can be burdensome for more complex
// ui.
_hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, (LPCTSTR)_atomWndClass, TEXT("Snoop Window"), WS_BORDER | WS_DISABLED | WS_POPUP, SNOOP_X_POS, SNOOP_Y_POS, SNOOP_WIDTH, SNOOP_HEIGHT, NULL, NULL, g_hInst, this);
return (_hWnd != NULL); }
//+---------------------------------------------------------------------------
//
// _Uninit
//
//----------------------------------------------------------------------------
void CSnoopWnd::_Uninit() { if (_hWnd != NULL) { DestroyWindow(_hWnd); _hWnd = NULL; } }
//+---------------------------------------------------------------------------
//
// _Show
//
//----------------------------------------------------------------------------
void CSnoopWnd::_Show() { ShowWindow(_hWnd, SW_SHOWNA); }
//+---------------------------------------------------------------------------
//
// _Hide
//
//----------------------------------------------------------------------------
void CSnoopWnd::_Hide() { ShowWindow(_hWnd, SW_HIDE); }
//+---------------------------------------------------------------------------
//
// _UpdateText
//
//----------------------------------------------------------------------------
void CSnoopWnd::_UpdateText(ITfRange *pRange) { ITfDocumentMgr *pdmFocus; ITfContext *pContext; CUpdateTextEditSession *pEditSession; HRESULT hr;
if (pRange == NULL) { // caller wants us to just use the selection in the focus doc
if (_pCase->_GetThreadMgr()->GetFocus(&pdmFocus) != S_OK) return;
hr = pdmFocus->GetTop(&pContext);
pdmFocus->Release();
if (hr != S_OK) return; } else if (pRange->GetContext(&pContext) != S_OK) return;
if (pEditSession = new CUpdateTextEditSession(pContext, pRange, this)) { // we need a document read lock to scan text
// the CUpdateTextEditSession will do all the work when the
// CUpdateTextEditSession::DoEditSession method is called by the context
pContext->RequestEditSession(_pCase->_GetClientId(), pEditSession, TF_ES_READ | TF_ES_ASYNCDONTCARE, &hr);
pEditSession->Release(); }
pContext->Release(); }
//+---------------------------------------------------------------------------
//
// DoEditSession
//
//----------------------------------------------------------------------------
STDAPI CUpdateTextEditSession::DoEditSession(TfEditCookie ec) { _pSnoopWnd->_UpdateText(ec, _pContext, _pRange); return S_OK; }
//+---------------------------------------------------------------------------
//
// _UpdateText
//
//----------------------------------------------------------------------------
void CSnoopWnd::_UpdateText(TfEditCookie ec, ITfContext *pContext, ITfRange *pRange) { LONG cchBefore; LONG cchAfter; TF_SELECTION tfSelection; ULONG cFetched; BOOL fReleaseRange = FALSE;
if (pRange == NULL) { // caller wants us to use the selection
if (pContext->GetSelection(ec, TS_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) { return; }
pRange = tfSelection.range; // no AddRef, take ownership of the pointer
fReleaseRange = TRUE; }
// arbitrarily grab some text before and after the range start anchor
pRange->Collapse(ec, TF_ANCHOR_START);
pRange->ShiftStart(ec, -MAX_SNOOP_TEXT / 2, &cchBefore, NULL);
cchBefore = -cchBefore; // we shifted backwards, so make count a positive number
pRange->GetText(ec, 0, _achText, cchBefore, (ULONG *)&cchBefore);
pRange->Collapse(ec, TF_ANCHOR_END);
pRange->ShiftEnd(ec, MAX_SNOOP_TEXT - cchBefore, &cchAfter, NULL);
pRange->GetText(ec, 0, _achText + cchBefore, cchAfter, (ULONG *)&cchAfter);
_cchText = cchBefore + cchAfter;
// force a repaint
InvalidateRect(_hWnd, NULL, TRUE);
if (fReleaseRange) { pRange->Release(); } }
//+---------------------------------------------------------------------------
//
// _WndProc
//
// Snoop window proc.
//----------------------------------------------------------------------------
/* static */ LRESULT CALLBACK CSnoopWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps;
switch (uMsg) { case WM_CREATE: _SetThis(hWnd, lParam); return 0;
case WM_PAINT: hdc = BeginPaint(hWnd, &ps); _GetThis(hWnd)->_OnPaint(hWnd, hdc); EndPaint(hWnd, &ps); return 0; }
return DefWindowProc(hWnd, uMsg, wParam, lParam); }
//+---------------------------------------------------------------------------
//
// _OnPaint
//
// WM_PAINT handler for CSnoopWnd.
//----------------------------------------------------------------------------
void CSnoopWnd::_OnPaint(HWND hWnd, HDC hdc) { RECT rc;
// background
GetClientRect(hWnd, &rc); FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
// text
TextOutW(hdc, 0, 0, _achText, _cchText); }
//+---------------------------------------------------------------------------
//
// _InitSnoopWnd
//
// Create and init the snoop window.
//----------------------------------------------------------------------------
BOOL CCaseTextService::_InitSnoopWnd() { BOOL fThreadfocus; ITfSource *pSource = NULL;
// create a snoop window
if ((_pSnoopWnd = new CSnoopWnd(this)) == NULL) return FALSE;
if (!_pSnoopWnd->_Init()) goto ExitError;
// we also need a thread focus sink
if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) != S_OK) { pSource = NULL; goto ExitError; }
if (pSource->AdviseSink(IID_ITfThreadFocusSink, (ITfThreadFocusSink *)this, &_dwThreadFocusSinkCookie) != S_OK) { // make sure we don't try to Unadvise _dwThreadFocusSinkCookie later
_dwThreadFocusSinkCookie = TF_INVALID_COOKIE; goto ExitError; }
pSource->Release();
// we may need to display the snoop window right now
// our thread focus sink won't be called until something changes,
// so we need to check the current state.
if (_pThreadMgr->IsThreadFocus(&fThreadfocus) == S_OK && fThreadfocus) { OnSetThreadFocus(); }
return TRUE;
ExitError: SafeRelease(pSource); _UninitSnoopWnd(); return FALSE; }
//+---------------------------------------------------------------------------
//
// _UninitSnoopWnd
//
// Uninit and free the snoop window, unadvise the thread focus sink.
//----------------------------------------------------------------------------
void CCaseTextService::_UninitSnoopWnd() { ITfSource *pSource;
if (_pSnoopWnd != NULL) { _pSnoopWnd->_Uninit(); delete _pSnoopWnd; }
if (_dwThreadFocusSinkCookie != TF_INVALID_COOKIE) { if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK) { pSource->UnadviseSink(_dwThreadFocusSinkCookie); pSource->Release(); }
_dwThreadFocusSinkCookie = TF_INVALID_COOKIE; } }
//+---------------------------------------------------------------------------
//
// _Menu_ShowSnoopWnd
//
// Show or hide the snoop window.
//----------------------------------------------------------------------------
void CCaseTextService::_Menu_ShowSnoopWnd(CCaseTextService *_this) { _this->_fShowSnoop = !_this->_fShowSnoop;
if (_this->_fShowSnoop) { _this->_pSnoopWnd->_Show(); } else { _this->_pSnoopWnd->_Hide(); } }
//+---------------------------------------------------------------------------
//
// OnSetThreadFocus
//
// Called by the system when the thread/appartment of this text service gains
// the ui focus.
//----------------------------------------------------------------------------
STDAPI CCaseTextService::OnSetThreadFocus() { if (_fShowSnoop) { _pSnoopWnd->_Show(); }
return S_OK; }
//+---------------------------------------------------------------------------
//
// OnKillThreadFocus
//
// Called by the system when the thread/appartment of this text service loses
// the ui focus.
//----------------------------------------------------------------------------
STDAPI CCaseTextService::OnKillThreadFocus() { // only show our snoop window when our thread has the focus.
if (_fShowSnoop) { _pSnoopWnd->_Hide(); }
return S_OK; }
|