//
// tipbar.cpp
//

#include "private.h"
#include "globals.h"
#include <initguid.h>
#include "tipbar.h"
#include "helpers.h"
#include "xstring.h"
#include "commctrl.h"
#include "resource.h"
#include "inatlib.h"
#include "thdutil.h"
#include "catutil.h"
#include "immxutil.h"
#include "utbmenu.h"
#include "balloon.h"
#include "cregkey.h"
#include "cuimenu.h"
#include "cuishadw.h"
#include "cuischem.h"
#include "cmydc.h"
#include "intlmenu.h"
#include "utbtray.h"
#include "catenum.h"
#include "asynccal.h"
#include "fontlink.h"
#include "cresstr.h"
#include "nuiinat.h"
#include "tlapi.h"
#include "cuiutil.h"
#include "cuischem.h"
#include "cuitip.h"
#include "utbdlgs.h"
#include <shlapip.h>
#include "deskband.h"
#include "lmcons.h" // for UNLEN
#include "sddl.h"

#include "winuserp.h"

const DWORD TF_LBESF_GLOBAL = 0x0001;
const DWORD TF_LBSMI_FILTERCURRENTTHREAD = 0x0001;

extern HINSTANCE g_hInst;
const TCHAR c_szTipbarWndClass[] = TEXT("TipbarWndClass");
const TCHAR c_szTipbarWndName[] = TEXT("Cicload Tipbar");

const TCHAR c_szCicKey[]                  = TEXT("SOFTWARE\\Microsoft\\CTF\\");
const TCHAR c_szUTBKey[]                  = TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\");
const TCHAR c_szSkipRedrawHKL[]           = TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\SkipRedrawHKL");
const TCHAR c_szShowTipbar[]              = TEXT("ShowTipbar");
const TCHAR c_szDontShowCloseLangBarDlg[] = TEXT("DontShowCloseLangBarDlg");
const TCHAR c_szDontShowMinimizeLangBarDlg[] = TEXT("DontShowMinimizeLangBarDlg");
const TCHAR c_szShowDebugMenu[]           = TEXT("ShowDebugMenu");
const TCHAR c_szShowDeskBand[]            = TEXT("ShowDeskBand");
const TCHAR c_szNewLook[]                 = TEXT("NewLook");
const TCHAR c_szIntelliSense[]            = TEXT("IntelliSense");
const TCHAR c_szTimeOutNonIntentional[]   = TEXT("TimeOutNonIntentional");
const TCHAR c_szTimeOutIntentional[]      = TEXT("TimeOutIntentional");
const TCHAR c_szShowCloseMenu[]           = TEXT("ShowCloseMenu");
const TCHAR c_szShowMinimizedBalloon[]    = TEXT("ShowMinimizedBalloon");
const TCHAR c_szLeft[]                    = TEXT("Left");
const TCHAR c_szTop[]                     = TEXT("Top");
const TCHAR c_szExcludeCaptionButtons[]   = TEXT("ExcludeCaptionButtons");
const TCHAR c_szShowShadow[]              = TEXT("ShowShadow");
const TCHAR c_szTaskbarTheme[]            = TEXT("TaskbarTheme");
const TCHAR c_szVertical[]                = TEXT("Vertical");
// const TCHAR c_szMoveToTray[]              = TEXT("MoveToTray");

BOOL g_bNewLook                = TRUE;
BOOL g_bIntelliSense           = FALSE;
BOOL  g_bShowTipbar            = TRUE;
BOOL  g_bShowDebugMenu         = FALSE;
BOOL  g_bShowCloseMenu         = FALSE;
BOOL  g_bShowMinimizedBalloon  = TRUE;
BOOL  g_bExcludeCaptionButtons = TRUE;
BOOL  g_bShowShadow            = FALSE;
BOOL  g_bShowDeskBand          = FALSE;
BOOL  g_nLeft = -1;
BOOL  g_nTop  = -1;
DWORD g_dwWndStyle            = 0;
DWORD g_dwChildWndStyle       = 0;
DWORD g_dwMenuStyle           = 0;
CTipbarWnd *g_pTipbarWnd;
CTrayIconWnd *g_pTrayIconWnd;
HWND g_hwndParent;
BOOL g_bWinLogon = FALSE;
BOOL g_fTaskbarTheme = TRUE;
BOOL g_fVertical = FALSE;
BOOL g_fInClosePopupTipbar = FALSE;
BOOL g_fRTL = FALSE;

const TCHAR c_szTimerElapseSTUBSTART[]          = TEXT("TimerElapseSTUBSTART");
const TCHAR c_szTimerElapseSTUBEND[]            = TEXT("TimerElapseSTUBEND");
const TCHAR c_szTimerElapseBACKTOALPHA[]        = TEXT("TimerElapseBACKTOALPHA");
const TCHAR c_szTimerElapseONTHREADITEMCHANGE[] = TEXT("TimerElapseONTHREADITEMCHANGE");
const TCHAR c_szTimerElapseSETWINDOWPOS[]       = TEXT("TimerElapseSETWINDOWPOS");
const TCHAR c_szTimerElapseONUPDATECALLED[]     = TEXT("TimerElapseONUPDATECALLED");
const TCHAR c_szTimerElapseSYSCOLORCHANGED[]    = TEXT("TimerElapseSYSCOLORCHANGED");
const TCHAR c_szTimerElapseDISPLAYCHANGE[]      = TEXT("TimerElapseDISPLAYCHANGE");
const TCHAR c_szTimerElapseUPDATEUI[]           = TEXT("TimerElapseUPDATEUI");
const TCHAR c_szTimerElapseSHOWWINDOW[]         = TEXT("TimerElapseSHOWWINDOW");
const TCHAR c_szTimerElapseMOVETOTRAY[]         = TEXT("TimerElapseMOVETOTRAY");
const TCHAR c_szTimerElapseTRAYWNDONDELAYMSG[]  = TEXT("TimerElapseTRAYWNDONDELAYMSG");
const TCHAR c_szTimerElapseDOACCDEFAULTACTION[] = TEXT("TimerElapseDOACCDEFAULTACTION");
const TCHAR c_szTimerElapseENSUREFOCUS[]        = TEXT("TimerElapseENSUREFOCUS");
const TCHAR c_szTimerElapseSHOWDESKBAND[]       = TEXT("TimerElapseSHOWWDESKBAND");

UINT g_uTimerElapseSTUBSTART          = 100;
UINT g_uTimerElapseSTUBEND            = 2000;
UINT g_uTimerElapseBACKTOALPHA        = 3000;
UINT g_uTimerElapseONTHREADITEMCHANGE = 200;
UINT g_uTimerElapseSETWINDOWPOS       = 100;
UINT g_uTimerElapseONUPDATECALLED     = 50; // Satori tune up 20,50,100 or 200
UINT g_uTimerElapseSYSCOLORCHANGED    = 20;
UINT g_uTimerElapseDISPLAYCHANGE      = 20;
UINT g_uTimerElapseUPDATEUI           = 70; // MSIME2002 JP needs 70ms.
UINT g_uTimerElapseSHOWWINDOW         = 50;
UINT g_uTimerElapseMOVETOTRAY         = 50;
UINT g_uTimerElapseTRAYWNDONDELAYMSG  = 50;
UINT g_uTimerElapseDOACCDEFAULTACTION = 200;
UINT g_uTimerElapseENSUREFOCUS        = 50;
UINT g_uTimerElapseSHOWDESKBAND       = 3000;


//
// from bandobjs.cpp
//
extern UINT  g_wmTaskbarCreated;

//
// from itemlist.cpp
//
extern UINT g_uTimeOutNonIntentional;
extern UINT g_uTimeOutIntentional;
extern UINT g_uTimeOutMax;


//
// SkipRedrawing Hack HKL list.
//
CStructArray<HKL> *g_prghklSkipRedrawing = NULL;
void UninitSkipRedrawHKLArray();

#define WM_LBWND_SHOWCONTEXTMENU      (WM_USER + 1)

// TM_LANGUAGEBAND is defined in "shell\inc\trayp.h"
#define TM_LANGUAGEBAND     WM_USER+0x105

/* 142b6d42-955d-4488-97c0-b23b23e6b048 */
const IID IID_PRIV_BUTTONITEM = { 
    0x142b6d42,
    0x955d,
    0x4488,
    {0x97, 0xc0, 0xb2, 0x3b, 0x23, 0xe6, 0xb0, 0x48}
  };

/* 8dd1cc81-fca0-4dd5-b848-2b85732d2fc4 */
const IID IID_PRIV_BITMAPBUTTONITEM = { 
    0x8dd1cc81,
    0xfca0,
    0x4dd5,
    {0xb8, 0x48, 0x2b, 0x85, 0x73, 0x2d, 0x2f, 0xc4}
  };

/* 36b40e05-7b3e-4a4a-bda7-2249ba17d3c4 */
const IID IID_PRIV_BITMAPITEM = { 
    0x36b40e05,
    0x7b3e,
    0x4a4a,
    {0xbd, 0xa7, 0x22, 0x49, 0xba, 0x17, 0xd3, 0xc4}
  };

/* 68831a74-6f86-447a-b2b8-634250ac445e */
const IID IID_PRIV_BALLOONITEM = { 
    0x68831a74,
    0x6f86,
    0x447a,
    {0xb2, 0xb8, 0x63, 0x42, 0x50, 0xac, 0x44, 0x5e}
  };

//
// from MSCTF.DLL.
//
extern "C" BOOL WINAPI TF_IsFullScreenWindowAcitvated();
extern "C" DWORD WINAPI TF_CheckThreadInputIdle(DWORD dwThreadId, DWORD dwTimeOut);

//
// from intlmenu.cpp
//
extern BOOL IsFELangId(LANGID langid);

//////////////////////////////////////////////////////////////////////////////
//
// predefined control buttons
//
//////////////////////////////////////////////////////////////////////////////

static CTRLBTNMAP g_cbCtrlBtn[NUM_CTRLBUTTONS] = {
   {ID_CBTN_CAPSKEY,  UIBUTTON_CENTER | UIBUTTON_VCENTER | UIBUTTON_TOGGLE, 
    0, 0, CTRL_ICONFROMRES | CTRL_TOGGLEBUTTON, {0x0, 0x0}},
   {ID_CBTN_KANAKEY,  UIBUTTON_CENTER | UIBUTTON_VCENTER | UIBUTTON_TOGGLE,
    0, 1, CTRL_ICONFROMRES | CTRL_TOGGLEBUTTON, {0x0, 0x0}},
   {ID_CBTN_MINIMIZE, UIBUTTON_CENTER | UIBUTTON_VCENTER,  
    1, 0, CTRL_USEMARLETT | CTRL_DISABLEONWINLOGON, {0x0030, 0x0000}},
   {ID_CBTN_EXTMENU,  UIBUTTON_CENTER | UIBUTTON_VCENTER,  
    1, 1, CTRL_USEMARLETT | CTRL_DISABLEONWINLOGON, {0x0075, 0x0000}},
   };

static CTRLBTNMAP g_cbCtrlBtnDeskBand[NUM_CTRLBUTTONS] = {
   {ID_CBTN_CAPSKEY,  UIBUTTON_CENTER | UIBUTTON_VCENTER | UIBUTTON_TOGGLE, 
    0, 0, CTRL_ICONFROMRES | CTRL_TOGGLEBUTTON, {0x0, 0x0}},
   {ID_CBTN_KANAKEY,  UIBUTTON_CENTER | UIBUTTON_VCENTER | UIBUTTON_TOGGLE,
    0, 1, CTRL_ICONFROMRES | CTRL_TOGGLEBUTTON, {0x0, 0x0}},
   {ID_CBTN_RESTORE, UIBUTTON_CENTER | UIBUTTON_VCENTER,  
    1, 0, CTRL_USEMARLETT | CTRL_DISABLEONWINLOGON, {0x0032, 0x0000}},
   {ID_CBTN_EXTMENU,  UIBUTTON_CENTER | UIBUTTON_VCENTER,  
    1, 1, CTRL_USEMARLETT | CTRL_DISABLEONWINLOGON, {0x0075, 0x0000}},
   };

static int c_nColumnStart[] = {0, CX_COLUMN0, CX_COLUMN1};

    

//////////////////////////////////////////////////////////////////////////////
//
// APIs
//
//////////////////////////////////////////////////////////////////////////////

extern "C" BOOL WINAPI GetPopupTipbar(HWND hwndParent, DWORD dwFlags)
{
    if ( !(dwFlags & UTB_GTI_WINLOGON) )
    {
        TurnOffSpeechIfItsOn( );
    }

    return GetTipbarInternal(hwndParent, UTB_GTI_POPUP | dwFlags, NULL);
}

BOOL GetTipbarInternal(HWND hwndParent, DWORD dwFlags, CDeskBand *pDeskBand)
{
    DWORD dwSFSFlags;
    BOOL fPopup = (dwFlags & UTB_GTI_POPUP) ? TRUE : FALSE;

    g_bWinLogon = (dwFlags & UTB_GTI_WINLOGON) ? TRUE : FALSE;

    //
    // MSAA support
    //
    InitTipbarAcc();

    InitFromReg();

    if (!g_bShowTipbar)
        return NULL;

    //
    // we don't have to create TrayIconWnd under explorer's desk band.
    //
    if (fPopup)
    {
        g_pTrayIconWnd = new CTrayIconWnd();
        if (!g_pTrayIconWnd)
            return FALSE;

        g_pTrayIconWnd->CreateWnd();
    }

    g_pTipbarWnd = new CTipbarWnd(fPopup ? g_dwWndStyle : g_dwChildWndStyle);
    if (!g_pTipbarWnd)
        return FALSE;

    if (!g_pTipbarWnd->Initialize())
        return FALSE;

    g_pTipbarWnd->Init(!fPopup, pDeskBand);


    g_pTipbarWnd->CreateWnd(hwndParent);
    SetWindowText(g_pTipbarWnd->GetWnd(), TF_FLOATINGLANGBAR_WNDTITLE);

    DWORD dwPrevFlags = 0;
    if (!fPopup)
    {
        g_pTipbarWnd->GetLangBarMgr()->GetPrevShowFloatingStatus(&dwPrevFlags);

        g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_DESKBAND);
    }

    g_pTipbarWnd->GetLangBarMgr()->GetShowFloatingStatus(&dwSFSFlags);
    g_pTipbarWnd->ShowFloating(dwSFSFlags);

    //
    // get the previous show floating status.
    // if it does not have TF_SFT_DESKBAND, the floating toolbar
    // was minimized.
    // if it has TF_SFT_DESKBAND, exploere just started. Then we don't
    // want to adjust the deskband and use the default size.
    // (Explorer remembers the position of the previous logon.)
    //
    if (!fPopup && (dwPrevFlags & TF_SFT_DESKBAND))
        g_pTipbarWnd->SetDeskbandSizeAdjusted();

    g_hwndParent = hwndParent;

    return TRUE;
}

extern "C" void WINAPI ClosePopupTipbar()
{
    if (g_fInClosePopupTipbar)
        return;

    g_fInClosePopupTipbar = TRUE;

    if (g_pTipbarWnd)
    {
        g_pTipbarWnd->ClearDeskBandPointer();
        g_pTipbarWnd->DestroyWnd();
        g_pTipbarWnd->Release();
        g_pTipbarWnd = NULL;
    }

    if (g_pTrayIconWnd)
    {
        g_pTrayIconWnd->DestroyWnd();
        delete g_pTrayIconWnd;
        g_pTrayIconWnd = NULL;
    }

    UninitSkipRedrawHKLArray();

    g_fInClosePopupTipbar = FALSE;
}

//////////////////////////////////////////////////////////////////////////////
//
// misc func
//
//////////////////////////////////////////////////////////////////////////////


extern "C" HRESULT WINAPI TF_GetGlobalCompartment(ITfCompartmentMgr **pCompMgr);

//+---------------------------------------------------------------------------
//
//  GetCompartment
//
//----------------------------------------------------------------------------

HRESULT GetGlobalCompartment(REFGUID rguidComp, ITfCompartment **ppComp)
{
    HRESULT hr = E_FAIL;
    ITfCompartmentMgr *pCompMgr = NULL;

    if (FAILED(hr = TF_GetGlobalCompartment(&pCompMgr)))
    {
         Assert(0);
         goto Exit;
    }

    if (SUCCEEDED(hr) && pCompMgr)
    {
        hr = pCompMgr->GetCompartment(rguidComp, ppComp);
        pCompMgr->Release();
    }
    else
        hr = E_FAIL;

Exit:
    return hr;
}


//+---------------------------------------------------------------------------
//
//  SetCompartmentDWORD
//
//----------------------------------------------------------------------------

HRESULT SetGlobalCompartmentDWORD(REFGUID rguidComp, DWORD dw)
{
    HRESULT hr;
    ITfCompartment *pComp;
    VARIANT var;

    if (SUCCEEDED(hr = GetGlobalCompartment(rguidComp, &pComp)))
    {
        var.vt = VT_I4;
        var.lVal = dw;
        hr = pComp->SetValue(0, &var);
        pComp->Release();
    }
    return hr;
}


//+---------------------------------------------------------------------------
//
//  GetGlobalCompartmentDWORD
//
//----------------------------------------------------------------------------

HRESULT GetGlobalCompartmentDWORD(REFGUID rguidComp, DWORD *pdw)
{
    HRESULT hr;
    ITfCompartment *pComp;
    VARIANT var;

    *pdw = 0;
    if (SUCCEEDED(hr = GetGlobalCompartment(rguidComp, &pComp)))
    {
        if ((hr = pComp->GetValue(&var)) == S_OK)
        {
            Assert(var.vt == VT_I4);
            *pdw = var.lVal;
        }
        pComp->Release();
    }

    return hr;
}

//+---------------------------------------------------------------------------
//
//  TurnOffSpeechIfItsOn
//
//----------------------------------------------------------------------------
void  TurnOffSpeechIfItsOn()
{
    // turn off the mic here only if someone set speech on
    DWORD dw = 0; 
    HRESULT hr = GetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, &dw);
    if (SUCCEEDED(hr) && dw > 0)
    {
        SetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0);
    }
}

//+---------------------------------------------------------------------------
//
// InitSkipRedrawHKLArray
//
//+---------------------------------------------------------------------------

void InitSkipRedrawHKLArray()
{
    CMyRegKey key;
    HKL *phkl;

    Assert(!g_prghklSkipRedrawing);
    g_prghklSkipRedrawing = new CStructArray<HKL>;
    if (!g_prghklSkipRedrawing)
        return;

    if (IsOnNT51())
    {
        phkl = g_prghklSkipRedrawing->Append(1);
        if (phkl)
            *phkl = (HKL)IntToPtr(0xe0010411);
    }

    if (key.Open(HKEY_LOCAL_MACHINE, c_szSkipRedrawHKL, KEY_READ) == S_OK)
    {
        char szValue[255];
        DWORD dwIndex = 0;
        while (key.EnumValue(dwIndex, szValue, ARRAYSIZE(szValue)) == S_OK)
        {
            if ((szValue[0] == '0') && 
                ((szValue[1] == 'X') || (szValue[1] == 'x')))
            {
                phkl = g_prghklSkipRedrawing->Append(1);
                if (phkl)
                    *phkl = (HKL)IntToPtr(AsciiToNum(&szValue[2]));
            }
            dwIndex++;
        }
    }
}

//+---------------------------------------------------------------------------
//
// UninitSkipRedrawHKLArray
//
//+---------------------------------------------------------------------------

void UninitSkipRedrawHKLArray()
{
    if (!g_prghklSkipRedrawing)
        return;

    delete g_prghklSkipRedrawing;
    g_prghklSkipRedrawing = NULL;
}

//+---------------------------------------------------------------------------
//
// IsSkipRedrawHKL
//
//+---------------------------------------------------------------------------

BOOL IsSkipRedrawHKL(HKL hkl)
{
    int i;

    if (0x0411 != LANGID(LOWORD(HandleToLong(hkl))))
        return FALSE;

    if (!g_prghklSkipRedrawing)
        return FALSE;

    for (i = 0; i < g_prghklSkipRedrawing->Count(); i++)
    {
        HKL *phkl = g_prghklSkipRedrawing->GetPtr(i);
        if (phkl && (*phkl == hkl))
            return TRUE;
    }

    return FALSE;
}


//+---------------------------------------------------------------------------
//
// InitFromReg
//
//+---------------------------------------------------------------------------

BOOL InitFromReg()
{
    CMyRegKey key;
    CMyRegKey keyUTB;
    DWORD dwValue;
    LANGID langID = 0;

    if (key.Open(HKEY_CURRENT_USER, c_szCicKey, KEY_READ) == S_OK)
    {
        if (key.QueryValue(dwValue, c_szShowTipbar) == S_OK)
            g_bShowTipbar = dwValue ? TRUE : FALSE;
    }

    if (keyUTB.Open(HKEY_CURRENT_USER, c_szUTBKey, KEY_READ) == S_OK)
    {
        if (keyUTB.QueryValue(dwValue, c_szShowDebugMenu) == S_OK)
            g_bShowDebugMenu = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szNewLook) == S_OK)
            g_bNewLook = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szIntelliSense) == S_OK)
            g_bIntelliSense = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szShowCloseMenu) == S_OK)
            g_bShowCloseMenu = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szTimeOutNonIntentional) == S_OK)
            g_uTimeOutNonIntentional = dwValue * 1000;

        if (keyUTB.QueryValue(dwValue, c_szTimeOutIntentional) == S_OK)
        {
            g_uTimeOutIntentional = dwValue * 1000;
            g_uTimeOutMax = g_uTimeOutIntentional * 6;
        }

        if (keyUTB.QueryValue(dwValue, c_szShowMinimizedBalloon) == S_OK)
            g_bShowMinimizedBalloon = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szLeft) == S_OK)
            g_nLeft = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTop) == S_OK)
            g_nTop = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szExcludeCaptionButtons) == S_OK)
            g_bExcludeCaptionButtons = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szShowShadow) == S_OK)
            g_bShowShadow = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szTaskbarTheme) == S_OK)
            g_fTaskbarTheme = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szVertical) == S_OK)
            g_fVertical = dwValue ? TRUE : FALSE;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseSTUBSTART) == S_OK)
            g_uTimerElapseSTUBSTART          = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseSTUBEND) == S_OK)
            g_uTimerElapseSTUBEND            = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseBACKTOALPHA) == S_OK)
            g_uTimerElapseBACKTOALPHA        = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseONTHREADITEMCHANGE) == S_OK)
            g_uTimerElapseONTHREADITEMCHANGE = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseSETWINDOWPOS) == S_OK)
            g_uTimerElapseSETWINDOWPOS       = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseONUPDATECALLED) == S_OK)
            g_uTimerElapseONUPDATECALLED     = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseSYSCOLORCHANGED) == S_OK)
            g_uTimerElapseSYSCOLORCHANGED    = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseDISPLAYCHANGE) == S_OK)
            g_uTimerElapseDISPLAYCHANGE      = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseUPDATEUI) == S_OK)
            g_uTimerElapseUPDATEUI           = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseSHOWWINDOW) == S_OK)
            g_uTimerElapseSHOWWINDOW           = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseMOVETOTRAY) == S_OK)
            g_uTimerElapseMOVETOTRAY           = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseTRAYWNDONDELAYMSG) == S_OK)
            g_uTimerElapseTRAYWNDONDELAYMSG           = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseDOACCDEFAULTACTION) == S_OK)
            g_uTimerElapseDOACCDEFAULTACTION           = dwValue;

        if (keyUTB.QueryValue(dwValue, c_szTimerElapseENSUREFOCUS) == S_OK)
            g_uTimerElapseENSUREFOCUS           = dwValue;

        if (IsOnNT51() && keyUTB.QueryValue(dwValue, c_szShowDeskBand) == S_OK)
            g_bShowDeskBand = dwValue ? TRUE : FALSE;

        if (IsOnNT51() && keyUTB.QueryValue(dwValue, c_szTimerElapseSHOWDESKBAND) == S_OK)
            g_uTimerElapseSHOWDESKBAND          = dwValue;
    }


    InitSkipRedrawHKLArray();
 
    if (g_bNewLook)
    {
        g_dwWndStyle = UIWINDOW_TOPMOST | 
                       // UIWINDOW_WSDLGFRAME | 
                       UIWINDOW_HASTOOLTIP | 
                       UIWINDOW_HABITATINWORKAREA | 
                       UIWINDOW_OFC10TOOLBAR |
                       UIWINDOW_TOOLWINDOW;

        if (IsOnNT51())
        {
            g_dwWndStyle &= ~UIWINDOW_OFC10TOOLBAR;
            g_dwWndStyle |= UIWINDOW_WHISTLERLOOK;
            // g_dwWndStyle |= UIWINDOW_WSBORDER;
        }

        if (g_bShowShadow)
            g_dwWndStyle |= UIWINDOW_HASSHADOW;

        g_dwMenuStyle = UIWINDOW_TOPMOST | 
                        UIWINDOW_TOOLWINDOW | 
                        UIWINDOW_OFC10MENU |
                        UIWINDOW_HASSHADOW |
                        UIWINDOW_HABITATINSCREEN;
    }
    else
    {
        g_dwWndStyle = UIWINDOW_TOPMOST | 
                       UIWINDOW_HASTOOLTIP | 
                       UIWINDOW_WSDLGFRAME |
                       UIWINDOW_HABITATINWORKAREA;
        g_dwMenuStyle = UIWINDOW_TOPMOST | 
                        UIWINDOW_WSDLGFRAME |
                        UIWINDOW_HABITATINSCREEN;
    }

    g_dwChildWndStyle = UIWINDOW_CHILDWND;

    if (IsOnNT51())
    {
        g_dwChildWndStyle |= UIWINDOW_WHISTLERLOOK | 
                             UIWINDOW_HASTOOLTIP |
                             UIWINDOW_NOMOUSEMSGFROMSETCURSOR;
    }

    langID = GetPlatformResourceLangID();
    if (PRIMARYLANGID(langID) == LANG_ARABIC || PRIMARYLANGID(langID) == LANG_HEBREW)
    {
        g_dwWndStyle |= UIWINDOW_LAYOUTRTL;
        g_dwChildWndStyle |= UIWINDOW_LAYOUTRTL;
        g_dwMenuStyle |= UIWINDOW_LAYOUTRTL;
        g_fRTL = TRUE;
    }

    return TRUE;
}

//+---------------------------------------------------------------------------
//
// GetTopLevelWindow
//
//+---------------------------------------------------------------------------

HWND GetTopLevelWindow(HWND hwnd)
{
    HWND hwndT,hwndRet;
    HWND hwndDsktop = GetDesktopWindow();

    hwndT = hwndRet = hwnd;

    while (hwndT && hwndT != hwndDsktop)
    {
        HWND hwndT0;
        hwndRet = hwndT;
        hwndT0 = GetParent(hwndT);

        if (IsOn98() && !hwndT0)
        {
            //
            // GetLastActivePopup() returns hwnd->hwndLastActive.
            // But top level owner's hwndLastActive is used.
            // We need to find a top level owner.
            //
            hwndT0 = GetWindow(hwndT, GW_OWNER);
        }
        hwndT = hwndT0;
    }

    return(hwndRet);
}

//+---------------------------------------------------------------------------
//
// MyWaitForInputIdle
//
//+---------------------------------------------------------------------------

#define UTB_INPUTIDLETIMEOUT 2000

DWORD MyWaitForInputIdle(DWORD dwThreadId, DWORD dwTimeOut)
{
    DWORD dwRet = -1;
    DWORD dwProcessId = 0;
    DWORD dwThreadFlags;

    if (g_pTipbarWnd && g_pTipbarWnd->IsSFDeskband())
    {
        //
        //  Skip it on the Deskband that is belong to Explorer process.
        //
        return 0;
    }

    //
    // If the target thread is in marshaling call, we can behave as it's busy.
    //
    if (TF_IsInMarshaling(dwThreadId))
        return WAIT_TIMEOUT;

    if (TF_GetThreadFlags(dwThreadId, &dwThreadFlags, &dwProcessId, NULL) && dwProcessId)
    {
        dwRet = 0;

        if (IsOnNT() && 
            Is16bitThread(dwProcessId, dwThreadId))
        {
            //
            // we need to do something here to detect 16bit idle.
            //
        }
        else if (IsOnNT() || !(dwThreadFlags & TLF_NOWAITFORINPUTIDLEONWIN9X))
        {
#if 0
            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 
                                      FALSE, dwProcessId);
            if (hProcess)
            {
                dwRet = WaitForInputIdle(hProcess, dwTimeOut);
                CloseHandle(hProcess);
            }
            else
                dwRet = -1;
#else
            dwRet = TF_CheckThreadInputIdle(dwThreadId, dwTimeOut);
#endif
        }
    }

    return dwRet;
}

//+---------------------------------------------------------------------------
//
// ClearMsgQueue
//
//+---------------------------------------------------------------------------

void ClearMsgQueue()
{
    MSG msg;
    ULONG ulQuitCode;
    BOOL fQuitReceived = FALSE;
    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD))
    {
        if (msg.message == WM_QUIT)
        {
            ulQuitCode = (ULONG)(msg.wParam);
            fQuitReceived = TRUE;
        }

        DispatchMessage(&msg);
    }

    if (fQuitReceived)
        PostQuitMessage(ulQuitCode);
   
}

//+---------------------------------------------------------------------------
//
// IsFullScreenSize
//
//+---------------------------------------------------------------------------

BOOL IsFullScreenSize(HWND hwnd)
{
    RECT rc;
    GetWindowRect(hwnd, &rc);
    if ((rc.left <= 0) &&
        (rc.top <= 0)&&
        (rc.right >= GetSystemMetrics(SM_CXFULLSCREEN)) &&
        (rc.bottom >= GetSystemMetrics(SM_CYFULLSCREEN)))
    {
        return TRUE;
    }
    return FALSE;
}


//+---------------------------------------------------------------------------
//
// InitUniqueString
//
//----------------------------------------------------------------------------

BOOL GetUserSIDString(DWORD dwProcessId, char *pch, UINT cch)
{
    HANDLE hToken = NULL;
    char *pszStringSid = NULL;
    HANDLE hProcess;

    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);

    if (hProcess)
        OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);

    if (hToken)
    {
        DWORD dwReturnLength = 0;
        void  *pvUserBuffer = NULL;

        GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength);

        pvUserBuffer = cicMemAllocClear(dwReturnLength);
        if (pvUserBuffer &&
            GetTokenInformation(hToken,
                                 TokenUser,
                                 pvUserBuffer,
                                 dwReturnLength,
                                 &dwReturnLength))
        {
            if (!ConvertSidToStringSid(((TOKEN_USER*)(pvUserBuffer))->User.Sid,
                                       &pszStringSid))
            {
                if (pszStringSid)
                    LocalFree(pszStringSid);

                pszStringSid = NULL;
            }

        }

        if (pvUserBuffer)
        {
            cicMemFree(pvUserBuffer);
        }

        CloseHandle(hToken);
    }

    if (hProcess)
        CloseHandle(hProcess);

    if (pszStringSid)
    {
        StringCchCopy(pch, cch, pszStringSid);
        LocalFree(pszStringSid);
        return TRUE;
    }

    *pch = '\0';
    return FALSE;
}

//+---------------------------------------------------------------------------
//
// InitCurrentProcessSid
//
//+---------------------------------------------------------------------------

BOOL g_fSidInit = FALSE;
char g_szSid[UNLEN + 1];

BOOL InitCurrentProcessSid()
{
    if (g_fSidInit)
        return TRUE;

    if (GetUserSIDString(GetCurrentProcessId(), g_szSid, ARRAYSIZE(g_szSid)))
        g_fSidInit = TRUE;

    return g_fSidInit;
}


//+---------------------------------------------------------------------------
//
// IsVisibleWindowInDesktop()
//
//+---------------------------------------------------------------------------

BOOL CALLBACK EnumVisibleWindowProc(HWND hwnd, LPARAM lParam)
{
    DWORD dwProcessId;

    if (!GetWindowThreadProcessId(hwnd, &dwProcessId))
        dwProcessId = 0;

    //
    // we're not interested in ctfmon's process window.
    //
    if (g_pTipbarWnd && !g_pTipbarWnd->IsInDeskBand())
        if (dwProcessId == GetCurrentProcessId())
            return TRUE;

    if (IsWindowVisible(hwnd))
    {
        if (g_fSidInit)
        {
            // 
            // if the process is owned by different user, we skip it.
            // 
            char szSid[UNLEN + 1];
            GetUserSIDString(dwProcessId, szSid, ARRAYSIZE(szSid));
            if (lstrcmp(szSid, g_szSid))
                return TRUE;
        }

        BOOL *pfFound = (BOOL *)lParam;
        *pfFound = TRUE;
        return FALSE;
    }

    return TRUE;
}

BOOL IsVisibleWindowInDesktop()
{
    BOOL fFound = FALSE;

    InitCurrentProcessSid();
    EnumWindows(EnumVisibleWindowProc, (LPARAM)&fFound);
    return fFound;
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarGripper
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// CTipbarGripper::ctor
//
//----------------------------------------------------------------------------

CTipbarGripper::CTipbarGripper(CTipbarWnd *pTipbarWnd, RECT *prc, DWORD dwStyle) : CUIFGripper( pTipbarWnd, prc, dwStyle) 
{
    _pTipbarWnd = pTipbarWnd;
    _fInMenu = FALSE;
}

//+---------------------------------------------------------------------------
//
// CTipbarGripper::OnSetCursor
//
//----------------------------------------------------------------------------

BOOL CTipbarGripper::OnSetCursor(UINT uMsg, POINT pt)
{
    if (!_fInMenu)
        return CUIFGripper::OnSetCursor(uMsg, pt);

    return FALSE;
}

//+---------------------------------------------------------------------------
//
// CTipbarGripper::OnRButtonUp
//
//----------------------------------------------------------------------------

void CTipbarGripper::OnRButtonUp(POINT pt)
{
    if (!g_bShowDebugMenu)
        return;

    HMENU hMenu = CreatePopupMenu();
    if (!hMenu)
        return;

    SetCursor(LoadCursor(NULL, IDC_ARROW));

    ClientToScreen(_pTipbarWnd->GetWnd(), &pt);


    InsertMenu(hMenu, -1, MF_BYPOSITION | MF_STRING, IDM_CLOSECICLOAD, "Close cicload");

#ifdef DEBUG
    InsertMenu(hMenu, -1, MF_BYPOSITION | MF_STRING, IDM_BREAK, CRStr(IDS_BREAK));
#endif
    InsertMenu(hMenu, -1, MF_BYPOSITION | MF_STRING, IDCANCEL, CRStr(IDS_CANCEL));

    _fInMenu = TRUE;
    int nRet = TrackPopupMenuEx(hMenu,
                         TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
                         pt.x, pt.y, _pTipbarWnd->GetWnd(), NULL);
    _fInMenu = FALSE;

    DestroyMenu(hMenu);

    switch (nRet)
    {
        case IDM_CLOSECICLOAD:
            {
                _pTipbarWnd->UnInit();
                if (IsWindow(g_hwndParent))
                    DestroyWindow(g_hwndParent);
                MSG msg;
                while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE | PM_NOYIELD));
                PostQuitMessage(0);
            }
            break;

#ifdef DEBUG
        case IDM_BREAK:
            DebugBreak();
            break;
#endif
    }

}

//+---------------------------------------------------------------------------
//
// CTipbarGripper::OnLButtonUp
//
//----------------------------------------------------------------------------

void CTipbarGripper::OnLButtonUp(POINT pt)
{
    _pTipbarWnd->RestoreFromStub();

    //
    // Mouse Drag/Drop from floating language bar to deskband.
    //
    if (IsOnNT51())
    {
        APPBARDATA abd;
        RECT rcTrayWnd;

        abd.cbSize = sizeof(APPBARDATA);

        abd.hWnd = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);

        if (SHAppBarMessage(ABM_GETTASKBARPOS, &abd))
        {
            POINT ptCursor;

            rcTrayWnd = abd.rc;

            GetCursorPos(&ptCursor);

            if ((ptCursor.x >= rcTrayWnd.left && ptCursor.x <= rcTrayWnd.right) &&
                (ptCursor.y >= rcTrayWnd.top && ptCursor.y <= rcTrayWnd.bottom))
            {
                if (g_pTipbarWnd)
                    g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_DESKBAND |
                                                                TF_SFT_EXTRAICONSONMINIMIZED);

            }
        }
    }

    CUIFGripper::OnLButtonUp(pt);

    //
    // CUIFGripper::OnLButonUp() calls MoveWindow.
    // Now we update pos flags of TipbarWnd.
    //
    _pTipbarWnd->UpdatePosFlags();
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarWnd
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// IUnknown
//
//----------------------------------------------------------------------------

STDAPI CTipbarWnd::QueryInterface(REFIID riid, void **ppvObj)
{
    *ppvObj = NULL;

    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_ITfLangBarEventSink))
    {
        *ppvObj = SAFECAST(this, ITfLangBarEventSink *);
    }
    else if (IsEqualIID(riid, IID_ITfLangBarEventSink_P))
    {
        *ppvObj = SAFECAST(this, ITfLangBarEventSink_P *);
    }

    if (*ppvObj)
    {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

STDAPI_(ULONG) CTipbarWnd::AddRef()
{
    return ++_cRef;
}

STDAPI_(ULONG) CTipbarWnd::Release()
{
    _cRef--;
    Assert(_cRef >= 0);

    if (_cRef == 0)
    {
        delete this;
        return 0;
    }

    return _cRef;
}

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarWnd::CTipbarWnd(DWORD dwStyle) : CUIFWindow(g_hInst, dwStyle)
{
    Dbg_MemSetThisName(TEXT("CTipbarWnd"));
    POINT pt;
    RECT rc;

    pt.x = g_nLeft;
    pt.y = g_nTop;
    CUIGetScreenRect(pt, &rc);
    if (!PtInRect(&rc, pt))
    {
         if (IsOnFE())
         {
             RECT rcWork;
             SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
             g_nLeft = rcWork.right;
             g_nTop  = rcWork.bottom;
         }
         else if (g_fRTL)
         {
             g_nLeft = GetSystemMetrics(SM_CXSIZE) * 3;
             g_nTop  = 0;
         }
         else
         {
             g_nLeft = GetSystemMetrics(SM_CXSCREEN) - (GetSystemMetrics(SM_CXSIZE) * 3);
             g_nTop  = 0;
         }
    }
   
    Move(g_nLeft, g_nTop, STATUSWND_WIDTH, STATUSWND_HEIGHT);

    //
    // initialize Pos flags after calling Move().
    //
    UpdatePosFlags();

    _fShowText = FALSE;
    _fInStub = FALSE;

    _hfontMarlett = CreateFont(8, 8, 0, 0, 400, FALSE, FALSE, FALSE, SYMBOL_CHARSET, 0, 0, 0, 0, "Marlett");

    ITfLangBarMgr *putb;
    if (SUCCEEDED(TF_CreateLangBarMgr(&putb)) && putb)
    {
        putb->QueryInterface(IID_ITfLangBarMgr_P, (void **)&_putb);

        putb->Release();
    }
   

    if (dwStyle & UIWINDOW_WHISTLERLOOK)
    {
        if (g_fTaskbarTheme)
            SetActiveTheme(L"TASKBAR", TBP_BACKGROUNDBOTTOM, TS_NORMAL );
        else
            SetActiveTheme(L"REBAR", 0, TS_NORMAL );
    }

    SetVertical(g_fVertical);

    _cRef = 1;
}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarWnd::~CTipbarWnd()
{
    Assert(!_pModalMenu);

    UnInit();

    DeleteObject(_hfontMarlett);
    if (_hfontVert)
        DeleteObject(_hfontVert);

    TFUninitLib_Thread(&g_libTLS);
}

//+---------------------------------------------------------------------------
//
// UnInit
//
//----------------------------------------------------------------------------

void CTipbarWnd::UnInit()
{
    SetFocusThread(NULL);

    int i;
    for (i = 0; i < _rgThread.Count(); i++)
    {
        CTipbarThread *pThread = _rgThread.Get(i);
        if (!pThread)
            continue;

        pThread->_UninitItemList(TRUE);
        pThread->Disconnect();
        pThread->_Release();
    }
    _rgThread.Clear();

    if (_putb)
        _putb->UnadviseEventSink(_dwlbimCookie);

    SafeReleaseClear(_putb);
}

//+---------------------------------------------------------------------------
//
// SetFocus
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::OnSetFocus(DWORD dwThreadId)
{
    BOOL fNewThread = FALSE;
    CTipbarThread *pThread;
    CTipbarThread *pPrevFocusThread;
    BOOL fWasInFullScreen = _fInFullScreen;
    HWND hwndFore = GetForegroundWindow();
    DWORD dwThreadIdFore = GetWindowThreadProcessId(hwndFore, NULL);
    HRESULT hr;
    CTipbarThread *pThreadPrev = NULL;
    BOOL fSkipRedrawOnNoItem = FALSE;

    TraceMsg(TF_FUNC, "focusnfy OnSetFocus %x ", dwThreadId);

    //
    // if the toolbar is being terminated, do nothing.
    //
    if (_fTerminating)
        return S_OK;

    if (_dwThreadIdWaitNotify && (_dwThreadIdWaitNotify != dwThreadId))
        return S_OK;
    //
    // If this MSUTB is in ctfmon.exe and the langbar status is in Deskband,
    // this meutb should stop wroking.
    //
    if (!_fInDeskBand && IsSFDeskband())
        return S_OK;

    if (!IsWindow(GetWnd()))
        return E_FAIL;

    StartPendingUpdateUI();
    AddRef();

    if (!_fInDeskBand && dwThreadIdFore)
    {
        BOOL fScreenSaverRunning = FALSE;

        if (IsOnNT5() || IsOn98())
        {
            SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0,
                                 &fScreenSaverRunning, FALSE);
        }

        if (IsFullScreenWindow(hwndFore) || fScreenSaverRunning)
        {
            if (GetWindowLongPtr(GetWnd(), GWL_STYLE) & WS_VISIBLE)
            {
                Show(FALSE);
                _fInFullScreen = TRUE;
                _dwPrevTBStatus = _dwSFTFlags;
            }
        }
        else if (fWasInFullScreen)
        {
            Show(TRUE);
            _fInFullScreen = FALSE;

            //
            // Bug#500507 - Need to recover language bar show status value.
            //
            if (!(_dwPrevTBStatus & TF_SFT_DESKBAND))
                GetLangBarMgr()->ShowFloating(_dwPrevTBStatus);
        }
    }

    KillTimer(TIPWND_TIMER_SETWINDOWPOS);
    SetTimer(TIPWND_TIMER_SETWINDOWPOS, g_uTimerElapseSETWINDOWPOS);

    pThread = _FindThread(dwThreadId);
    if (_pFocusThread && (pThread == _pFocusThread))
    {
        hr = S_OK;
        goto Exit;
    }

    //
    // keep the current focus thread.
    //
    pPrevFocusThread = _pFocusThread;

    CancelMenu();

    if (!pThread)
    {
        pThread = _CreateThread(dwThreadId);
        if (!pThread)
        {
            hr = E_FAIL;
            goto Exit;
        }

        fNewThread = TRUE;
    }

    //
    // focus has been change during creating pThread.
    // we don't have to do anything now.
    //
    if (_pFocusThread && (pPrevFocusThread != _pFocusThread))
    {
        hr = S_OK;
        goto Exit;
    }

    if (_pFocusThread)
    {
        _pFocusThread->RemoveUIObjs();
    }

    SetFocusThread(pThread);

    if (pThread)
    {
        Assert(pThread == _pFocusThread);
        BOOL fItemChanged = pThread->_fItemChanged;

        //
        // addref to increment the refcount.
        //
        pThread->_AddRef();

        hr = S_OK;
        if (fItemChanged)
            hr = pThread->_UninitItemList(TRUE);

        if (SUCCEEDED(hr))
        {
            pThread->RemoveUIObjs();

            if (fItemChanged)
                pThread->InitItemList();
        }

        //
        // UninitItemList and InitItemList make marshaling calls.
        // we need to check _pFocusThread again.
        //
        if (pThread == _pFocusThread)
        {
            pThread->LocateItems();
            pThread->AddUIObjs();

            if (fNewThread || fItemChanged)
            {
                if (!pThread->UpdateItems())
                {
                    pThread->RemoveUIObjs();
                    SetFocusThread(NULL);
                }
            }
            else if (pThread->IsDirtyItem())
            {
                //
                // this thread has a update dirty item. Need to update now.
                // We got OnUpdate call while it was background thread.
                //
                KillTimer(TIPWND_TIMER_ONUPDATECALLED);
                SetTimer(TIPWND_TIMER_ONUPDATECALLED, g_uTimerElapseONUPDATECALLED);
            }
        }

        fSkipRedrawOnNoItem = pThread->_fSkipRedrawOnNoItem;
        //
        // release to decrement the refcount.
        //
        pThread->_Release();
    }

    _ctrlbtnHolder.EnableBtns();

    if (_fShowTrayIcon)
    {
       KillTimer(TIPWND_TIMER_MOVETOTRAY);
       SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
    }

    //
    // Cic#4712
    //
    if (_dwThreadItemChangedForTimer != dwThreadId)
    {
        KillOnTheadItemChangeTimer();
    }

    hr = S_OK;

Exit:
    if (fSkipRedrawOnNoItem)
        KillTimer(TIPWND_TIMER_UPDATEUI);

    EndPendingUpdateUI();
    Release();
    return hr;
}

//+---------------------------------------------------------------------------
//
// IsFullScreenWindow
//
//+---------------------------------------------------------------------------

BOOL CTipbarWnd::IsFullScreenWindow(HWND hwnd)
{
    ULONG_PTR dwStyle;
    ULONG_PTR dwExStyle;

    dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
    if (!(dwStyle & WS_VISIBLE))
        return FALSE;

    if (dwStyle & WS_CAPTION)
        return FALSE;

    dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);

#ifdef OLD_FULLSCREENDETECTION
    if (dwExStyle & WS_EX_TOOLWINDOW)
        return FALSE;

    if (!IsZoomed(hwnd) && !(dwExStyle & WS_EX_LAYERED))
    {
        if (IsFullScreenSize(hwnd))
            return TRUE;
    }
#else
    if (dwExStyle & WS_EX_LAYERED)
        return FALSE;

    //
    // #376691
    //
    // the full screen mode of Windows Media Player uses WS_EX_TOOLWINDOW style.
    // we need to check if it is fullscreen window or not.
    //
    if (dwExStyle & WS_EX_TOOLWINDOW)
    {
        if (hwnd == shellwnd.GetWndProgman())
            return FALSE;
    }

    //
    // And some shell fullscreen window (such as slide show) 
    // has "mazimized" status. So we don't want to check IsZoomed().
    //
    // Thus any application without caption covers the screen won't have a 
    // floating toolbar. 
    //
    if (IsFullScreenSize(hwnd))
        return TRUE;
#endif

    return FALSE;
}

//+---------------------------------------------------------------------------
//
// SetFocusThread
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::SetFocusThread(CTipbarThread *pThread)
{
    if (pThread == _pFocusThread)
        return S_OK;

    DWORD dwThreadId = GetCurrentThreadId();

    DestroyOverScreenSizeBalloon();

    if (_pFocusThread)
    {
        _pFocusThread->SetFocus(FALSE);
        AttachThreadInput(dwThreadId, _pFocusThread->_dwThreadId, FALSE);
    }

    _pFocusThread = pThread;

    //
    // we will attach the focus thread input into this thread when
    // when we need (mouse message comes and any other case?). 
    //
    _fFocusAttached = FALSE;

    if (_pFocusThread)
    {
        _pFocusThread->SetFocus(TRUE);
    }

    if (!_pFocusThread)
    {
        if (!IsVisibleWindowInDesktop())
        {
            // this is a hack to shut down ctfmon.exe when we're in a terminal server session
            // and the main app has shutdown and no shell is running -- terminal server won't
            // end the session as long as ctfmon is running which effectively locks the machine.
            // See cicero bug 4235.
            //
            // Issue: got some more info from the terminal server team, another cleaner fix:
            //
            // Anyway if you need to put something in "not wait for" list, just add a value to 
            // "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\SysProcs" key.
            // Name of the value should be equal to a name of executable, type is REG_DWORD, value is 0.
            if (!_fInDeskBand)
                PostQuitMessage(0);
            else if (_pDeskBand)
                _pDeskBand->DeleteBand();

        }
    }
    return S_OK;
}

//+---------------------------------------------------------------------------
//
// AttachFocusThread
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::AttachFocusThread()
{
    if (_fFocusAttached)
        return TRUE;

    // 
    // Attach the focus thread when mouse message is coming.  Since this 
    // toolbar window is disabled window, using different input focus
    // causes unexpected focus change.
    //

    if (_pFocusThread)
    {
        DWORD dwThreadId = GetCurrentThreadId();
        AttachThreadInput(dwThreadId, _pFocusThread->_dwThreadId, TRUE);
        _fFocusAttached = TRUE;
    }

    return S_OK;
}

//+---------------------------------------------------------------------------
//
// ThreadTerminate
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::OnThreadTerminate(DWORD dwThreadId)
{
    HRESULT hr;

    StartPendingUpdateUI();
    AddRef();

    hr = OnThreadTerminateInternal(dwThreadId);
    if (!_pFocusThread)
        EnsureFocusThread();

    EndPendingUpdateUI();
    Release();
    return hr;
}

//+---------------------------------------------------------------------------
//
// OnThreadTerminateInternal
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::OnThreadTerminateInternal(DWORD dwThreadId)
{
    TraceMsg(TF_FUNC, "focusnfy OnThreadTerminate %x ", dwThreadId);

    int i;
    for (i = 0; i < _rgThread.Count(); i++)
    {
        CTipbarThread *pThread = _rgThread.Get(i);
        if (!pThread)
            continue;

        if (pThread->_dwThreadId == dwThreadId)
        {
            _rgThread.Remove(i, 1);

            pThread->RemoveUIObjs();

            CleanUpThreadPointer(pThread, FALSE);

            pThread->_UninitItemList(TRUE);
            pThread->Disconnect();
            pThread->_Release();
            goto Exit;
        }
    }

Exit:
    return S_OK;
}

//+---------------------------------------------------------------------------
//
// CleanUpThreadPointer
//
// This function make sure CTipbarWnd does not have pThread pointer any more.
//
//----------------------------------------------------------------------------

void CTipbarWnd::CleanUpThreadPointer(CTipbarThread *pThread, BOOL fCheckThreadArray)
{
    Assert(pThread);

    if (fCheckThreadArray)
    {
        int i;
        for (i = 0; i < _rgThread.Count(); i++)
        {
            if (pThread == _rgThread.Get(i))
            {
                _rgThread.Remove(i, 1);
                break;
            }
        }
    }

    if (pThread == _pFocusThread)
        SetFocusThread(NULL);

    if (pThread == _pttModal)
        _pttModal = NULL;

    if (pThread == _pThreadShowWindowAtTimer)
        _pThreadShowWindowAtTimer = NULL;
}

//+---------------------------------------------------------------------------
//
// EnsureFocusThread
//
//----------------------------------------------------------------------------

void CTipbarWnd::EnsureFocusThread()
{
    if (_pFocusThread)
    {
        Assert(0); 
        return;
    }

    if (_fTerminating)
        return;

    if (_fInEnsureFocusThread)
        return;

    _fInEnsureFocusThread = TRUE;

    HWND hwndFore = GetForegroundWindow();
    if (hwndFore)
    {
        DWORD dwThreadId = GetWindowThreadProcessId(hwndFore, NULL);
        if (dwThreadId)
            OnSetFocus(dwThreadId);
    }

    _fInEnsureFocusThread = FALSE;
}

//+---------------------------------------------------------------------------
//
// OnThreadItemChange
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::OnThreadItemChange(DWORD dwThreadId)
{
    CTipbarThread *pThread;
    TraceMsg(TF_FUNC, "focusnfy OnThreadItemChange %x ", dwThreadId);

    //
    // if the toolbar is being terminated, do nothing.
    //
    if (_fTerminating)
        return S_OK;

    //
    // If this MSUTB is in ctfmon.exe and the langbar status is in Deskband,
    // this meutb should stop wroking.
    //
    if (!_fInDeskBand && IsSFDeskband())
        return S_OK;

    pThread = _FindThread(dwThreadId);
    if (!pThread)
    {
#if 0
        //
        // Issue: #365434 - In the running of Deskband after just restart
        // machine, this hit will disable the showing deskband.
        //
        if (!_pFocusThread)
            Show(FALSE);
#endif

        return S_OK;
    }

    if ((_dwThreadIdWaitNotify && (_dwThreadIdWaitNotify != dwThreadId)) ||
        (pThread != _pFocusThread))
    {
        pThread->_fItemChanged = TRUE;
        return S_OK;
    }

    KillOnTheadItemChangeTimer();

    _dwThreadItemChangedForTimer = dwThreadId;
    KillTimer(TIPWND_TIMER_ONUPDATECALLED);
    SetTimer(TIPWND_TIMER_ONTHREADITEMCHANGE, g_uTimerElapseONTHREADITEMCHANGE);
    return S_OK;
}

//+---------------------------------------------------------------------------
//
// OnThreadItemChange
//
//----------------------------------------------------------------------------

HRESULT CTipbarWnd::OnThreadItemChangeInternal(DWORD dwThreadId)
{
    CTipbarThread *pThread;
    HRESULT hr = S_OK;

    TraceMsg(TF_FUNC, "focusnfy OnThreadItemChangeInternal %x ", dwThreadId);

    if (_dwThreadIdWaitNotify && (_dwThreadIdWaitNotify != dwThreadId))
        return S_OK;

    //
    // If this MSUTB is in ctfmon.exe and the langbar status is in Deskband,
    // this meutb should stop wroking.
    //
    if (!_fInDeskBand && IsSFDeskband())
        return S_OK;

    pThread = _FindThread(dwThreadId);

    if (!pThread)
        return S_OK;

    if (pThread != _pFocusThread)
    {
        pThread->_fItemChanged = TRUE;
        return hr;
    }

    //
    // Ok, dwThreadId has a focus now, we need immediate action to update
    // langbar.
    //
    Assert(dwThreadId == pThread->_dwThreadId);

    StartPendingUpdateUI();

    //
    // addref to increment the refcount.
    //
    pThread->_AddRef();

    hr = pThread->_UninitItemList(TRUE);

    if (SUCCEEDED(hr))
    {
        pThread->RemoveUIObjs();
        hr = pThread->InitItemList();

        if (SUCCEEDED(hr))
        {
            //
            // UninitItemList and InitItemList make marshaling calls.
            // we need to check _pFocusThread again.
            //
            if (pThread == _pFocusThread)
            {
                pThread->LocateItems();
                pThread->AddUIObjs();
                pThread->UpdateItems();
            }
        }
    }

    //
    // release to decrement the refcount.
    //
    pThread->_Release();

    //
    // #366835
    //
    // We got an error for the focus thread. Marshalling stubs might been gone!
    // Let's restart marshaling.
    //
    if (hr == RPC_E_CONNECTION_TERMINATED)
    {
        //
        // Throw away lost marshalled interfaces.
        //
        OnThreadTerminateInternal(dwThreadId);

        //
        // OnSetFocus() will reacate CTipbarThread.
        //
        OnSetFocus(dwThreadId);
    }

    _ctrlbtnHolder.EnableBtns();

    // InvalidateRect(GetWnd(), NULL, TRUE);
    if (_fShowTrayIcon)
    {
        KillTimer(TIPWND_TIMER_MOVETOTRAY);
        SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
    }

    EndPendingUpdateUI();
    return hr;
}

//+---------------------------------------------------------------------------
//
// MoveToTray
//
//----------------------------------------------------------------------------

void CTipbarWnd::MoveToTray()
{
    //
    // we don't use NotyfTrayIcon on WinXP.
    //
    if (IsOnNT51())
        return;

    if (!g_pTrayIconWnd)
        return;

    //
    // Even if the floating toolbar setting is "minimized", we need to show
    // it when explorer.exe is not running.
    //
    if (!g_pTrayIconWnd->GetNotifyWnd())
    {
        Show(TRUE);
        return;
    }

    if (_fShowTrayIcon)
    {
        if (_pFocusThread)
        { 
            if (TF_IsInMarshaling(_pFocusThread->_dwThreadId))
            {
                SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
                return;
            }
        }
        //
        // we move to TrayIcon. Make sure the toolbar is hidden.
        //
        KillTimer(TIPWND_TIMER_SHOWWINDOW);
        Show(FALSE);

        DestroyOverScreenSizeBalloon();
        CTipbarItem *pItem = NULL;
        BOOL fIsKeyboardItemVisible = FALSE;
        CTipbarItem *pKeyboardItem = NULL;
        if (_pFocusThread)
        {
            if (_pFocusThread->IsConsole())
                pItem = _pFocusThread->GetItem(GUID_LBI_INATITEM);
            else
                pItem = _pFocusThread->GetItem(GUID_LBI_CTRL);

            if (pItem && !pItem->IsVisibleInToolbar())
                pItem = NULL;

            pKeyboardItem = _pFocusThread->GetItem(GUID_TFCAT_TIP_KEYBOARD);
            if (pKeyboardItem && !pKeyboardItem->IsInHiddenStatus())
                fIsKeyboardItemVisible = TRUE;
        }

        //
        // we don't have to show UTB's Main Icon when
        //   - there is LBI_INATITEM or LBI_CTRL item.
        //   - there is a visible keyboard item.
        //
        g_pTrayIconWnd->SetMainIcon(pItem ? NULL : fIsKeyboardItemVisible ? NULL : GetFocusKeyboardLayout());

        if (!g_pTrayIconWnd->_fShowExtraIcons)
        {
            DWORD dwRAIFlags = 0;
            if (pItem)
                dwRAIFlags |= TIW_RAI_LEAVELANGICON;

            if (fIsKeyboardItemVisible)
                dwRAIFlags |= TIW_RAI_LEAVEKEYBOARDICON;

            g_pTrayIconWnd->RemoveAllIcon(dwRAIFlags);

            if (pItem)
            {
                pItem->MoveToTray();
            }
            else if (fIsKeyboardItemVisible)
            {
                Assert(!!pKeyboardItem)
                pKeyboardItem->MoveToTray();
            }
        }
        else if (_pFocusThread)
        {
            int i;

            g_pTrayIconWnd->RemoveUnusedIcons(&_pFocusThread->_rgItem);

            for (i = 0; i < _pFocusThread->_rgItem.Count(); i++)
            {
                if (TF_IsInMarshaling(_pFocusThread->_dwThreadId))
                {
                    SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
                    return;
                }

                pItem = _pFocusThread->_rgItem.Get(i);
                if (pItem)
                    pItem->MoveToTray();
            }
        }
    }
}
//+---------------------------------------------------------------------------
//
// OnModalInput
//
//----------------------------------------------------------------------------

STDAPI CTipbarWnd::OnModalInput(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_KEYDOWN:
        case WM_KEYUP:
            if (_pttModal)
            {
                Assert(_pModalMenu);
                Assert(_pttModal->_dwThreadId == dwThreadId);
                _pModalMenu->PostKey((uMsg == WM_KEYUP), wParam, lParam);
            }
            break;

        case WM_NCLBUTTONDOWN:
        case WM_NCRBUTTONDOWN:
        case WM_NCMBUTTONDOWN:
            break;

        case WM_NCLBUTTONUP:
        case WM_NCRBUTTONUP:
        case WM_NCMBUTTONUP:
            //
            // Multi Monitor
            //
            // if the disable window is in the negative location of 
            // screen coordinate, wm_ncxx message is generated. 
            // (maybe this is not mm specific, since siable window does not
            //  get WM_NCHITTEST.)
            // 
            // we just forward this message to modal menu window as a normal
            // mouse message to simulate the mouse action.
            //
            if (_pttModal)
            {
                Assert(_pModalMenu);
                Assert(_pttModal->_dwThreadId == dwThreadId);
                HWND hwnd = _pModalMenu->GetWnd();
                if (hwnd) 
                {
                    POINT pt;
                    POINTSTOPOINT( pt, MAKEPOINTS( lParam ) );
                    ScreenToClient(hwnd, &pt);
                    PostMessage(hwnd,
                                uMsg + (WM_MOUSEMOVE - WM_NCMOUSEMOVE),
                                wParam,
                                MAKELPARAM(pt.x, pt.y));
                }
            }
            break;

        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
        case WM_MBUTTONUP:
            break;

        default:
            CancelMenu();
            break;
            
    }
    return S_OK;
}

//+---------------------------------------------------------------------------
//
// ShowFloating
//
//----------------------------------------------------------------------------

STDAPI CTipbarWnd::ShowFloating(DWORD dwFlags)
{
    if (_fInDeskBand)
    {
        _dwSFTFlags = dwFlags;

        if (dwFlags & TF_SFT_DESKBAND)
        {
            //
            // If we don't have _pFocusThread, the empty langbar is shown.
            // Try to get the thread of the foreground window. This may not
            // work correctly because the actual focus could be different 
            // from the thread of the foreground window.
            //
            if (!_pFocusThread)
            {
                KillTimer(TIPWND_TIMER_ENSUREFOCUS);
                SetTimer(TIPWND_TIMER_ENSUREFOCUS, g_uTimerElapseENSUREFOCUS);
            }

            //
            // Update Extra icons changing options
            //
            KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);
            SetTimer(TIPWND_TIMER_SYSCOLORCHANGED, g_uTimerElapseSYSCOLORCHANGED);
        }

        if (dwFlags & TF_SFT_EXTRAICONSONMINIMIZED)
        {
            _fAddExtraIcon = TRUE;
            ClearDeskbandSizeAdjusted();
        }
        else if (dwFlags & TF_SFT_NOEXTRAICONSONMINIMIZED)
        {
            _fAddExtraIcon = FALSE;
            ClearDeskbandSizeAdjusted();
        }

        return S_OK;
    }
    
    if (dwFlags & TF_SFT_SHOWNORMAL)
    {
        //
        // we update the itemlist from registry now.
        // something might be change during deskbanding.
        //
        _itemList.Load();

        SetShowTrayIcon(FALSE);

        //
        // Call SetLangBar() before updating _dwSFTFlags.
        //
        SetLangBand(FALSE);

        //
        // Set SHOWNOARMAL flag before calling OnSetFocus().
        //
        _dwSFTFlags = TF_SFT_SHOWNORMAL;

        //
        // If we don't have _pFocusThread, the empty langbar is shown.
        // Try to get the thread of the foreground window. This may not
        // work correctly because the actual focus could be different 
        // from the thread of the foreground window.
        //
        if (!_pFocusThread)
            EnsureFocusThread();

        Show(TRUE);

    }
    else if (dwFlags & TF_SFT_DOCK)
    {
        //
        // Call SetLangBar() before updating _dwSFTFlags.
        //
        SetLangBand(FALSE);
        _dwSFTFlags = TF_SFT_DOCK;
    }
    else if (dwFlags & TF_SFT_MINIMIZED)
    {
        SetShowTrayIcon(TRUE);
        KillTimer(TIPWND_TIMER_SHOWWINDOW);
        Show(FALSE);

        //
        // Call SetLangBar() before updating _dwSFTFlags.
        //
        SetLangBand(FALSE);

        _dwSFTFlags = TF_SFT_MINIMIZED;
    }
    else if (dwFlags & TF_SFT_HIDDEN)
    {
        SetShowTrayIcon(FALSE);
        KillTimer(TIPWND_TIMER_SHOWWINDOW);
        Show(FALSE);

        //
        // Call SetLangBar() before updating _dwSFTFlags.
        //
        SetLangBand(FALSE);
        _dwSFTFlags = TF_SFT_HIDDEN;

        TurnOffSpeechIfItsOn();
    }
    else if (dwFlags & TF_SFT_DESKBAND)
    {
        SetShowTrayIcon(FALSE);
        KillTimer(TIPWND_TIMER_SHOWWINDOW);
        KillTimer(TIPWND_TIMER_SHOWDESKBAND);
        Show(FALSE);

        //
        // if the process of explorer belongs to different user, we don't 
        // set langband.
        //
        if (InitCurrentProcessSid())
        {
            DWORD dwProcessIdTray;
            HWND hwndTray = shellwnd.GetWndTray();
            GetWindowThreadProcessId(hwndTray, &dwProcessIdTray);
            if (dwProcessIdTray)
            {
                char szSid[UNLEN + 1];
                GetUserSIDString(dwProcessIdTray, szSid, ARRAYSIZE(szSid));
                if (lstrcmp(szSid, g_szSid))
                    return S_OK;
    
            }
        }

        //
        // Need to make sure adding the language bar menu on taskbar
        //
        SetRegisterLangBand(TRUE);

        //
        // BugBug#377897 - Always show the extra additional icons in case of
        // single keyboard layout.
        //
        if (IsSFNoExtraIcon())
        {
            if (IsSingleKeyboardLayout())
            {
                GetLangBarMgr()->ShowFloating(TF_SFT_EXTRAICONSONMINIMIZED);
            }
        }

        //
        // Call SetLangBar() before updating _dwSFTFlags.
        //
        if (SetLangBand(TRUE))
            _dwSFTFlags = TF_SFT_DESKBAND;
        else
            SetTimer(TIPWND_TIMER_SHOWDESKBAND, g_uTimerElapseSHOWDESKBAND);
    }

    if (dwFlags & TF_SFT_NOTRANSPARENCY)
    {
         SetAlpha(255, FALSE);
    }
    else if (dwFlags & TF_SFT_LOWTRANSPARENCY)
    {
         SetAlpha(128, FALSE);
    }
    else if (dwFlags & TF_SFT_HIGHTRANSPARENCY)
    {
         SetAlpha(62, FALSE);
    }

    if (dwFlags & TF_SFT_LABELS)
    {
        SetShowText(TRUE);
    }
    else if (dwFlags & TF_SFT_NOLABELS)
    {
        SetShowText(FALSE);
    }

    if (dwFlags & TF_SFT_EXTRAICONSONMINIMIZED)
    {
        _fAddExtraIcon = TRUE;

        if (g_pTrayIconWnd)
        {
            g_pTrayIconWnd->_fShowExtraIcons = TRUE;
            if (_fShowTrayIcon)
                SetShowTrayIcon(TRUE);
        }
    }
    else if (dwFlags & TF_SFT_NOEXTRAICONSONMINIMIZED)
    {
        _fAddExtraIcon = FALSE;

        if (g_pTrayIconWnd)
        {
            g_pTrayIconWnd->_fShowExtraIcons = FALSE;
            if (_fShowTrayIcon)
                SetShowTrayIcon(TRUE);
        }
    }

    return S_OK;
}

//+---------------------------------------------------------------------------
//
// GetItemFloatingRect
//
//----------------------------------------------------------------------------

STDAPI CTipbarWnd::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
{
    HRESULT hr;

    if (IsShowTrayIcon())
        return E_UNEXPECTED;

    if (!_pFocusThread)
        return E_FAIL;

    if (_pFocusThread->_dwThreadId != dwThreadId)
        return E_FAIL;

    hr = E_FAIL;

    int i;
    for (i = 0; i < _pFocusThread->_rgItem.Count(); i++)
    {
        CTipbarItem *pItem = _pFocusThread->_rgItem.Get(i);
        if (!pItem)
            continue;

        if (pItem->IsVisibleInToolbar() && IsEqualGUID(*pItem->GetGUID(), rguid))
        {
            pItem->GetScreenRect(prc);
            hr = S_OK;
            break;
        }
    }
    return hr;
}

//+---------------------------------------------------------------------------
//
// OnLangBarUpdate
//
//----------------------------------------------------------------------------

STDAPI CTipbarWnd::OnLangBarUpdate(UINT uUpdate, LPARAM lParam)
{
    switch (uUpdate)
    {
        case TF_LBU_CAPSKANAKEY:
            _ctrlbtnHolder.UpdateCapsKanaState(lParam);
            break;

        case TF_LBU_NTCONSOLELANGCHANGE:
            if (_pFocusThread && _pFocusThread->IsConsole())
            {
                CTipbarItem *pItem = _pFocusThread->GetItem(GUID_LBI_INATITEM);
                if (pItem)
                {
                    CLBarInatItem *plbi = (CLBarInatItem *)pItem->GetNotifyUI();

                    HKL hkl = (HKL)lParam;
                    if (!hkl)
                    {
                        //
                        // #403714
                        //
                        // Don't know when GetKeyboardLayout() starts returning
                        // the correct value for the Console thread id.
                        // Want to use another timer to have an interval but
                        // having lots of code and path is not good idea at
                        // this time (just before releasing WinXP).
                        // Calling Sleep() with small interval looks the 
                        // safest way to solve this problem.
                        //
                        Sleep(50);
                        hkl = GetKeyboardLayout(_pFocusThread->_dwThreadId);
                    }

                    plbi->SetHKL(hkl);
                    if (g_pTrayIconWnd)
                    {
                       g_pTrayIconWnd->SetMainIcon(NULL);
                    }
                }
                _pFocusThread->UpdateItems();
            }
            break;
    }
    return S_OK;
}

//+---------------------------------------------------------------------------
//
// FindAndCreateThread
//
//----------------------------------------------------------------------------

CTipbarThread *CTipbarWnd::_FindThread(DWORD dwThreadId)
{
    int i;
    for (i = 0; i < _rgThread.Count(); i++)
    {
        CTipbarThread *pThread = _rgThread.Get(i);
        if (!pThread)
            continue;

        if (pThread->_dwThreadId == dwThreadId)
        {
            DWORD dwProcessId;
            DWORD dwThreadFlags;
            DWORD dwTickTime;

            //
            // TF_GetThreadFlag() does not work corrently on 
            // winlogon desktop..
            //
            if (g_bWinLogon)
                break;

            TF_GetThreadFlags(dwThreadId, &dwThreadFlags, &dwProcessId, &dwTickTime);

            if (!dwProcessId || 
                (dwProcessId != pThread->_dwProcessId) ||
                (dwTickTime != pThread->_dwTickTime))
            {
                OnThreadTerminateInternal(dwThreadId);
                pThread = NULL;
            }

            return pThread;
        }
    }

    return NULL;
}

//+---------------------------------------------------------------------------
//
// FindAndCreateThread
//
//----------------------------------------------------------------------------

CTipbarThread *CTipbarWnd::_CreateThread(DWORD dwThreadId)
{
    HRESULT hr;
    CTipbarThread *pThread = _FindThread(dwThreadId);

    if (pThread)
        return pThread;

    CTipbarThread **ppThread;

    MyWaitForInputIdle(dwThreadId, UTB_INPUTIDLETIMEOUT);

    pThread = new CTipbarThread(this);
    if (!pThread)
        goto Exit;

    hr = pThread->Init(dwThreadId);
    if (FAILED(hr))
    {
        goto FreeThread;
    }

    if (SUCCEEDED(pThread->InitItemList()))
    {
        TraceMsg(TF_GENERAL, "OnSetFocus Create New CTipbarThreadm");

        ppThread = _rgThread.Append(1);
        if (!ppThread)
        {
            goto FreeThread;
        }

        *ppThread = pThread;
    }
    else
    {
        TraceMsg(TF_GENERAL, "focusnfy OnSetFocus fail to create CTipbarThreadm");
FreeThread:
        pThread->_UninitItemList(TRUE);
        pThread->Disconnect();
        pThread->_Release();
        pThread = NULL;
        goto Exit;
    }

Exit:
    return pThread;
}

//+---------------------------------------------------------------------------
//
// Init
//
//----------------------------------------------------------------------------

void CTipbarWnd::Init(BOOL fInDeskBand, CDeskBand *pDeskBand)
{
    RECT rc;


    if (_fInDeskBand = fInDeskBand)
        _fShowText = FALSE;
 
    _pDeskBand = pDeskBand;

    ::SetRect(&rc, 0, 0, 0, 0);

    if (g_bNewLook && 
        !_pWndFrame &&
        (GetStyle() & UIWINDOW_OFC10TOOLBAR))
    {
        UINT uWndFrameStyle;

        uWndFrameStyle = UIWNDFRAME_THIN | UIWNDFRAME_NORESIZE;

        _pWndFrame = new CUIFWndFrame(this, &rc, uWndFrameStyle);

        if (_pWndFrame)
        {
            _pWndFrame->Initialize();

            AddUIObj(_pWndFrame);
        }
    }

    if (!_pGripper && !_fInDeskBand)
    {
        _pGripper = new CTipbarGripper(this, &rc, IsVertical() ? UIGRIPPER_VERTICAL : 0);

        if (_pGripper)
        {
            _pGripper->Initialize();

            AddUIObj(_pGripper);
        }
    }


    _ctrlbtnHolder.Init(this);

    if (!IsVertical())
        Move(_xWnd, _yWnd, 0, GetTipbarHeight());
    else
        Move(_xWnd, _yWnd, GetTipbarHeight(), 0);
}

//+---------------------------------------------------------------------------
//
// SetVertical
//
//----------------------------------------------------------------------------

void CTipbarWnd::SetVertical(BOOL fVertical)
{
    int iPartID;
    _fVertical = fVertical;

    if (_fVertical)
        iPartID = TBP_BACKGROUNDLEFT;
    else
        iPartID = TBP_BACKGROUNDBOTTOM;

    if (_pGripper)
    {
        DWORD dwStyle = _pGripper->GetStyle();
        if (fVertical)
            dwStyle |= UIGRIPPER_VERTICAL;
        else
            dwStyle &= ~UIGRIPPER_VERTICAL;
        _pGripper->SetStyle(dwStyle);
    }

    if (g_fTaskbarTheme)
        SetActiveTheme(L"TASKBAR", iPartID, TS_NORMAL );

    if (!_fInDeskBand)
    {
        if (!IsVertical())
            Move(_xWnd, _yWnd, 0, GetTipbarHeight());
        else
            Move(_xWnd, _yWnd, GetTipbarHeight(), 0);
    }

    if (GetWnd())
    {
        KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);
        SetTimer(TIPWND_TIMER_SYSCOLORCHANGED, g_uTimerElapseSYSCOLORCHANGED);
    }
}

//+---------------------------------------------------------------------------
//
// InitThemeMargins
//
//----------------------------------------------------------------------------

void CTipbarWnd::InitThemeMargins()
{
    CUIFTheme themeBtn;
    memset(&_marginsItem, 0, sizeof(_marginsItem));
    _cxItemMargin = CX_ITEMMARGIN;
    _nItemDistance = ITEMDISTANCE;
    _nCtrlItemHeightMargin = CTRLITEMHEIGHTMARGIN;
    _cxCapBtn = GetSystemMetrics( SM_CXSIZE );

    themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);
    if (SUCCEEDED(themeBtn.OpenThemeData(GetWnd())))
    {
        themeBtn.GetThemeMargins(NULL, TS_NORMAL, 
                                 TMT_CONTENTMARGINS, 
                                 NULL, &_marginsItem);
        _cxItemMargin = CX_ITEMMARGIN_THEME;
        _nItemDistance = ITEMDISTANCE_THEME;
        _nCtrlItemHeightMargin = CTRLITEMHEIGHTMARGIN_THEME;
    }

    themeBtn.CloseThemeData();
    themeBtn.SetActiveTheme(L"WINDOW", WP_CLOSEBUTTON, 0);
    if (SUCCEEDED(themeBtn.OpenThemeData(GetWnd())))
    {
        SIZE size;
        themeBtn.GetThemePartSize(NULL, TS_NORMAL, 
                                  NULL,
                                  TS_TRUE, 
                                  &size);

        int cy = themeBtn.GetThemeSysSize(SM_CYSIZE);
        _cxCapBtn = MulDiv(cy, size.cx, size.cy);
    }
}


//+---------------------------------------------------------------------------
//
// UpdateVerticalFont
//
//----------------------------------------------------------------------------

void CTipbarWnd::UpdateVerticalFont()
{
    if (_fVertical)
    {
        if (_hfontVert)
        {
            DeleteObject(_hfontVert);
            SetFontToThis(NULL);
            _hfontVert = NULL;
        }

        _hfontVert = CreateVerticalFont();
        SetFontToThis(_hfontVert);
    }
    else
    {
        SetFontToThis(NULL);
    }
}

//+---------------------------------------------------------------------------
//
// CheckEAFonts
//
//----------------------------------------------------------------------------

int CALLBACK FindEAEnumFontProc(const LOGFONT *plf, const TEXTMETRIC *ptm, WORD wType, LPARAM lParam)
{
    BOOL *pf = (BOOL *)lParam;

    if (wType != TRUETYPE_FONTTYPE)
        return 1;

    if (plf->lfFaceName[0] == '@')
    {
        *pf = TRUE;
        return 0;
    }

    return 1;
}

BOOL CheckEAFonts()
{
    HDC hdc = GetDC(NULL);
    BOOL fFound = FALSE;

    EnumFonts(hdc, NULL, (FONTENUMPROC)FindEAEnumFontProc, (LPARAM)&fFound);

    ReleaseDC(NULL, hdc);
    return fFound;
}


//+---------------------------------------------------------------------------
//
// CreateVerticalFont
//
//----------------------------------------------------------------------------

HFONT CTipbarWnd::CreateVerticalFont()
{
    HFONT hfontVert = NULL;
    CUIFTheme themeBtn;
    themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);

    if (!GetWnd())
        return NULL;

    BOOL fIsEAFonts = CheckEAFonts();

    if (SUCCEEDED(themeBtn.OpenThemeData(GetWnd())))
    {
        LOGFONTW lfw;
        Assert(IsOnNT51());

        if (SUCCEEDED(themeBtn.GetThemeFont(NULL, 0 , TMT_FONT, &lfw)))
        {
            lfw.lfEscapement = 2700;
            lfw.lfOrientation = 2700;
            lfw.lfOutPrecision = OUT_TT_ONLY_PRECIS;

            if (fIsEAFonts)
            {
                //
                // Use @font for vertical langbar.
                //
                WCHAR szFaceName[LF_FACESIZE];
                szFaceName[0] = L'@';
                StringCchCopyW(&szFaceName[1], ARRAYSIZE(szFaceName) -1, lfw.lfFaceName);
                StringCchCopyW(lfw.lfFaceName, ARRAYSIZE(lfw.lfFaceName), szFaceName);

            }
            hfontVert = CreateFontIndirectW(&lfw);
            goto CheckFont;
        }
    }

    LOGFONT lf;
    HFONT hDefFont = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
    GetObject(hDefFont, sizeof(LOGFONT), &lf);
    lf.lfEscapement = 2700;
    lf.lfOrientation = 2700;
    lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;

    if (fIsEAFonts)
    {
        //
        // Use @font for vertical langbar.
        //
        char szFaceName[LF_FACESIZE];
        szFaceName[0] = '@';
        StringCchCopy(&szFaceName[1], ARRAYSIZE(szFaceName) -1, lf.lfFaceName);
        StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), szFaceName);
    }

    hfontVert = CreateFontIndirect(&lf);

CheckFont:
    return hfontVert;
}

//+---------------------------------------------------------------------------
//
// SetLangBand
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::SetLangBand(BOOL fLangBand, BOOL fNotify)
{
    BOOL fRet = TRUE;

    if (fLangBand == (IsSFDeskband() ? TRUE : FALSE))
        return fRet;

    //
    // Set/Remove language band object
    //
    HWND hwndTray = shellwnd.GetWndTray();

    if (fNotify && hwndTray)
    {
#ifndef CUAS_ENABLE
        DWORD_PTR dwResult;
        LRESULT lResult = (LRESULT)0;

        lResult = SendMessageTimeout(hwndTray,
                                     TM_LANGUAGEBAND,
                                     0,
                                     fLangBand,
                                     SMTO_ABORTIFHUNG | SMTO_BLOCK,
                                     5000,
                                     &dwResult);

        //
        // Checking the language band setting fail case
        //
        if (!lResult || dwResult != fLangBand)
        {
            Assert(0);
        }
#else
        DWORD_PTR dwResult;
        LRESULT lResult = (LRESULT)0;

        //
        // Workaround fixes of Cicero 5181
        // Explorer process doesn't initialize _ptbs yet when receive TM_LANGUAGEBAND.
        //
        HWND hwndIME = NULL;

        //
        // we should not load IMM32 here. If there is no IMM32.DLL loaded,
        // there is no hwndIME.
        //
        if (GetSystemModuleHandle("imm32.dll"))
            hwndIME = ImmGetDefaultIMEWnd(hwndTray);

        if (hwndIME)
        {
            lResult = SendMessageTimeout(hwndIME,
                                         WM_IME_SYSTEM,
                                         fLangBand ? IMS_SETLANGBAND : IMS_RESETLANGBAND,
                                         (LPARAM)hwndTray,
                                         SMTO_ABORTIFHUNG | SMTO_BLOCK,
                                         5000,
                                         &dwResult);
        }
        else
        {
            lResult = SendMessageTimeout(hwndTray,
                                         TM_LANGUAGEBAND,
                                         0,
                                         fLangBand,
                                         SMTO_ABORTIFHUNG | SMTO_BLOCK,
                                         5000,
                                         &dwResult);
        }

        //
        // Checking the language band setting fail case
        //
        if (!lResult || dwResult != fLangBand)
        {
            Assert(0);
        }
#endif
    }
    else
    {
        fRet = FALSE;
    }

    //
    // If this MSUTB is in ctfmon.exe and the langbar status is in Deskband,
    // this meutb should stop wroking.
    //
    if (!_fInDeskBand && fLangBand)
    {
        KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);
        SetTimer(TIPWND_TIMER_SYSCOLORCHANGED, g_uTimerElapseSYSCOLORCHANGED);
    }

    return fRet;
}

//+---------------------------------------------------------------------------
//
// SetMoveRect
//
//----------------------------------------------------------------------------

void CTipbarWnd::SetMoveRect( int x, int y, int nWidth, int nHeight)
{
    if (_fInDeskBand)
    {
       //
       // In case of DeskBand case, only update width and height.
       //
       _nWidth = nWidth;
       _nHeight = nHeight;

       return;
    }

    _rcNew.left   = x;
    _rcNew.top    = y;
    _rcNew.right  = nWidth;
    _rcNew.bottom = nHeight;
    _fNeedMoveWindow = TRUE;

    StartPendingUpdateUI();

    RECT rc;
    SIZE sizeWndFrame;
    sizeWndFrame.cx = 0;
    sizeWndFrame.cy = 0;
    if (_pWndFrame)
    {
        ::SetRect(&rc, 0, 0,
                  nWidth - GetCxDlgFrame(),
                  nHeight - GetCyDlgFrame());
        _pWndFrame->SetRect(&rc);
        _pWndFrame->GetFrameSize( &sizeWndFrame );
    }

    if (_pGripper)
    {
        if (!IsVertical())
        {
            ::SetRect(&rc,
                      sizeWndFrame.cx,
                      sizeWndFrame.cy,
                      sizeWndFrame.cx + GetGripperWidth(),
                      nHeight - GetCyDlgFrame() - sizeWndFrame.cy);
        }
        else
        {
            ::SetRect(&rc,
                      sizeWndFrame.cx,
                      sizeWndFrame.cy,
                      nWidth - GetCxDlgFrame() - sizeWndFrame.cx,
                      sizeWndFrame.cy + GetGripperWidth());
        }
        _pGripper->SetRect(&rc);
    }
    EndPendingUpdateUI();
}

//+---------------------------------------------------------------------------
//
// GetGripperWidth
//
//----------------------------------------------------------------------------

int CTipbarWnd::GetGripperWidth()
{ 
    if (_fInDeskBand)
        return 0;

    if (_pGripper)
    {
        if (SUCCEEDED(_pGripper->EnsureThemeData(GetWnd())))
        {
            int nRet = -1;

            SIZE size;
            HDC hdc = GetDC(GetWnd());
            if (SUCCEEDED(_pGripper->GetThemePartSize(hdc, 
                                                      TS_NORMAL,
                                                      NULL, 
                                                      TS_TRUE, 
                                                      &size)))
            {
                if (!IsVertical())
                   nRet = size.cx + CUI_GRIPPER_THEME_MARGIN * 2;
                else
                   nRet = size.cy + CUI_GRIPPER_THEME_MARGIN * 2;
            }

            ReleaseDC(GetWnd(), hdc);

            if (nRet >= 0)
                return nRet;
        }
    }

    return 5;
}

//+---------------------------------------------------------------------------
//
// Move
//
//----------------------------------------------------------------------------

void CTipbarWnd::Move( int x, int y, int nWidth, int nHeight)
{
    CUIFWindow::Move(x, y, nWidth, nHeight);
}

//+---------------------------------------------------------------------------
//
// LocateCtrlButtons
//
//----------------------------------------------------------------------------

void CTipbarWnd::LocateCtrlButtons()
{
    DWORD dwFlags = 0;

    if (IsSFDeskband() && IsSFNoExtraIcon())
        dwFlags |= TCBH_NOCOLUMN;

    if (!IsCapKanaShown())
        dwFlags |= TCBH_NOCOLUMN0;

    SIZE sizeWndFrame;
    sizeWndFrame.cx = 0;
    sizeWndFrame.cy = 0;
    if (_pWndFrame != NULL) 
        _pWndFrame->GetFrameSize( &sizeWndFrame );

    int nTipbarHeight = GetTipbarHeight();
    RECT rc;
    GetRect(&rc);
    int nHeightPadding = 0;

    if (!IsVertical())
    {
        if (rc.bottom - rc.top > nTipbarHeight)
            nHeightPadding = (rc.bottom - rc.top - nTipbarHeight) / 2;

        int xNew;
        if (_fNeedMoveWindow)
            xNew =  _rcNew.right - GetCtrlButtonWidth() - sizeWndFrame.cx;
        else
            xNew =  _nWidth - GetCtrlButtonWidth() - sizeWndFrame.cx;

        _ctrlbtnHolder.Locate(this, 
                              xNew,
                              sizeWndFrame.cy + nHeightPadding, 
                              nTipbarHeight - (sizeWndFrame.cy * 2), 
                              dwFlags, FALSE);
    }
    else
    {
        if (rc.right - rc.left > nTipbarHeight)
            nHeightPadding = (rc.right - rc.left - nTipbarHeight) / 2;

        int yNew;
        if (_fNeedMoveWindow)
            yNew =  _rcNew.bottom - GetCtrlButtonWidth() - sizeWndFrame.cy;
        else
            yNew =  _nHeight - GetCtrlButtonWidth() - sizeWndFrame.cy;

        _ctrlbtnHolder.Locate(this, 
                              sizeWndFrame.cx + nHeightPadding,
                              yNew,
                              nTipbarHeight - (sizeWndFrame.cx * 2), 
                              dwFlags, TRUE);
    }
}

//+---------------------------------------------------------------------------
//
// GetFocusKeyboardLayout
//
//----------------------------------------------------------------------------

HKL CTipbarWnd::GetFocusKeyboardLayout() 
{
    return GetKeyboardLayout(_pFocusThread ? _pFocusThread->_dwThreadId : 0);
}

//+---------------------------------------------------------------------------
//
// HandleMouseMsg
//
//----------------------------------------------------------------------------

void CTipbarWnd::HandleMouseMsg( UINT uMsg, POINT pt )
{
    if (_fInHandleMouseMsg)
        return;

    //
    // Bug#477031: Add the reference count to finish the current task before
    // destructing this object.
    //
    //
    AddRef();

    _fInHandleMouseMsg = TRUE;

    if (_pFocusThread)
    {
        AttachFocusThread();

        if ((uMsg == WM_LBUTTONDOWN) || (uMsg == WM_RBUTTONDOWN))
            if (!MyWaitForInputIdle(_pFocusThread->_dwThreadId, 
                                    UTB_INPUTIDLETIMEOUT))
                _pFocusThread->_ptw->_putb->RestoreLastFocus(NULL, FALSE);
    }

    POINT ptScrn = pt;
    ClientToScreen(GetWnd(), &ptScrn);
    if (WindowFromPoint(ptScrn) == GetWnd())
    {
        SetAlpha(255, TRUE);

        if (_fInStub)
        {
            KillTimer(TIPWND_TIMER_STUBEND);

            if (!_fInStubShow)
               SetTimer(TIPWND_TIMER_STUBSTART, g_uTimerElapseSTUBSTART);
        }
    }
    else
    {
        SetAlpha(_bAlpha, TRUE);

        if (_fInStub && _fInStubShow)
            SetTimer(TIPWND_TIMER_STUBEND, g_uTimerElapseSTUBEND);
    }
    CUIFWindow::HandleMouseMsg(uMsg, pt);

    if (uMsg == WM_RBUTTONUP)
    {
       CUIFObject *pUIObj = ObjectFromPoint( pt );
       if (pUIObj && pUIObj->GetID() != (-1))
       {
           PostMessage(GetWnd(), WM_LBWND_SHOWCONTEXTMENU, 0, MAKELPARAM(pt.x, pt.y));
       }
    }

    _fInHandleMouseMsg = FALSE;
    Release();
}

//+---------------------------------------------------------------------------
//
// OnMouseOutFromWindow
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnMouseOutFromWindow( POINT pt )
{
    StartBackToAlphaTimer();

    if (_fInStub && _fInStubShow)
        SetTimer(TIPWND_TIMER_STUBEND, g_uTimerElapseSTUBEND);
}

//+---------------------------------------------------------------------------
//
// CheckO10Flag
//
//----------------------------------------------------------------------------

#ifdef USE_OFC10LOOKONWINXP

void CTipbarWnd::CheckO10Flag()
{
    if (!g_bNewLook)
        return;

    EnsureThemeData(GetWnd());
    if (IsThemeActive() || _fInDeskBand)
    {
        g_dwWndStyle &= ~UIWINDOW_OFC10TOOLBAR;
    }
    else
    {
        g_dwWndStyle |= UIWINDOW_OFC10TOOLBAR;
    }

    SetStyle(g_dwWndStyle);
    CreateScheme();
}
#endif

//+---------------------------------------------------------------------------
//
// OnCreate
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnCreate(HWND hWnd)
{

    if (g_fTaskbarTheme)
         SetWindowTheme(hWnd, L"TASKBAR", NULL);

#ifdef USE_OFC10LOOKONWINXP
    CheckO10Flag();
#endif

    if (_fVertical)
    {
        if (!_hfontVert)
        {
            _hfontVert = CreateVerticalFont();
        }
        SetFontToThis(_hfontVert);
    }
 
    _ctrlbtnHolder.UpdateBitmap(this);

    _itemList.Load();

    if (_putb)
        _putb->AdviseEventSink(this, hWnd, TF_LBESF_GLOBAL, &_dwlbimCookie);

    if (_pFocusThread)
        _pFocusThread->InitItemList();
  
    InitHighContrast();
    SetAlpha(128, FALSE);

    InitMetrics();


    //
    // MSAA support
    //
    Assert(!_pTipbarAcc);
    _pTipbarAcc = new CTipbarAccessible(this);
    if (_pTipbarAcc)
    {
        _pTipbarAcc->SetWindow(hWnd);
    }
}

//+---------------------------------------------------------------------------
//
// SetAlpha
//
//----------------------------------------------------------------------------

typedef BOOL (WINAPI * SETLAYERWINDOWATTRIBUTE)(HWND, COLORREF, BYTE, DWORD);
void CTipbarWnd::SetAlpha(BYTE bAlpha, BOOL fTemp)
{
    if (!_fInDeskBand && IsOnNT5())
    {

        //
        // we don't do alpha blending.
        //
        //    when high contrast is on 
        //    when Modal Menu is shown.
        //
        //
        if (IsHighContrastOn() ||
            _pModalMenu)
        {
            fTemp = TRUE;
            bAlpha = 255;
        }

        if (!fTemp)
            _bAlpha = bAlpha;

        if (_bCurAlpha == bAlpha)
            return;

        CUIFShadow *pShadowWnd = GetShadowWnd();
        if (pShadowWnd)
        {
            EnableShadow(bAlpha == 255);
            pShadowWnd->Show((bAlpha == 255) && IsVisible());
        }

        DWORD dwExStyle = GetWindowLong(GetWnd(), GWL_EXSTYLE);
        SetWindowLong(GetWnd(), GWL_EXSTYLE, dwExStyle | WS_EX_LAYERED);

        static SETLAYERWINDOWATTRIBUTE  pfnSetLayeredWindowAttributes = NULL;
        if (!pfnSetLayeredWindowAttributes)
        {
            HINSTANCE hUser32;
            hUser32 = GetSystemModuleHandle(TEXT("user32.dll"));
            if (hUser32)
                pfnSetLayeredWindowAttributes = (SETLAYERWINDOWATTRIBUTE)GetProcAddress(hUser32, TEXT("SetLayeredWindowAttributes"));
        }

        if (pfnSetLayeredWindowAttributes)
            pfnSetLayeredWindowAttributes(GetWnd(), 0, (BYTE)bAlpha, LWA_ALPHA);


        _bCurAlpha = bAlpha;
    }
}

//+---------------------------------------------------------------------------
//
// OnDestroy
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnDestroy(HWND hWnd)
{
    CancelMenu();

    //
    // MSAA support
    //
    if (_pTipbarAcc)
        _pTipbarAcc->NotifyWinEvent( EVENT_OBJECT_DESTROY, this);

    OnTerminateToolbar();

    if (_pTipbarAcc)
    {
        _pTipbarAcc->ClearAccItems();
        _pTipbarAcc->Release();
        _pTipbarAcc = NULL;
    }

    CoUninit();

    if (_putb)
        _putb->UnadviseEventSink(_dwlbimCookie);
}

//+---------------------------------------------------------------------------
//
// OnShowWindow
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnShowWindow( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    //
    // MSAA support
    //
    if (_pTipbarAcc)
    {
        if (wParam) 
        {
            _pTipbarAcc->NotifyWinEvent( EVENT_OBJECT_SHOW ,this);

            // 
            // MSCANDUI does this.
            // 
            // REVIEW: KOJIW: Unless we send notify EVENT_OBJECT_FOCUS, 
            // we never receive WM_GETOBJECT message.  Why???
            // 

            _pTipbarAcc->NotifyWinEvent( EVENT_OBJECT_FOCUS ,this);
        }
        else 
        {
            _pTipbarAcc->NotifyWinEvent( EVENT_OBJECT_HIDE ,this);
        }
    }

    return CUIFWindow::OnShowWindow( hWnd, uMsg, wParam, lParam );
}

//+---------------------------------------------------------------------------
//
// OnEndSession
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnEndSession(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    if (!g_bWinLogon)
        OnTerminateToolbar();

    if (wParam)
    {
        if (lParam & ENDSESSION_LOGOFF)
        {
            KillTimer(TIPWND_TIMER_SHOWWINDOW);
            Show(FALSE);
        }
        else
        {
            OnTerminateToolbar();

            AddRef();
            DestroyWindow(hwnd);
            Release();
        }
    }
}

//+---------------------------------------------------------------------------
//
// OnTerminateToolbar
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnTerminateToolbar()
{
    _fTerminating = TRUE;

    DestroyOverScreenSizeBalloon();

    TerminateAllThreads(TRUE);

    if (!_fInDeskBand)
        SavePosition();
}

//+---------------------------------------------------------------------------
//
// SavePosition
//
//----------------------------------------------------------------------------

void CTipbarWnd::SavePosition()
{
    CMyRegKey keyUTB;

    if (keyUTB.Create(HKEY_CURRENT_USER, c_szUTBKey) == S_OK)
    {
        POINT pt;
        pt.x = 0;
        pt.y = 0;
        MyClientToScreen(&pt, NULL);
        keyUTB.SetValue((DWORD)pt.x, c_szLeft);
        keyUTB.SetValue((DWORD)pt.y, c_szTop);
        keyUTB.SetValue((DWORD)_fVertical ? 1 : 0, c_szVertical);
    }
}

//+---------------------------------------------------------------------------
//
// TerminateAllThreads
//
//----------------------------------------------------------------------------

void CTipbarWnd::TerminateAllThreads(BOOL fTerminatFocusThread)
{
    int nCnt = _rgThread.Count();
    int i;
    DWORD *pdwThread;

    pdwThread = new DWORD[nCnt + 1];
    if (!pdwThread)
        return;

    for (i = 0; i < nCnt; i++)
    {
        pdwThread[i] = 0;

        CTipbarThread *pThread = _rgThread.Get(i);
        if (!pThread)
            continue;

        if (!fTerminatFocusThread && (pThread == _pFocusThread))
            continue;

        pdwThread[i] = pThread->_dwThreadId;
    }

    
    for (i = 0; i < nCnt; i++)
    {
        if (pdwThread[i])
            OnThreadTerminateInternal(pdwThread[i]);
    }

    delete[] pdwThread;
}

//+---------------------------------------------------------------------------
//
// SetShowText()
//
//----------------------------------------------------------------------------

void CTipbarWnd::SetShowText(BOOL fShowText) 
{
    _fShowText = fShowText;

    if (_pFocusThread)
    {
        OnThreadItemChange(_pFocusThread->_dwThreadId);
    }

    TerminateAllThreads(FALSE);
}

//+---------------------------------------------------------------------------
//
// OnWindowPosChanged
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (_pFocusThread)
    {
        int i;
        for (i = 0; i < _pFocusThread->_rgItem.Count(); i++)
        {
            CTipbarItem *pItem = _pFocusThread->_rgItem.Get(i);
            if (pItem)
                pItem->OnPosChanged();
        }
    }

    return CUIFWindow::OnWindowPosChanged(hWnd, uMsg, wParam, lParam);
}

//+---------------------------------------------------------------------------
//
// OnWindowPosChanging
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnWindowPosChanging(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    WINDOWPOS *pwp = (WINDOWPOS *)lParam;

    if (!(pwp->flags & SWP_NOZORDER))
    {
        CUIFToolTip *ptip = GetToolTipWnd();

        //
        // we don't patch hwndInsertAfter, when
        //    - Tooltip is being shown.
        //    - Modal Popup menu is shown.
        //
        if ((!ptip || !(ptip->IsBeingShown())) &&
            !_pttModal)
            pwp->hwndInsertAfter = HWND_TOP;
    }

    return CUIFWindow::OnWindowPosChanged(hWnd, uMsg, wParam, lParam);
}

//+---------------------------------------------------------------------------
//
// OnEraseBkGnd()
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnEraseBkGnd( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{ 
    return 1;
}

//+---------------------------------------------------------------------------
//
// PaintObject()
//
//----------------------------------------------------------------------------

void CTipbarWnd::PaintObject( HDC hDC, const RECT *prcUpdate )
{
    // KillTimer(TIPWND_TIMER_ONUPDATECALLED);

    if (_fNeedMoveWindow)
    {
        Move(_rcNew.left, _rcNew.top, _rcNew.right, _rcNew.bottom);
        _fNeedMoveWindow = FALSE;
    }

    if (_pFocusThread && _pFocusThread->IsDirtyItem())
    {
        _pFocusThread->CallOnUpdateHandler();

        //
        // #432697: Stress fault
        //
        // ClosePopupTipbar() could be called while CallOnUpdateHandler()
        // is calling marshaling. We should check if g_pTIpbarWnd is 
        // available.
        //
        if (!g_pTipbarWnd)
            return;
    }

    CUIFWindow::PaintObject(hDC, prcUpdate);
}

//+---------------------------------------------------------------------------
//
// UpdateUI()
//
//----------------------------------------------------------------------------

void CTipbarWnd::UpdateUI( const RECT *prcUpdate )
{
    // TraceMsg(TF_FUNC, "UpdateUI");

    KillTimer(TIPWND_TIMER_UPDATEUI);

    if (_dwThreadItemChangedForTimer ||
        _dwPendingUpdateUI || 
        (_pFocusThread && _pFocusThread->IsDirtyItem()))
    {
        SetTimer(TIPWND_TIMER_UPDATEUI, g_uTimerElapseUPDATEUI);
        return;
    }

    if (_fNeedMoveWindow)
    {
        // TraceMsg(TF_FUNC, "UpdateUI need move window");
        StartPendingUpdateUI();
        Move(_rcNew.left, _rcNew.top, _rcNew.right, _rcNew.bottom);
        _fNeedMoveWindow = FALSE;
        EndPendingUpdateUI();
    }

    TraceMsg(TF_FUNC, "UpdateUI update now ");
    CUIFWindow::UpdateUI(NULL);
}


//+---------------------------------------------------------------------------
//
// SetShowTrayIcon()
//
//----------------------------------------------------------------------------

void CTipbarWnd::SetShowTrayIcon(BOOL fShowTrayIcon) 
{
    _fShowTrayIcon = fShowTrayIcon;

    if (_fShowTrayIcon && _pFocusThread)
    {
        KillTimer(TIPWND_TIMER_MOVETOTRAY);
        SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
    }
    else if (g_pTrayIconWnd)
    {
        g_pTrayIconWnd->SetMainIcon(NULL);
        g_pTrayIconWnd->RemoveAllIcon(0);
    }



}

//+---------------------------------------------------------------------------
//
// ShowOverScreenSizeBalloon
//
//----------------------------------------------------------------------------

void CTipbarWnd::ShowOverScreenSizeBalloon()
{
    RECT rc;
    POINT pt;
    CTipbarCtrlButton *pcuiCtrlbtn = _ctrlbtnHolder.GetCtrlBtn(ID_CBTN_EXTMENU);
    if (!pcuiCtrlbtn)
    {
        Assert(0);
        return;
    }

    DestroyOverScreenSizeBalloon();

    _pblnOverScreenSize = new CUIFBalloonWindow(g_hInst, UIBALLOON_OK);
    if (!_pblnOverScreenSize)
        return;

    _pblnOverScreenSize->Initialize();

    pcuiCtrlbtn->GetRect(&rc);
    pt.x = (rc.left + rc.right) / 2;
    pt.y = rc.top;
    MyClientToScreen(&pt, &rc);

    _pblnOverScreenSize->SetTargetPos(pt);
    _pblnOverScreenSize->SetExcludeRect(&rc);

    _pblnOverScreenSize->SetText(CRStr(IDS_OVERSCREENSIZE));
    _pblnOverScreenSize->CreateWnd(GetWnd());

}

//+---------------------------------------------------------------------------
//
// DestroyMinimizeBalloon
//
//----------------------------------------------------------------------------

void CTipbarWnd::DestroyOverScreenSizeBalloon()
{
    if (_pblnOverScreenSize)
    {
        if (IsWindow(_pblnOverScreenSize->GetWnd()))
            DestroyWindow(_pblnOverScreenSize->GetWnd());
        delete _pblnOverScreenSize;
        _pblnOverScreenSize = NULL;
    }
}

//+---------------------------------------------------------------------------
//
// CancelMenu
//
//----------------------------------------------------------------------------

void CTipbarWnd::CancelMenu()
{
    if (_pttModal)
    {
        if (_pttModal->_ptw && _pttModal->_ptw->_putb)
            _pttModal->_ptw->StartModalInput(NULL, _pttModal->_dwThreadId);
        Assert(_pModalMenu);
        _pModalMenu->CancelMenu();

        StartBackToAlphaTimer();
    }
}

//+---------------------------------------------------------------------------
//
// MoveToStub
//
//----------------------------------------------------------------------------

void CTipbarWnd::MoveToStub(BOOL fHide)
{
    RECT rc;
    _fInStub = TRUE;

    SystemParametersInfo(SPI_GETWORKAREA, 0, (void *)&rc, FALSE);

    if (fHide)
    {
        _xWnd = rc.right - (24 + 14);
        _fInStubShow = FALSE;
    }
    else
    {
        RECT rcWnd;
        GetWindowRect(GetWnd(), &rcWnd);
        _xWnd = rc.right - (rcWnd.right - rcWnd.left);
        _fInStubShow = TRUE;
    }
    _yWnd = rc.bottom - GetTipbarHeight() - _cyDlgFrame;

    if (_pFocusThread)
        _pFocusThread->MyMoveWnd(0, 0);
}

//+---------------------------------------------------------------------------
//
// RestoreFromStub
//
//----------------------------------------------------------------------------

void CTipbarWnd::RestoreFromStub()
{
    _fInStub = FALSE;
    _fInStubShow = FALSE;
    KillTimer(TIPWND_TIMER_STUBSTART);
    KillTimer(TIPWND_TIMER_STUBEND);
}

//+---------------------------------------------------------------------------
//
// CTipbarWnd::KillOnThreadItemChangeTimer
//
//----------------------------------------------------------------------------

void CTipbarWnd::KillOnTheadItemChangeTimer()
{
    DWORD dwThreadId = _dwThreadItemChangedForTimer;
    _dwThreadItemChangedForTimer = 0;

    KillTimer(TIPWND_TIMER_ONTHREADITEMCHANGE);

    if (dwThreadId)
    {
        CTipbarThread *pThread = _FindThread(dwThreadId);
        if (pThread)
            pThread->_fItemChanged = TRUE;
    }
}


//+---------------------------------------------------------------------------
//
// CTipbarWnd::OnTimer
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnTimer(UINT uId)
{
    DWORD dwFocusThreadId;
    DWORD dwRet;

    AddRef();

    switch (uId)
    {
        case TIPWND_TIMER_STUBSTART:
            KillTimer(TIPWND_TIMER_STUBSTART);
            MoveToStub(FALSE);
            break;

        case TIPWND_TIMER_STUBEND:
            KillTimer(TIPWND_TIMER_STUBEND);
            MoveToStub(TRUE);
            break;

        case TIPWND_TIMER_BACKTOALPHA:
            KillTimer(TIPWND_TIMER_BACKTOALPHA);
            SetAlpha(_bAlpha, TRUE);
            break;

        case TIPWND_TIMER_ONTHREADITEMCHANGE:
            //
            // OnThreadItemChangeInternat will disconnect the marshaling for
            // all items. It is better todo this later.
            //
            dwRet = MyWaitForInputIdle(_dwThreadItemChangedForTimer,  
                                       UTB_INPUTIDLETIMEOUT);
            if (dwRet)
            {
                if (dwRet != WAIT_TIMEOUT)
                {
                    KillTimer(TIPWND_TIMER_ONTHREADITEMCHANGE);
                    _dwThreadItemChangedForTimer = 0;
                }
                break;
            }

            if (!_pttModal)
            {
                KillTimer(TIPWND_TIMER_ONTHREADITEMCHANGE);

                //
                // #509156
                //
                // Set _dwThreadItemChagnedForTimer before calling 
                // OnThreadItemChangeInternal(). During the marshaling call 
                // in the function, someone else may set 
                // _dwThreadItemChangedForTimer.
                //
                DWORD dwThreadIdTemp = _dwThreadItemChangedForTimer;
                _dwThreadItemChangedForTimer = 0;
                OnThreadItemChangeInternal(dwThreadIdTemp);
            }
            break;

        case TIPWND_TIMER_SETWINDOWPOS:
            KillTimer(TIPWND_TIMER_SETWINDOWPOS);
            SetWindowPos(GetWnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
            break;

        case TIPWND_TIMER_ONUPDATECALLED:
            KillTimer(TIPWND_TIMER_ONUPDATECALLED);
            //
            // if _dwThreadItemChangedForTimer is not 0, we will
            // update all items later.
            //
            if (_pFocusThread && 
                (_pFocusThread->_dwThreadId != _dwThreadItemChangedForTimer))
            {
                if (!_pFocusThread->CallOnUpdateHandler())
                {
                    if (_pFocusThread)
                        OnThreadItemChange(_pFocusThread->_dwThreadId);
                }
            }
            break;

        case TIPWND_TIMER_SYSCOLORCHANGED:
            KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);

            //
            // the sys colors were changed, we recreate all thread info
            // again.
            //

            if (_pFocusThread)
                dwFocusThreadId = _pFocusThread->_dwThreadId;
            else
                dwFocusThreadId = 0;

            TerminateAllThreads(TRUE);

            UpdateVerticalFont();

            if (dwFocusThreadId)
                OnSetFocus(dwFocusThreadId);

            InitMetrics();
            _ctrlbtnHolder.UpdateBitmap(this);
            InitHighContrast();
            SetAlpha(255, TRUE);

            ::RedrawWindow(GetWnd(), 
                           NULL, 
                           NULL, 
                           RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
            break;

        case TIPWND_TIMER_DISPLAYCHANGE:
            KillTimer(TIPWND_TIMER_DISPLAYCHANGE);

            AdjustPosOnDisplayChange();
            break;


        case TIPWND_TIMER_UPDATEUI:
            KillTimer(TIPWND_TIMER_UPDATEUI);
            UpdateUI(NULL);
            break;

        case TIPWND_TIMER_SHOWWINDOW:
            KillTimer(TIPWND_TIMER_SHOWWINDOW);

            if (_pThreadShowWindowAtTimer == _pFocusThread)
                Show(_fShowWindowAtTimer);

            _pThreadShowWindowAtTimer = NULL;
    
            //
            // If the window was over the screen and hide some items,
            // we show balloon tips.
            //
            if (_fShowOverItemBalloonAtTimer)
                ShowOverScreenSizeBalloon();

            break;

        case TIPWND_TIMER_SHOWDESKBAND:
            if (SetLangBand(TRUE))
            {
                _dwSFTFlags = TF_SFT_DESKBAND;
                KillTimer(TIPWND_TIMER_SHOWDESKBAND);
            }

            break;

        case TIPWND_TIMER_MOVETOTRAY:
            KillTimer(TIPWND_TIMER_MOVETOTRAY);
            MoveToTray();
            break;

        case TIPWND_TIMER_ENSUREFOCUS:
            if (_pDeskBand && _pDeskBand->IsInTipbarCreating())
                break;
                
            KillTimer(TIPWND_TIMER_ENSUREFOCUS);
            if (!_pFocusThread)
                EnsureFocusThread();
            break;

        case TIPWND_TIMER_DOACCDEFAULTACTION:
            //
            // MSAA support
            //
            KillTimer(TIPWND_TIMER_DOACCDEFAULTACTION);
            if (_pTipbarAcc && _nDoAccDefaultActionItemId)
            {
                _pTipbarAcc->DoDefaultActionReal(_nDoAccDefaultActionItemId);
                _nDoAccDefaultActionItemId = 0;
            }
            break;

        default:
            if ((uId >= TIPWND_TIMER_DEMOTEITEMFIRST) &&
                (uId < TIPWND_TIMER_DEMOTEITEMLAST))
            {
                LANGBARITEMSTATE *pItemState;
                if (pItemState = _itemList.GetItemStateFromTimerId(uId))
                {
                    CTipbarItem *pItem;
                    _itemList.SetDemoteLevel(pItemState->guid, DL_HIDDENLEVEL1);
                    if (_pFocusThread && 
                        (pItem = _pFocusThread->GetItem(pItemState->guid)))
                    {
                        Assert(!pItem->IsHiddenStatusControl())
                        pItem->AddRemoveMeToUI(FALSE);
                    }
                }
                break;
            }
    }

    Release();
    return;
}


//+---------------------------------------------------------------------------
//
// CTipbarWnd::OnSysColoeChange
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnSysColorChange()
{
    KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);
    SetTimer(TIPWND_TIMER_SYSCOLORCHANGED, g_uTimerElapseSYSCOLORCHANGED);
}

//+---------------------------------------------------------------------------
//
// OnUser
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnUser(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
     POINT pt;

     switch (uMsg)
     {
         case WM_LBWND_SHOWCONTEXTMENU:
             pt.x = LOWORD(lParam);
             pt.y = HIWORD(lParam);
             MyClientToScreen(&pt, NULL);
             ShowContextMenu(pt, NULL, TRUE);
             break;

         default:
             if (uMsg == g_wmTaskbarCreated)
             {
                 shellwnd.Clear();
             }
             break;
     }
}

//+---------------------------------------------------------------------------
//
// OnSettingChange
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
        case 0:
        case SPI_SETHIGHCONTRAST:
        case SPI_SETNONCLIENTMETRICS:
            KillTimer(TIPWND_TIMER_SYSCOLORCHANGED);
            SetTimer(TIPWND_TIMER_SYSCOLORCHANGED, g_uTimerElapseSYSCOLORCHANGED);
            break;
    }
    return 0;
}

//+---------------------------------------------------------------------------
//
// OnDisplayChange
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnDisplayChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

    if (!_fInDeskBand)
    {
        KillTimer(TIPWND_TIMER_DISPLAYCHANGE);
        SetTimer(TIPWND_TIMER_DISPLAYCHANGE, g_uTimerElapseDISPLAYCHANGE);
    }
    return CUIFWindow::OnDisplayChange(hWnd, uMsg, wParam, lParam);
}

//+---------------------------------------------------------------------------
//
// AdjustPosOnDisplayChange
//
//----------------------------------------------------------------------------

void CTipbarWnd::AdjustPosOnDisplayChange()
{
    RECT rc;
    RECT rcWnd;
    int xWnd = _xWnd;
    int yWnd = _yWnd;

    Assert(!_fInDeskBand);

    rcWnd.left = _xWnd;
    rcWnd.top = _yWnd;
    rcWnd.right = _xWnd + _nWidth;
    rcWnd.bottom = _yWnd + _nHeight;
    if (!GetWorkArea(&rcWnd, &rc))
        return;

    if (_fPosLeft)
        xWnd = rc.left;

    if (_fPosTop)
        yWnd = rc.top;

    if (_fPosRight)
        xWnd = rc.right - _nWidth;

    if (_fPosBottom)
        yWnd = rc.bottom - _nHeight;

    if ((xWnd != _xWnd) || (yWnd != _yWnd))
        Move(xWnd, yWnd, _nWidth, _nHeight);
}

//+---------------------------------------------------------------------------
//
// UpdatePosFlags
//
//----------------------------------------------------------------------------

#define POSFLAG_MARGIN 2

void CTipbarWnd::UpdatePosFlags()
{
    RECT rc;
    RECT rcWnd;

    if (_fInDeskBand)
        return;


    rcWnd.left = _xWnd;
    rcWnd.top = _yWnd;
    rcWnd.right = _xWnd + _nWidth;
    rcWnd.bottom = _yWnd + _nHeight;
    if (!GetWorkArea(&rcWnd, &rc))
        return;

    if (_xWnd <= rc.left + POSFLAG_MARGIN)
        _fPosLeft = TRUE;
    else
        _fPosLeft = FALSE;

    if (_yWnd <= rc.top + POSFLAG_MARGIN)
        _fPosTop = TRUE;
    else
        _fPosTop = FALSE;

    if (_xWnd + _nWidth >= rc.right - POSFLAG_MARGIN)
        _fPosRight = TRUE;
    else
        _fPosRight = FALSE;

    if (_yWnd + _nHeight >= rc.bottom - POSFLAG_MARGIN)
        _fPosBottom = TRUE;
    else
        _fPosBottom = FALSE;

}

//+---------------------------------------------------------------------------
//
// AutoAdjustDeskBandSize
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::AutoAdjustDeskBandSize()
{
    if (_fDeskbandSizeAdjusted)
        return FALSE;

    if (!_pFocusThread)
        return FALSE;

    if (_pFocusThread->IsCtfmonProcess())
        return FALSE;

    //
    // if _fAdjustDeskbandIfNoRoom is on, don't put fFit so we don't 
    // do anything if there is a room.
    //
    BOOL fFit = TRUE;
    if (_fAdjustDeskbandIfNoRoom)
        fFit = FALSE;

    _fAdjustDeskbandIfNoRoom = FALSE;

    if (AdjustDeskBandSize(fFit))
    {
        SetDeskbandSizeAdjusted();
        return TRUE;
    }

    return FALSE;
}

//+---------------------------------------------------------------------------
//
// AdjustDeskBandSize
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::AdjustDeskBandSize(BOOL fFit)
{
    if (!_fInDeskBand)
        return FALSE;

    if (!_pDeskBand)
        return FALSE;

    return _pDeskBand->ResizeRebar(GetWnd(), 
                                   IsVertical() ? _nHeight : _nWidth, 
                                   fFit);
}

//+---------------------------------------------------------------------------
//
// GetThread
//
//----------------------------------------------------------------------------

CTipbarThread *CTipbarWnd::GetThread(DWORD dwThreadId)
{
    int i;
    for (i = 0; i < _rgThread.Count(); i++)
    {
        CTipbarThread *pThread = _rgThread.Get(i);
        if (!pThread)
            continue;

        if (pThread->_dwThreadId == dwThreadId)
        {
            if (TF_GetThreadFlags(dwThreadId, NULL, NULL, NULL))
            {
                return pThread;
            }
        }
    }

    return NULL;
}

//+---------------------------------------------------------------------------
//
// RestoreLastFocs
//
//----------------------------------------------------------------------------

void CTipbarWnd::RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev)
{
    if (_putb)
        _putb->RestoreLastFocus(pdwThreadId, fPrev);
}

//+---------------------------------------------------------------------------
//
// StartModalInput
//
//----------------------------------------------------------------------------

void CTipbarWnd::StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId)
{
    if (!_putb)
        return;

    _putb->SetModalInput(pSink, dwThreadId, 0);

    //
    // we want this to track a mouse event of Tray window.
    //
    if (g_pTrayIconWnd)
        _putb->SetModalInput(pSink, g_pTrayIconWnd->GetThreadIdTray(), 0);

    //
    // we want this to track a mouse event of CMD prompt window.
    //
    _putb->SetModalInput(pSink, GetCurrentThreadId(), TF_LBSMI_FILTERCURRENTTHREAD );
}

//+---------------------------------------------------------------------------
//
// StopModalInput
//
//----------------------------------------------------------------------------

void CTipbarWnd::StopModalInput(DWORD dwThreadId)
{
    if (!_putb)
        return;

    _putb->SetModalInput(NULL, dwThreadId, 0);

    if (g_pTrayIconWnd)
        _putb->SetModalInput(NULL, g_pTrayIconWnd->GetThreadIdTray(), 0);

    _putb->SetModalInput(NULL, GetCurrentThreadId(), 0);
}

//+---------------------------------------------------------------------------
//
// ClearLBItemList
//
//----------------------------------------------------------------------------

void CTipbarWnd::ClearLBItemList()
{
    _itemList.Clear();
    if (_pFocusThread)
    {
        OnThreadItemChange(_pFocusThread->_dwThreadId);
    }
}

//+---------------------------------------------------------------------------
//
// ShowMenuExtendMenu
//
//----------------------------------------------------------------------------

void CTipbarWnd::ShowContextMenu(POINT pt, RECT *prc, BOOL fExtendMenuItems)
{
    CUTBContextMenu *pMenu = NULL;
    RECT rc;
    CTipbarThread *ptt = GetFocusThread();
    DWORD dwThreadId;
    UINT uId = CUI_MENU_UNSELECTED;

    //
    // CTipbarWnd could be destroyed during ShowPopup().
    //
    AddRef();

    if (!prc)
    {
        rc.left   = pt.x;
        rc.top    = pt.y;
        rc.right  = pt.x;
        rc.bottom = pt.y;
        prc = &rc;
    }

    if (!ptt)
        goto Exit;

    pMenu = new CUTBContextMenu(this);
    if (!pMenu)
        goto Exit;

    if (!pMenu->Init())
        goto Exit;

    _pttModal = ptt;
    StartModalInput(this, ptt->_dwThreadId);

    dwThreadId = GetCurrentThreadId();
    _pModalMenu = pMenu;

    uId = pMenu->ShowPopup(this, pt, prc, fExtendMenuItems);

    _pModalMenu = NULL;

    if (_pttModal)
        StopModalInput(_pttModal->_dwThreadId);
    _pttModal = NULL;

    if (uId != CUI_MENU_UNSELECTED)
    {
        pMenu->SelectMenuItem(uId);
    }

Exit:
    if (pMenu)
        delete pMenu;

    Release();
}

//+---------------------------------------------------------------------------
//
// IsInItemChangOrDirty
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::IsInItemChangeOrDirty(CTipbarThread *pThread)
{
    if (pThread->_dwThreadId == _dwThreadItemChangedForTimer)
        return TRUE;

    return pThread->IsDirtyItem();
}

//+---------------------------------------------------------------------------
//
// OnGetObject
//
//----------------------------------------------------------------------------

LRESULT CTipbarWnd::OnGetObject( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = (LRESULT)0;

    switch (lParam) 
    {
        //
        // We process the OBJID_CLIENT object identifier;
        // this is the client area of our application
        // window.
        //

        case OBJID_CLIENT: 
        {
            HRESULT hr;

            if (_pTipbarAcc == NULL) 
            {
                return E_OUTOFMEMORY;
            }


            if (!_pTipbarAcc->IsInitialized()) 
            {
                //
                //
                //
                hr = EnsureCoInit();
                if (FAILED(hr)) 
                {
                    break;
                }
     

                //
                //    Initialize our Accessible object.  If the
                //      initialization fails, delete the Accessible
                //      object and return the failure code.
                //

                hr = _pTipbarAcc->Initialize();
                if (FAILED(hr)) 
                {
                    _pTipbarAcc->Release();
                    _pTipbarAcc = NULL;

                    lResult = (LRESULT)hr;
                    break;
                }

                //
                //    Send an EVENT_OBJECT_CREATE WinEvent for the
                //      creation of the Accessible object for the
                //      client area.
                //

                _pTipbarAcc->NotifyWinEvent( EVENT_OBJECT_CREATE , this);
            }

            //
            //    Call LresultFromObject() to create reference to
            //      our Accessible object that MSAA will marshal to
            //      the client.
            //

            lResult = _pTipbarAcc->CreateRefToAccObj( wParam );
            break;
        }

    }


    return lResult;
}

//+---------------------------------------------------------------------------
//
// OnThemeChanged
//
//----------------------------------------------------------------------------

void CTipbarWnd::OnThemeChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
#ifdef USE_OFC10LOOKONWINXP
    CheckO10Flag();
#endif
    CUIFWindow::OnThemeChanged(hwnd, wParam, lParam);
}

//+---------------------------------------------------------------------------
//
// StartDoDefaultActionTimer
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::StartDoAccDefaultActionTimer(CTipbarItem *pItem)
{
   if (!_pTipbarAcc)
       return FALSE;

   _nDoAccDefaultActionItemId = _pTipbarAcc->GetIDOfItem(pItem);
   if ((_nDoAccDefaultActionItemId == 0) || (_nDoAccDefaultActionItemId == -1))
       return FALSE;

   KillTimer(TIPWND_TIMER_DOACCDEFAULTACTION);
   SetTimer(TIPWND_TIMER_DOACCDEFAULTACTION, g_uTimerElapseDOACCDEFAULTACTION);

   return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarThread
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarThread::CTipbarThread(CTipbarWnd *ptw)
{

    Dbg_MemSetThisName(TEXT("CTipbarThread"));

    _ptw = ptw;
    _dwThreadId = 0;
    _plbim = NULL;
    _ref = 1;
}

//+---------------------------------------------------------------------------
//
// Init
//
//----------------------------------------------------------------------------

HRESULT CTipbarThread::Init(DWORD dwThreadId)
{
    DWORD dwThreadIdTmp;
    HRESULT hr = S_OK;

    _dwThreadId = dwThreadId;

    if (!TF_GetThreadFlags(_dwThreadId, &_dwThreadFlags, &_dwProcessId, &_dwTickTime))
       return E_FAIL;

    if (IsConsole())
       return S_OK;

    // What's happening: we eventually reach InternalGetThreadUIManager
    // which, if _dwThreadId is NULL, will substitute 
    // g_ShareMem.dwActiveThreadId.
    // This is dangerous, because if the active thread does not match
    // this one we'll do rpc and _plbim will be on the wrong thread.
    // Passing in _dwThreadId seems like the right thing to do....
    
    hr = _ptw->GetLangBarMgr()->GetThreadLangBarItemMgr(_dwThreadId, &_plbim, &dwThreadIdTmp);
    if (FAILED(hr))
        return hr;

    Assert(dwThreadIdTmp == _dwThreadId);

    return hr;
}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarThread::~CTipbarThread()
{
#ifdef DEBUG
    Assert(!_fInCallOnUpdateHandler);
#endif

    if (_ptw)
    {
        Assert(this != _ptw->GetFocusThread());
        RemoveUIObjs();

        _ptw->CleanUpThreadPointer(this, TRUE);
    }

    _UninitItemList(TRUE);
    SafeReleaseClear(_plbim);
}

//+---------------------------------------------------------------------------
//
// _AddRef
//
//----------------------------------------------------------------------------

ULONG CTipbarThread::_AddRef( )
{
    _ref++;

    return _ref;
}

//+---------------------------------------------------------------------------
//
// _Release
//
//----------------------------------------------------------------------------

ULONG CTipbarThread::_Release( )
{
    ULONG cr;
 
    _ref--;

    cr = _ref;

    if (cr == 0) {
        delete this;
    }

    return cr;
}

//+---------------------------------------------------------------------------
//
// SetFocus
//
//----------------------------------------------------------------------------

BOOL CTipbarThread::SetFocus(BOOL fFocus)
{

    if (!fFocus)
    {
        int i;
        for (i = 0; i < _rgItem.Count(); i++)
        {
            CTipbarItem *pItem = _rgItem.Get(i);
            CTipbarBalloonItem *pballoon;
            if (pItem &&
                SUCCEEDED(pItem->QueryInterface(IID_PRIV_BALLOONITEM, (void **)&pballoon)))
            {
                pballoon->DestroyBalloonTip();
                pballoon->Release();
            }
        }

    }
    return TRUE;
}

//+---------------------------------------------------------------------------
//
// InitItemList
//
//----------------------------------------------------------------------------
#define NUM_GETITEMATONCE   30

HRESULT CTipbarThread::InitItemList()
{
    HRESULT hr = E_FAIL;
    IEnumTfLangBarItems *pEnum = NULL;
    RECT rc;
    CEnumCatCache *penumcache = NULL;
    CGuidDwordCache *pgdcache = NULL;

    if (!_ptw)
        return hr;

    SIZE sizeWndFrame;
    sizeWndFrame.cx = 0;
    sizeWndFrame.cy = 0;
    if (_ptw->GetWndFrame() != NULL) 
        _ptw->GetWndFrame()->GetFrameSize( &sizeWndFrame );

    _ptw->InitThemeMargins();

    if (!IsVertical())
    {
        rc.left   = _ptw->GetGripperWidth() + 1 + sizeWndFrame.cx;
        rc.top    = 0 + sizeWndFrame.cy;
        rc.right  = 0;
        rc.bottom = _ptw->GetTipbarHeight() - sizeWndFrame.cy;
    }
    else
    {
        rc.left   = 0 + sizeWndFrame.cx;
        rc.top    = _ptw->GetGripperWidth() + 1 + sizeWndFrame.cy;
        rc.right  = _ptw->GetTipbarHeight() - sizeWndFrame.cx;
        rc.bottom = 0;
    }


    _nNumItem = 0;

    penumcache = new CEnumCatCache;
    if (!penumcache)
    {
        TraceMsg(TF_FUNC, "could not create CEnumCatCache");
        goto Exit;
    }

    pgdcache = new CGuidDwordCache;
    if (!pgdcache)
    {
        TraceMsg(TF_FUNC, "could not create CGuidDwordCache");
        goto Exit;
    }

    if (_plbim)
    {
        ULONG ulFetched = 0;
        ITfLangBarItem *plbi[NUM_GETITEMATONCE] = {NULL};
        TF_LANGBARITEMINFO lbiInfo[NUM_GETITEMATONCE];
        DWORD dwStatus[NUM_GETITEMATONCE];
        ULONG ul;
        if (SUCCEEDED(hr = _plbim->GetItems(NUM_GETITEMATONCE, 
                                            plbi, 
                                            lbiInfo, 
                                            dwStatus, 
                                            &ulFetched)) && ulFetched)
        {
            for (ul = 0; ul < ulFetched; ul++)
            {
                if (plbi[ul])
                {
                    if (SUCCEEDED(hr))
                    {
                        if (!InsertItem(plbi[ul], 
                                   penumcache, 
                                   pgdcache, 
                                   &rc,
                                   _ptw->GetThemeMargins(),
                                   &lbiInfo[ul], 
                                   &dwStatus[ul]))
                        {
                            hr =  E_FAIL;
                        }
                    }

                    plbi[ul]->Release();
                }
            }

        }

        if (SUCCEEDED(hr))
            _AdviseItemsSink();
    }
    else if (IsConsole())
    {
        CLBarInatItem *pInatItem = new CLBarInatItem(_dwThreadId);
        if (pInatItem)
        {
#ifdef DEBUG
            Assert(!_fIsInatItem);
            _fIsInatItem = TRUE;
#endif

            TF_LANGBARITEMINFO lbiInfo;
            DWORD dwStatus;
            pInatItem->GetInfo(&lbiInfo);
            pInatItem->GetStatus(&dwStatus);
            InsertItem(pInatItem, penumcache, pgdcache, &rc, _ptw->GetThemeMargins(), &lbiInfo, &dwStatus);

            pInatItem->Release();

            _AdviseItemsSink();
            hr = S_OK;
        }
    }

    LocateItems();

Exit:

    if (penumcache)
        delete penumcache;

    if (pgdcache)
        delete pgdcache;

    return hr;
}

//+---------------------------------------------------------------------------
//
// GetTextSize
//
//----------------------------------------------------------------------------

void CTipbarThread::GetTextSize(BSTR bstr, SIZE *psize)
{
    HFONT hfontOld = NULL;
    HDC hdc = GetDC(_ptw->GetWnd());

    if (SUCCEEDED(_ptw->EnsureThemeData(_ptw->GetWnd())))
    {
        RECT rcText;
        LOGFONTW lf;
        HFONT hfont = NULL;
        CUIFTheme themeBtn;

        Assert(IsOnNT51());

        themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);

        if (SUCCEEDED(themeBtn.OpenThemeData(_ptw->GetWnd())))
        {
            if (SUCCEEDED(themeBtn.GetThemeFont(NULL, 0 , TMT_FONT, &lf)))
                if (hfont = CreateFontIndirectW(&lf))
                    hfontOld = (HFONT)SelectObject(hdc, hfont);

            themeBtn.GetThemeTextExtent(hdc, 0 , bstr, SysStringLen(bstr),0, NULL, &rcText);
        }
        psize->cx = rcText.right;
        psize->cy = rcText.bottom;
 

        if (hfontOld)
            SelectObject(hdc, hfontOld);

        if (hfont)
            DeleteObject(hfont);
    }
    else
    {
        if (_ptw->GetFont())
            hfontOld = (HFONT)SelectObject(hdc, _ptw->GetFont());

        FLGetTextExtentPoint32( hdc, bstr, SysStringLen(bstr), psize);

        if (hfontOld)
            SelectObject(hdc, hfontOld);
    }


    ReleaseDC(_ptw->GetWnd(), hdc);
}

//+---------------------------------------------------------------------------
//
// InsertItem
//
//----------------------------------------------------------------------------

BOOL CTipbarThread::InsertItem(ITfLangBarItem *plbi, CEnumCatCache *penumcache, CGuidDwordCache *pgdcache, RECT *prc, MARGINS *pmargins, TF_LANGBARITEMINFO *plbiInfo, DWORD *pdwStatus)
{
    ITfLangBarItemButton *plbiButton = NULL;
    ITfLangBarItemBitmapButton *plbiBitmapButton = NULL;
    ITfLangBarItemBitmap *plbiBitmap = NULL;
    ITfLangBarItemBalloon *plbiBalloon = NULL;
    CTipbarItem *ptbItem = NULL;
    RECT rc = {0, 0, 0, 0};
    BOOL bRet = FALSE;
    BSTR bstrText = NULL;

    Assert(plbi);

    if ((SUCCEEDED(plbi->QueryInterface(IID_ITfLangBarItemButton, 
                                       (void **)&plbiButton))) ||
        (SUCCEEDED(plbi->QueryInterface(IID_ITfLangBarItemBitmapButton, 
                                       (void **)&plbiBitmapButton))))
    {
        if (!_ptw)
            goto Next;

        SIZE sizeText = {0,0};
        DWORD dwNuiBtnStyle = 0;
        DWORD dwSBtnShowType = 0;
        int nWidth = _ptw->GetSmIconWidth() + _ptw->GetItemMargin();

        if (_ptw->IsShowText())
        {
            dwSBtnShowType |= UITBBUTTON_TEXT;
            HRESULT hr;

            if (plbiButton)
               hr = plbiButton->GetText(&bstrText);
            else if (plbiBitmapButton)
               hr = plbiBitmapButton->GetText(&bstrText);
            else 
               goto Next;

            //
            // check if it is disconnected.
            //
            if (!_ptw)
               goto Next;

            if (SUCCEEDED(hr) && bstrText)
            {

                GetTextSize(bstrText, &sizeText);
                //
                // use height for text margin.
                //
                nWidth += (sizeText.cx + (sizeText.cy / 2));
            }
        }

        nWidth += pmargins->cxLeftWidth;
        nWidth += pmargins->cxRightWidth;

        dwNuiBtnStyle =  plbiInfo->dwStyle & 
                         (TF_LBI_STYLE_BTN_BUTTON | 
                          TF_LBI_STYLE_BTN_MENU | 
                          TF_LBI_STYLE_BTN_TOGGLE);

        if ((dwNuiBtnStyle & (TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_BTN_MENU))
             == (TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_BTN_MENU))
            nWidth += 14;

        if (!IsVertical())
        {
            prc->right  = prc->left + nWidth;
        }
        else
        {
            prc->bottom = prc->top + nWidth;
            dwNuiBtnStyle |= UITBBUTTON_VERTICAL;
        }

        if (plbiButton)
        {
            ptbItem = new CTipbarButtonItem(this, 
                                      plbiButton, 
                                      plbiButton, 
                                      0, 
                                      prc, 
                                      0,
                                      dwNuiBtnStyle,
                                      dwSBtnShowType,
                                      plbiInfo,
                                      *pdwStatus);
        }
        else if (plbiBitmapButton)
        {
            ptbItem = new CTipbarBitmapButtonItem(this, 
                                      plbiBitmapButton, 
                                      plbiBitmapButton, 
                                      0, 
                                      prc, 
                                      0,
                                      dwNuiBtnStyle,
                                      dwSBtnShowType,
                                      plbiInfo,
                                      *pdwStatus);
        }
        else
        {
            Assert(0);
            goto Next;
        }

        if (!ptbItem)
            goto Next;

        ptbItem->Init();

        if (IsVertical())
            ptbItem->SetFont(_ptw->GetVerticalFont());

        ptbItem->SetText((bstrText && SysStringLen(bstrText)) ? bstrText : NULL);
        ptbItem->SetTextSize(&sizeText);

        GetSortScore(ptbItem->GetItemSortScore(), plbiInfo, penumcache, pgdcache);
        ptbItem->SetWidth(nWidth);

    }
    else if (SUCCEEDED(plbi->QueryInterface(IID_ITfLangBarItemBitmap, 
                                            (void **)&plbiBitmap)))
    {
        if (!_ptw)
            goto Next;

        if (!plbiBitmap)
            goto Next;

        SIZE sizeDefault = {_ptw->GetSmIconWidth() * 2,
                            _ptw->GetSmIconHeight()};
        SIZE size;
        plbiBitmap->GetPreferredSize(&sizeDefault, &size);

        if (!_ptw)
            goto Next;

        if (!IsVertical())
            prc->right  = prc->left + size.cx;
        else
            prc->bottom  = prc->top + size.cx;

        ptbItem = new CTipbarBitmapItem(this, 
                                  plbiBitmap, 
                                  plbiBitmap, 
                                  0, 
                                  prc, 
                                  0,
                                  plbiInfo,
                                  *pdwStatus);

        if (!ptbItem)
            goto Next;

        ptbItem->Init();
        GetSortScore(ptbItem->GetItemSortScore(), plbiInfo, penumcache, pgdcache);
        ptbItem->SetWidth(size.cx);
    }
    else if (SUCCEEDED(plbi->QueryInterface(IID_ITfLangBarItemBalloon, 
                                            (void **)&plbiBalloon)))
    {
        if (!_ptw)
            goto Next;

        if (!plbiBalloon)
            goto Next;

        SIZE sizeDefault = {32,16};
        SIZE size;
        plbiBalloon->GetPreferredSize(&sizeDefault, &size);

        if (!_ptw)
            goto Next;

        if (!IsVertical())
            prc->right  = prc->left + size.cx;
        else
            prc->bottom  = prc->top + size.cx;

        ptbItem = new CTipbarBalloonItem(this, 
                                         plbiBalloon, 
                                         plbiBalloon, 
                                         0, 
                                         prc, 
                                         0,
                                         plbiInfo,
                                         *pdwStatus);

        if (!ptbItem)
            goto Next;

        ptbItem->Init();

        if (IsVertical())
            ptbItem->SetFont(_ptw->GetVerticalFont());

        GetSortScore(ptbItem->GetItemSortScore(), plbiInfo, penumcache, pgdcache);
        ptbItem->SetWidth(size.cx);

    }

Next:
    SafeReleaseClear(plbiButton);
    SafeReleaseClear(plbiBitmapButton);
    SafeReleaseClear(plbiBitmap);
    SafeReleaseClear(plbiBalloon);

    if (!_ptw && ptbItem)
    {
        delete ptbItem;
        ptbItem = NULL;
    }
        
    if (ptbItem)
    {
        CTipbarItem **pptbItem = _rgItem.Append(1);
        if (pptbItem)
        {
            *pptbItem = ptbItem;

            if (!IsVertical())
               prc->left = prc->right;
            else
               prc->top = prc->bottom;

            _nNumItem++;
            bRet = TRUE;
        }
        else
        {
            delete ptbItem;
            ptbItem = NULL;
        }
    }

    if (bstrText)
        SysFreeString(bstrText);

    return bRet;
}

//+---------------------------------------------------------------------------
//
// _UninitItemList
//
//----------------------------------------------------------------------------

HRESULT CTipbarThread::_UninitItemList(BOOL fUnAdvise)
{
    int i = 0;
    HRESULT hr = S_OK;

    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (!pItem)
            continue;

        pItem->Disconnect();
    }

    if (fUnAdvise)
    {
        if ((_dwThreadId == GetCurrentThreadId()) ||
            !MyWaitForInputIdle(_dwThreadId, UTB_INPUTIDLETIMEOUT))
           hr = _UnadviseItemsSink();
    }

    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (!pItem)
            continue;

        if (_ptw)
            pItem->RemoveMeToUI(_ptw);

        pItem->ClearConnections();

        if (!_ptw)
            pItem->ClearWnd();
        else
            pItem->DetachWnd();
        pItem->UninitUIResource();
        pItem->Release();
    }

    _rgItem.Clear();

    RemoveAllSeparators();
 
    return hr;
}

//+---------------------------------------------------------------------------
//
// _AdviseItemsSink
//
//----------------------------------------------------------------------------

void CTipbarThread::_AdviseItemsSink()
{
    HRESULT hr;
    int nCnt = _rgItem.Count();
    int i = 0;
    ITfLangBarItemSink **pplbis = NULL;
    GUID *pguid = NULL;
    DWORD *pdwCookie = NULL;

    if (!_plbim || !nCnt)
        goto Exit;

    pplbis = new ITfLangBarItemSink*[nCnt];
    if (!pplbis)
        goto Exit;

    pguid = new GUID[nCnt];
    if (!pguid)
        goto Exit;
    
    pdwCookie = new DWORD[nCnt];
    if (!pdwCookie)
        goto Exit;
    
    for (i = 0; (i < nCnt) && (i < _rgItem.Count()); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (!pItem)
        {
            Assert(0);
            goto Exit;
        }

        pguid[i] = *pItem->GetGUID();

        hr = pItem->QueryInterface(IID_ITfLangBarItemSink, (void **)&pplbis[i]);
        if (FAILED(hr))
        {
            Assert(0);
            goto Exit;
        }


    }
   
    if (FAILED(_plbim->AdviseItemsSink(nCnt, pplbis, pguid, pdwCookie)))
        goto Exit;

    for (i = 0; (i < nCnt) && (i < _rgItem.Count()); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (pItem)
            pItem->_dwlbiSinkCookie = pdwCookie[i];

        pplbis[i]->Release();
    }

Exit:
    if (pplbis)
        delete[] pplbis;
    if (pguid)
        delete[] pguid;
    if (pdwCookie)
        delete[] pdwCookie;
}

//+---------------------------------------------------------------------------
//
// _UnadviseItemsSink
//
//----------------------------------------------------------------------------

HRESULT CTipbarThread::_UnadviseItemsSink()
{
    int nCnt = _rgItem.Count();
    int i = 0;
    DWORD *pdwCookie = NULL;
    HRESULT hr = S_OK;

    if (!nCnt)
        goto Exit;

    if (!_plbim)
    {
        hr = E_FAIL;
        goto Exit;
    }
    
    pdwCookie = new DWORD[nCnt];
    if (!pdwCookie)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }
    
    for (i = 0; i < nCnt; i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (pItem)
            pdwCookie[i] = pItem->_dwlbiSinkCookie;
    }
   
    if (FAILED(hr = _plbim->UnadviseItemsSink(nCnt, pdwCookie)))
        goto Exit;
Exit:
    if (pdwCookie)
        delete[] pdwCookie;


    return hr;
}

//+---------------------------------------------------------------------------
//
// IsHKLToSkipRedrawOnNoItem
//
//----------------------------------------------------------------------------

BOOL CTipbarWnd::IsHKLToSkipRedrawOnNoItem()
{
    return IsSkipRedrawHKL(GetFocusKeyboardLayout());
}

//+---------------------------------------------------------------------------
//
// LocateItems
//
//----------------------------------------------------------------------------

void CTipbarThread::LocateItems()
{
    int i = 0;
    SIZE sizeWndFrame;
    POINT pt;
    RECT rcWork;
    RECT rc;
    BOOL fOverScreen = FALSE;
    int nTipbarHeight;

    _fSkipRedrawOnNoItem = FALSE;

    if (!_ptw)
        return;

    _ptw->GetRect(&rc);

    pt.x = rc.left;
    pt.y = rc.top;
    CUIGetWorkAreaRect(pt, &rcWork);

    sizeWndFrame.cx = 0;
    sizeWndFrame.cy = 0;
    if (_ptw->GetWndFrame() != NULL) 
        _ptw->GetWndFrame()->GetFrameSize( &sizeWndFrame );

    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *ptbItem = _rgItem.Get(i);
        CTipbarItem *ptbMin = NULL;
        if (!ptbItem)
            continue;
         

        int j;
        CItemSortScore issMin(-1, -1, -1);
        int nMin;

        for (j = i; j < _rgItem.Count(); j++)
        {
             CTipbarItem *ptb = _rgItem.Get(j);
             CItemSortScore *piss = ptb->GetItemSortScore();
             if (issMin > *piss)
             {
                 ptbMin = ptb;
                 issMin = *piss;
                 nMin = j;
             }
        }
        if (ptbMin)
        {
            CTipbarItem **pptbItem = _rgItem.GetPtr(i);
            CTipbarItem **pptbMin = _rgItem.GetPtr(nMin);

            *pptbItem = ptbMin;
            *pptbMin = ptbItem;
        }

    }

LocateItemsAgain:
    RemoveAllSeparators();

    nTipbarHeight = _ptw->GetTipbarHeight();
    if (!IsVertical())
    {
        rc.left   = 1 + _ptw->GetGripperWidth() + sizeWndFrame.cx;

        if (rc.bottom - rc.top > nTipbarHeight)
        {
            int nHeightPadding = (rc.bottom - rc.top - nTipbarHeight) / 2;

            if (nHeightPadding > CY_ITEMMARGIN_THEME)
                nHeightPadding -= CY_ITEMMARGIN_THEME;
            else
                nHeightPadding = 0;

            rc.top    += (0 + sizeWndFrame.cy + nHeightPadding);
            rc.bottom -= (sizeWndFrame.cy + nHeightPadding);
        }
        else
        {
            rc.top    = 0 + sizeWndFrame.cy;
            rc.bottom = nTipbarHeight - sizeWndFrame.cy;
        }

    }
    else
    {
        rc.top   = 1 + _ptw->GetGripperWidth() + sizeWndFrame.cx;

        if (rc.right - rc.left > nTipbarHeight)
        {
            int nHeightPadding = (rc.right - rc.left - nTipbarHeight) / 2;

            if (nHeightPadding > CY_ITEMMARGIN_THEME)
                nHeightPadding -= CY_ITEMMARGIN_THEME;
            else
                nHeightPadding = 0;

            rc.left  += (0 + sizeWndFrame.cy + nHeightPadding);
            rc.right -= (sizeWndFrame.cy + nHeightPadding);
        }
        else
        {
            rc.left  = 0 + sizeWndFrame.cy;
            rc.right = nTipbarHeight - sizeWndFrame.cy;
        }
    }

    i = 0;
    DWORD dwCatScore = 0;
    ULONG ulShownItemInPrevCat = 0;
    BOOL bShowToolbar = FALSE;
    LANGID langid = LANGID(LOWORD(HandleToLong(_ptw->GetFocusKeyboardLayout())));

    CTipbarItem *ptbLastHiddenableItem = NULL;

    while (i < _rgItem.Count())
    {
        LANGBARITEMSTATE *pItemState;
        CTipbarItem *ptbItem = _rgItem.Get(i);
        DWORD dwWidth = ptbItem->GetWidth();

        if (ptbItem->IsHiddenStatusControl())
        {
            if (ptbItem->IsInHiddenStatus())
                goto HideThis;
        }
        else
        {
            pItemState = _ptw->_itemList.FindItem(*ptbItem->GetGUID());
            if (pItemState)
            {
                if (!pItemState->IsShown())
                    goto HideThis;
            }
            else
            {
                if (ptbItem->IsHiddenByDefault())
                    goto HideThis;
            }
            ptbLastHiddenableItem = ptbItem;
        }

        if (_ptw->IsSFDeskband() && _ptw->IsSFNoExtraIcon())
        {
            REFGUID rguidItem = *ptbItem->GetGUID();

            if (!IsEqualGUID(rguidItem, GUID_TFCAT_TIP_KEYBOARD) &&
                !IsEqualGUID(rguidItem, GUID_LBI_INATITEM) &&
                !IsEqualGUID(rguidItem, GUID_LBI_CTRL) &&
                (!IsFELangId(langid) || (IsFELangId(langid) && !ptbItem->IsShownInTray())))
                goto HideThis;
        }

        if (ptbItem->IsShownInTrayOnly())
        {
HideThis:
            RECT rcEmp = {0, 0, 0, 0};
            ptbItem->SetRect(&rcEmp);
            ptbItem->VisibleInToolbar(FALSE);
            goto Next;
        }

        if (!ptbItem->IsHiddenStatusControl())
            _ptw->_itemList.StartDemotingTimer(*ptbItem->GetGUID(), FALSE);

        //
        // If we find an Item to be shown, we show toolbar.
        // If we have only "HideOnNoOterItems" to be shown, we hide toolbar.
        //
        if (!ptbItem->IsHideOnNoOtherItems())
        {
            bShowToolbar = TRUE;
        }

        if (ulShownItemInPrevCat && (dwCatScore != ptbItem->GetCatScore()))
        {
            DWORD dwSepStyle = 0;
            if (!IsVertical())
                rc.right  = rc.left + _ptw->GetItemDistance();
            else
            {
                rc.bottom = rc.top + _ptw->GetItemDistance();
                dwSepStyle |= UITBSEPARATOR_VERTICAL;
            }

            CUIFSeparator *pSep = new CUIFSeparator(_ptw, -1, &rc, dwSepStyle);
            if (pSep)
            {
                int nCntSep = _rgSep.Count();
                pSep->Initialize();

                if (_rgSep.Insert(nCntSep, 1))
                {
                    _rgSep.Set(nCntSep, pSep);
                }
                else
                {
                    delete pSep;
                    pSep = NULL;
                }
            }

            if (!IsVertical())
               rc.left = rc.right;
            else
               rc.top = rc.bottom;

            ulShownItemInPrevCat = 0;
        }

        dwCatScore = ptbItem->GetCatScore();

        if (!IsVertical())
            rc.right  = rc.left + dwWidth;
        else
            rc.bottom  = rc.top + dwWidth;

        ptbItem->SetRect(&rc);
        ptbItem->VisibleInToolbar(TRUE);

        if (!IsVertical())
           rc.left = rc.right;
        else
           rc.top = rc.bottom;

        ulShownItemInPrevCat++;
Next:
        i++;
    }

    // Add the last sepcarator
    if (!IsVertical())
       rc.right  = rc.left + 4;
    else
       rc.bottom  = rc.top + 4;

    DWORD dwSepStyle = 0;
    if (IsVertical())
       dwSepStyle |= UITBSEPARATOR_VERTICAL;

    CUIFSeparator *pSep = new CUIFSeparator(_ptw, -1, &rc, dwSepStyle);

    if (pSep)
    {
        int nCntSep = _rgSep.Count();
        pSep->Initialize();
        if (_rgSep.Insert(nCntSep, 1))
        {
            _rgSep.Set(nCntSep, pSep);
        }
        else
        {
            delete pSep;
            pSep = NULL;
        }
    }


    if (!IsVertical())
    {
        rc.left = rc.right;
        // allocate the space for ctrl buttons.
        rc.right  = rc.left + _ptw->GetCtrlButtonWidth();
    }
    else
    {
        rc.top = rc.bottom;
        // allocate the space for ctrl buttons.
        rc.bottom  = rc.top + _ptw->GetCtrlButtonWidth();
    }

    _sizeWnd.cx = rc.right + sizeWndFrame.cx;
    _sizeWnd.cy = rc.bottom + sizeWndFrame.cy;

    if (_ptw->GetWndFrame() != NULL) 
    {
        RECT rcWnd;
        rcWnd.left   = 0;
        rcWnd.top    = 0;
        rcWnd.right  = _sizeWnd.cx;
        rcWnd.bottom = _sizeWnd.cy;
        _ptw->GetWndFrame()->SetRect(&rcWnd);
    }

    //
    // If the window is wider than WorkArea, we hide one item and locate items
    // again.
    //
    if (_sizeWnd.cx > (rcWork.right - rcWork.left))
    {
        fOverScreen = TRUE;
        if (ptbLastHiddenableItem)
        {
            _ptw->_itemList.SetDemoteLevel(*ptbLastHiddenableItem->GetGUID(), 
                                           DL_HIDDENLEVEL1);
            goto LocateItemsAgain;
        }
    }

    //
    // Exclude caption buttons.
    //
    int dxOffset = 0;
    int dyOffset = 0;
    if (!IsVertical() && g_bExcludeCaptionButtons)
    {
        RECT rcWnd;
        _ptw->GetRect(&rcWnd);
        _ptw->MyClientToScreen(NULL, &rcWnd);
        if (_ptw->CheckExcludeCaptionButtonMode(&rcWnd, &rcWork))
        {
            if ((rcWnd.left + _sizeWnd.cx + _ptw->GetCxDlgFrame()) > 
                (rcWork.right - (_ptw->GetCaptionButtonWidth() * 3)))
            {
                dyOffset = 0 - rcWnd.top;
                dxOffset = (rcWork.right - (_ptw->GetCaptionButtonWidth() * 3)) - 
                           (rcWnd.left + _sizeWnd.cx + _ptw->GetCxDlgFrame());
                _ptw->SetRect(&rcWnd);
                _ptw->SetExcludeCaptionButtonMode(TRUE);
            }
        }
        else
            _ptw->SetExcludeCaptionButtonMode(FALSE);
    }

    MyMoveWnd(dxOffset, dyOffset);

    if (!_ptw)
        goto Exit;

    _ptw->_fIsItemShownInFloatingToolbar = bShowToolbar;
    //
    // We show or hide only when toolbar is floating arround.
    //
    if (IsFocusThread() && _ptw->IsSFShowNormal() && !_ptw->IsInFullScreen())
    {
        // 
        //  Satori Hack.
        // 
        // If the focus thread is running with Satori we don't hide 
        // the toolbar.
        // 
        if (!bShowToolbar && _ptw->IsHKLToSkipRedrawOnNoItem())
        {
            _fSkipRedrawOnNoItem = TRUE;
            goto Exit;
        }


        _ptw->_fShowWindowAtTimer = bShowToolbar;
        _ptw->_pThreadShowWindowAtTimer = this;
        _ptw->_fShowOverItemBalloonAtTimer = fOverScreen;

        _ptw->KillTimer(TIPWND_TIMER_SHOWWINDOW);
        _ptw->SetTimer(TIPWND_TIMER_SHOWWINDOW, g_uTimerElapseSHOWWINDOW);

#if 0
        _ptw->Show(bShowToolbar);

        //
        // If the window was over the screen and hide some items,
        // we show balloon tips.
        //
        if (fOverScreen)
            _ptw->ShowOverScreenSizeBalloon();
#endif
    }
Exit:
    return;
}

//+---------------------------------------------------------------------------
//
// GetSortScore
//
//----------------------------------------------------------------------------

void CTipbarThread::GetSortScore(CItemSortScore *pScore, TF_LANGBARITEMINFO *plbiInfo, CEnumCatCache *penumcache, CGuidDwordCache *pgdcache)
{
    DWORD dwSub = 0;
    DWORD dwCat = 0;
    DWORD dwCatIndex = 256;
    IEnumGUID *pEnum;
    BOOL bFound = FALSE;
    GUID guid;
  
    //
    // check system device type button.
    //
    if (pEnum = penumcache->GetEnumItemsInCategory(GUID_TFCAT_CATEGORY_OF_TIP))
    {
        while (!bFound && (pEnum->Next(1, &guid, NULL) == S_OK))
        {
            dwCatIndex++;

            if (!(dwCat = pgdcache->GetGuidDWORD(guid)))
               dwCat = dwCatIndex;

            if (IsEqualGUID(guid, plbiInfo->guidItem))
                bFound = TRUE;
            else
            {
                IEnumGUID *pEnumTip;
                if (pEnumTip = penumcache->GetEnumItemsInCategory(guid))
                {
                    CLSID clsid;
                    while (!bFound && (pEnumTip->Next(1, &clsid, NULL) == S_OK))
                    {

                        dwSub++;

                        if (IsEqualGUID(clsid, plbiInfo->clsidService))
                        {
                            bFound = TRUE;
                        }
                    }
                }
            }
        }
    }

    if (bFound)
    {
        pScore->Set(dwCat, plbiInfo->ulSort, dwSub);
        return;
    }

    //
    // check system toolbar button.
    //
    if (IsEqualGUID(GUID_NULL, plbiInfo->clsidService))
    {
        pScore->Set(0, plbiInfo->ulSort, 0);
        return;
    }
    else if (IsEqualGUID(CLSID_SYSTEMLANGBARITEM, plbiInfo->clsidService))
    {
        pScore->Set(0, plbiInfo->ulSort, 0);
        return;
    }
    else if (IsEqualGUID(CLSID_SYSTEMLANGBARITEM2, plbiInfo->clsidService))
    {
        pScore->Set((-1), plbiInfo->ulSort, 0);
        return;
    }
    else if (IsEqualGUID(CLSID_SYSTEMLANGBARITEM_KEYBOARD, plbiInfo->clsidService))
    {
        dwCat = pgdcache->GetGuidDWORD(GUID_TFCAT_TIP_KEYBOARD);
        pScore->Set(dwCat, plbiInfo->ulSort, (DWORD)-1);
        return;
    }
    else if (IsEqualGUID(CLSID_SYSTEMLANGBARITEM_SPEECH, plbiInfo->clsidService))
    {
        dwCat = pgdcache->GetGuidDWORD(GUID_TFCAT_TIP_SPEECH);
        pScore->Set(dwCat, plbiInfo->ulSort, (DWORD)-1);
        return;
    }
    else if (IsEqualGUID(CLSID_SYSTEMLANGBARITEM_HANDWRITING, plbiInfo->clsidService))
    {
        dwCat = pgdcache->GetGuidDWORD(GUID_TFCAT_TIP_HANDWRITING);
        pScore->Set(dwCat, plbiInfo->ulSort, (DWORD)-1);
        return;
    }

    pScore->Set((DWORD)-1, (DWORD)-1, (DWORD)-1);
    return;
}

//+---------------------------------------------------------------------------
//
// UpdateItems
//
//----------------------------------------------------------------------------

BOOL CTipbarThread::UpdateItems()
{
    int i;

    _fItemChanged = FALSE;

    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *ptbItem = _rgItem.Get(i);

        if (ptbItem)
            ptbItem->OnUpdate(TF_LBI_STATUS | TF_LBI_BTNALL | TF_LBI_BMPALL | TF_LBI_BALLOON);

    }

    for (i = 0; i < _rgSep.Count(); i++)
    {
        CUIFSeparator *pSep = _rgSep.Get(i);
        if (pSep)
            pSep->CallOnPaint();
    }
    return TRUE;
}


//+---------------------------------------------------------------------------
//
// MyMoveWnd
//
//----------------------------------------------------------------------------

void CTipbarThread::MyMoveWnd(int dxOffset, int dyOffset)
{
    if (!_ptw)
        return;

    if (_ptw->GetFocusThread() != this)
        return;

    POINT pt;
    RECT rc;
    RECT rcWork;

    _ptw->GetRect(&rc);
    pt.x = rc.left;
    pt.y = rc.top;
    CUIGetWorkAreaRect(pt, &rcWork);

    GetWindowRect(_ptw->GetWnd(), &rc);
    int x = rc.left + dxOffset;
    int y = rc.top + dyOffset;

    if (_ptw->IsInExcludeCaptionButtonMode())
    {
        //
        // now we're in exclude caption button mode.
        // adjust position to the next of caption buttons.
        //
        if (_ptw->CheckExcludeCaptionButtonMode(&rc, &rcWork))
        {
            x = (rcWork.right - (_ptw->GetCaptionButtonWidth() * 3)) -
                (_sizeWnd.cx + _ptw->GetCxDlgFrame());
            y = 0;
        }
        else
        {
            _ptw->SetExcludeCaptionButtonMode(FALSE);
        }
    }

    if (!IsVertical())
    {
        _ptw->SetMoveRect(x, y,
                          _sizeWnd.cx + _ptw->GetCxDlgFrame(),
                          _ptw->GetTipbarHeight() + _ptw->GetCyDlgFrame());
    }
    else
    {
        _ptw->SetMoveRect(x, y,
                          _ptw->GetTipbarHeight() + _ptw->GetCxDlgFrame(),
                          _sizeWnd.cy + _ptw->GetCyDlgFrame());
    }

    SIZE sizeWndFrame;
    sizeWndFrame.cx = 0;
    sizeWndFrame.cy = 0;
    if (_ptw->GetWndFrame() != NULL) 
        _ptw->GetWndFrame()->GetFrameSize( &sizeWndFrame );

    _ptw->LocateCtrlButtons();

    //
    // call AutoAdjustDeskBandSize() now.
    // this function adjust the deskband size at first call only.
    //
    _ptw->AutoAdjustDeskBandSize();
}

//+---------------------------------------------------------------------------
//
// AddUIObjs
//
//----------------------------------------------------------------------------

void CTipbarThread::AddUIObjs()
{

    _AddRef();

    int i;
    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *ptbItem = _rgItem.Get(i);
        if (ptbItem && ptbItem->IsVisibleInToolbar())
             ptbItem->AddMeToUI(_ptw);

    }

    AddAllSeparators();
    MyMoveWnd(0, 0);

    _Release();
}

//+---------------------------------------------------------------------------
//
// AddAllSeparators
//
//----------------------------------------------------------------------------

void CTipbarThread::AddAllSeparators()
{
    int i;
    for (i = 0; i < _rgSep.Count(); i++)
    {
        CUIFSeparator *pSep = _rgSep.Get(i);
        if (pSep)
            _ptw->AddUIObj(pSep);
    }
}

//+---------------------------------------------------------------------------
//
// RemoveUIObjs
//
//----------------------------------------------------------------------------

void CTipbarThread::RemoveUIObjs()
{
    int i;
    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *ptbItem = _rgItem.Get(i);
        if (ptbItem)
            ptbItem->RemoveMeToUI(_ptw);
    }
    RemoveAllSeparators();
}

//+---------------------------------------------------------------------------
//
// RemoveAllSeparators
//
//----------------------------------------------------------------------------

void CTipbarThread::RemoveAllSeparators()
{
    int i;
    for (i = 0; i < _rgSep.Count(); i++)
    {
        CUIFSeparator *pSep = _rgSep.Get(i);
        if (pSep)
        {
            if (_ptw)
                _ptw->RemoveUIObj(pSep);

            delete pSep;
        }
    }
    _rgSep.Clear();
}

//+---------------------------------------------------------------------------
//
// GetItem
//
//----------------------------------------------------------------------------

CTipbarItem *CTipbarThread::GetItem(REFGUID guid)
{
    int i;
    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *ptbItem = _rgItem.Get(i);
        if (ptbItem)
        {
            GUID *pguid= ptbItem->GetGUID();
            if (IsEqualGUID(*pguid, guid))
                return ptbItem;
        }
    }
    return NULL;
}

//+---------------------------------------------------------------------------
//
// IsDirtyItem
//
//----------------------------------------------------------------------------

DWORD CTipbarThread::IsDirtyItem()
{
    DWORD dwFlags = 0;

    int i;
    for (i = 0; i < _rgItem.Count(); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (pItem)
            dwFlags |= pItem->GetDirtyUpdateFlags();
    }

    return dwFlags;
}

//+---------------------------------------------------------------------------
//
// CallOnUpdateHandler
//
//----------------------------------------------------------------------------

BOOL CTipbarThread::CallOnUpdateHandler()
{
    int i;
    int nCnt;
    DWORD dwFlags;
    CTipbarItemGuidArray rgGuid;
    DWORD *pdw = NULL;
    BOOL bRet = TRUE;

    //
    // Windows Bug #367869.
    //
    // AddRef now because there is a change for this thread to be removed.
    //
    _AddRef();

#ifdef DEBUG
    _fInCallOnUpdateHandler = TRUE;
#endif

    //
    // we want to use g_pTipbarWnd instead of _ptw. 
    // _ptw could be disconnected during this function. If it is disconnected,
    // we can not decrement the pending counter.
    //
    if (g_pTipbarWnd)
        g_pTipbarWnd->StartPendingUpdateUI();

    //
    // if there is no items, do nothing
    //
    nCnt = _rgItem.Count();
    if (!nCnt)
    {
        goto Exit;
    }

    if (!_plbim)
    {
        if (IsConsole())
        {
            for (i = 0; i < _rgItem.Count(); i++)
            {
                DWORD dwStatus;

                CTipbarItem *pItem = _rgItem.Get(i);

                if (pItem && pItem->GetNotifyUI())
                {
                    dwFlags = pItem->GetDirtyUpdateFlags();
                    if (dwFlags & TF_LBI_STATUS)
                        pItem->GetNotifyUI()->GetStatus(&dwStatus);
                    else
                        dwStatus = 0;

                    pItem->ClearDirtyUpdateFlags();
                    pItem->OnUpdateHandler(dwFlags, dwStatus);
                }
            }
        }
        goto Exit;
    }

    rgGuid.Init(&_rgItem);

    //
    // if there is no dirty flag, do nothig.
    //
    dwFlags = IsDirtyItem();
    if (!dwFlags)
        goto Exit;

    pdw = new DWORD[nCnt];
    if (!pdw)
        goto Exit;

    //
    // Clear the each item OnUpdate() request
    //
    for (i = 0; (i < nCnt) && (i < _rgItem.Count()); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (!pItem)
            continue;

        pItem->ClearOnUpdateRequest();
    }

    //
    // get items flag at once.
    //
    if (FAILED(_plbim->GetItemsStatus(nCnt, rgGuid.GetPtr(), pdw)))
    {
        TraceMsg(TF_FUNC, "GetItemStatus failed");
        bRet = FALSE;
        goto Exit;
    }

    for (i = 0; (i < nCnt) && (i < _rgItem.Count()); i++)
    {
        CTipbarItem *pItem = _rgItem.Get(i);
        if (!pItem)
            continue;

        //
        // Skip the current item update request if the item has another OnUpdate() Request
        //
        if (pItem->IsNewOnUpdateRequest())
            continue;

        dwFlags = pItem->GetDirtyUpdateFlags();
        if (dwFlags)
        {
            pItem->ClearDirtyUpdateFlags();
            pItem->OnUpdateHandler(dwFlags, pdw[i]);
        }
    }

Exit:
    if (pdw)
        delete[] pdw;

    //
    // we want to use g_pTipbarWnd instead of _ptw. 
    // _ptw could be disconnected during this function. If it is disconnected,
    // we can not decrement the pending counter.
    //
    if (g_pTipbarWnd)
        g_pTipbarWnd->EndPendingUpdateUI();

#ifdef DEBUG
    _fInCallOnUpdateHandler = FALSE;
#endif

    _Release();

    return bRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarItem
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarItem::CTipbarItem(CTipbarThread *ptt, 
                         ITfLangBarItem *plbi, 
                         TF_LANGBARITEMINFO *plbiInfo, 
                         DWORD dwStatus)
{
    _ptt = ptt;
    _lbiInfo = *plbiInfo;
    _plbi = plbi;
    _plbi->AddRef();
    _fToolTipInit = FALSE;
    _fAddedToUI = FALSE;
    _fDisconnected = FALSE;

    _dwDirtyUpdateFlags = (TF_LBI_STATUS | TF_LBI_BTNALL | TF_LBI_BMPALL | TF_LBI_BALLOON);

    _dwStatus = dwStatus;
}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarItem::~CTipbarItem()
{
    if (_ptt && _ptt->_ptw && _ptt->_ptw->GetAccessible())
    {
        _ptt->_ptw->GetAccessible()->RemoveAccItem(this);
    }

    SafeRelease(_plbi);
}


//+---------------------------------------------------------------------------
//
// OnSetCursor
//
//----------------------------------------------------------------------------

BOOL CTipbarItem::OnSetCursor(UINT uMsg, POINT pt)
{
    return FALSE;
}

//+---------------------------------------------------------------------------
//
// GetToolTip
//
//----------------------------------------------------------------------------

LPCWSTR CTipbarItem::GetToolTip()
{
    AddRef();

    if (!_fToolTipInit)
    {
        BSTR bstrTooltip;
        HRESULT hr;

        _fToolTipInit = TRUE;
        if (FAILED(hr =_plbi->GetTooltipString(&bstrTooltip)))
            return NULL;

        if (bstrTooltip)
        {
            SetToolTip(bstrTooltip);
            SysFreeString(bstrTooltip);
        }
    }

    LPCWSTR psz;
    psz = GetToolTipFromUIOBJ();

    Release();
    return psz;
}

//+---------------------------------------------------------------------------
//
// AddedToUI
//
//----------------------------------------------------------------------------

void CTipbarItem::_AddedToUI()
{
    if (!IsConnected())
        return;

    AddRef();

    _fAddedToUI = TRUE;
    if (_dwDirtyUpdateFlags)
    {
        DWORD dwStatus;
 
        if (_dwDirtyUpdateFlags & TF_LBI_STATUS)
            _plbi->GetStatus(&dwStatus);
        else
            dwStatus = 0;
 
        OnUpdateHandler(_dwDirtyUpdateFlags, dwStatus);
        _dwDirtyUpdateFlags = 0;
    }
 
    if (_ptt && _ptt->_ptw && _ptt->_ptw->GetAccessible())
    {
        _ptt->_ptw->GetAccessible()->AddAccItem(this);
    }

    Release();
}

//+---------------------------------------------------------------------------
//
// RemovedToUI
//
//----------------------------------------------------------------------------

void CTipbarItem::_RemovedToUI()
{
    _fAddedToUI = FALSE;
 
    if (_ptt && _ptt->_ptw && _ptt->_ptw->GetAccessible())
    {
        _ptt->_ptw->GetAccessible()->RemoveAccItem(this);
    }
}

//+---------------------------------------------------------------------------
//
// Update
//
//----------------------------------------------------------------------------

HRESULT CTipbarItem::OnUpdate(DWORD dwFlags)
{
    DWORD dwPrevDirtyUpdateFlags = _dwDirtyUpdateFlags;
    if (!IsConnected())
        return S_OK;

    _dwDirtyUpdateFlags |= dwFlags;
    _fNewOnUpdateRequest = TRUE;

    //
    // if this item is not aded to UI or TrayIcon,
    // we don't have to update anything yet.
    // OnUpdate() will be called again 
    // when this item is added to UI or TrayIcon.
    //
    if ((!(dwFlags & TF_LBI_STATUS)) && !_fAddedToUI && !_fAddedToIconTray)
    {
        return S_OK;
    }

    if (_ptt && _ptt->_ptw && _ptt->_ptw->GetWnd())
    {
        _ptt->_ptw->KillTimer(TIPWND_TIMER_ONUPDATECALLED);
        _ptt->_ptw->SetTimer(TIPWND_TIMER_ONUPDATECALLED, g_uTimerElapseONUPDATECALLED);
    }

    return S_OK;
}

//+---------------------------------------------------------------------------
//
// OnUpdateHandler
//
//----------------------------------------------------------------------------

HRESULT CTipbarItem::OnUpdateHandler(DWORD dwFlags, DWORD dwStatus)
{
    if (!IsConnected())
        return S_OK;

    BOOL fPrevHidden = TRUE;

    if (IsHiddenStatusControl())
        fPrevHidden = IsInHiddenStatus();

    if (dwFlags & TF_LBI_TOOLTIP)
    {
        _fToolTipInit = FALSE;
    }

    if (dwFlags & TF_LBI_STATUS)
    {
        BOOL fEnabled = (_dwStatus & TF_LBI_STATUS_DISABLED) ? FALSE : TRUE;

        if (!IsHiddenStatusControl())
        {
            // Assert(dwStatus & TF_LBI_STATUS_HIDDEN);
            dwStatus &= ~TF_LBI_STATUS_HIDDEN;
        }

        //
        // MSAA support
        //
        if (_dwStatus != dwStatus)
        {
            if (_ptt && _ptt->_ptw && _ptt->_ptw->GetAccessible())
                _ptt->_ptw->GetAccessible()->NotifyWinEvent( EVENT_OBJECT_STATECHANGE , this);
        }

        _dwStatus = dwStatus;

        if (fEnabled && (_dwStatus & TF_LBI_STATUS_DISABLED))
             Enable(FALSE);
        else if (!fEnabled && !(_dwStatus & TF_LBI_STATUS_DISABLED))
             Enable(TRUE);
    }

    if (IsHiddenStatusControl())
    {
        if (fPrevHidden != IsInHiddenStatus())
            AddRemoveMeToUI(!IsInHiddenStatus() && !IsShownInTrayOnly());
    }

    return S_OK;
}


//+---------------------------------------------------------------------------
//
// AddRemoveMeToUI
//
//----------------------------------------------------------------------------

void CTipbarItem::AddRemoveMeToUI(BOOL fAdd)
{
    if (!IsConnected())
        return;

    _ptt->LocateItems();
    _ptt->AddAllSeparators();
    if (fAdd)
    {
        Assert(IsVisibleInToolbar());
        AddMeToUI(_ptt->_ptw);
    }
    else
    {
        Assert(!IsVisibleInToolbar());
        RemoveMeToUI(_ptt->_ptw);
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarButtonItem
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// IUnknown
//
//----------------------------------------------------------------------------

STDAPI CTipbarButtonItem::QueryInterface(REFIID riid, void **ppvObj)
{
    *ppvObj = NULL;

    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_ITfLangBarItemSink))
    {
        *ppvObj = SAFECAST(this, ITfLangBarItemSink *);
    }
    else if (IsEqualIID(riid, IID_PRIV_BUTTONITEM))
    {
        *ppvObj = this;
    }

    if (*ppvObj)
    {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

STDAPI_(ULONG) CTipbarButtonItem::AddRef()
{
    return ++_cRef;
}

STDAPI_(ULONG) CTipbarButtonItem::Release()
{
    _cRef--;
    Assert(_cRef >= 0);

    if (_cRef == 0)
    {
        delete this;
        return 0;
    }

    return _cRef;
}

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarButtonItem::CTipbarButtonItem(CTipbarThread *ptt, 
                                     ITfLangBarItem *plbi, 
                                     ITfLangBarItemButton *plbiButton, 
                                     DWORD dwId, 
                                     RECT *prc, 
                                     DWORD dwStyle, 
                                     DWORD dwNuiBtnStyle, 
                                     DWORD dwSBtnShowType, 
                                     TF_LANGBARITEMINFO *plbiInfo,
                                     DWORD dwStatus)
                    : CUIFToolbarButton(ptt->_ptw, 
                                     dwId, 
                                     prc, 
                                     dwStyle, 
                                     dwNuiBtnStyle, 
                                     dwSBtnShowType) , 
                    CTipbarItem(ptt, plbi, plbiInfo, dwStatus)
{
    Dbg_MemSetThisName(TEXT("CTipbarButtonItem"));

    _plbiButton = plbiButton;
    _plbiButton->AddRef();


    if (_dwStatus & TF_LBI_STATUS_DISABLED)
        Enable(FALSE);

    _cRef = 1;
}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarButtonItem::~CTipbarButtonItem()
{
    UninitUIResource();
    SafeRelease(_plbiButton);
}


//+---------------------------------------------------------------------------
//
// OnUpdateHandler
//
//----------------------------------------------------------------------------

HRESULT CTipbarButtonItem::OnUpdateHandler(DWORD dwFlags, DWORD dwStatus)
{
    BOOL fPrevHidden = TRUE;

    if (!IsConnected())
        return S_OK;

    HRESULT hr = S_OK;
    BOOL fCallPaint = FALSE;
    BOOL fUpdateToggleStatus = FALSE;

    //
    // add ref count to be safe for releasing during marshaling.
    //
    AddRef();

    if (dwFlags & TF_LBI_ICON)
    {
        HICON hIconOld;
        HICON hIcon = GetIcon();

        if (!_ptt || !_ptt->_ptw)
            goto Exit;

        if (hIconOld = GetIconFromUIObj())
            DestroyIcon(hIconOld);


        if (hIcon)
        {
            HICON hSmIcon = NULL;
            int cxSmIcon;
            int cySmIcon;

#ifdef SCALE_ICON
            cxSmIcon = GetSystemMetrics( SM_CXSMICON );
            cySmIcon = GetSystemMetrics( SM_CYSMICON );
#else
            cxSmIcon = 16;
            cySmIcon = 16;
#endif

            if (IsTextColorIcon())
            {
                COLORREF rgbText = GetSysColor(COLOR_BTNTEXT);
                if (_ptt && 
                    _ptt->_ptw && 
                    SUCCEEDED(_pBtn->EnsureThemeData(_ptt->_ptw->GetWnd())))
                {
                    COLORREF col;
                    if (SUCCEEDED(_pBtn->GetThemeColor(TS_NORMAL, TMT_TEXTCOLOR, &col)))
                        rgbText = col;
                }

                CMaskBitmap maskbmp;
                maskbmp.Init(hIcon, 16,16, rgbText);

                ICONINFO ii;
                ii.fIcon = TRUE;
                ii.xHotspot = 0;
                ii.yHotspot = 0;
                ii.hbmMask = maskbmp.GetBmpMask();
                ii.hbmColor = maskbmp.GetBmp();
                hSmIcon = CreateIconIndirect(&ii);

            }
            else
            {
#ifdef SCALE_ICON
                hSmIcon = StretchIcon(hIcon, cxSmIcon, cySmIcon);
#else
                hSmIcon = (HICON)CopyImage(hIcon, 
                                           IMAGE_ICON, 
                                           cxSmIcon, cySmIcon,
                                           LR_COPYFROMRESOURCE);
#endif
            }

            SetIcon(hSmIcon ? hSmIcon : hIcon);

            if (!IsHiddenStatusControl() && IsVisibleInToolbar())
                StartDemotingTimer(FALSE);

            if (hSmIcon)
                DestroyIcon(hIcon);
        }
        else
            SetIcon((HICON)NULL);

        fCallPaint = TRUE;
    }

    if ((dwFlags & TF_LBI_TEXT) && 
        _ptt && 
        _ptt->_ptw && 
        _ptt->_ptw->IsShowText())
    {
        BSTR bstr;
        hr =  _plbiButton->GetText(&bstr);

        if (FAILED(hr))
            goto Exit;
        
        if (_ptt && bstr && (!GetText() || wcscmp(GetText(), bstr)))
        {
            SIZE size;
            _ptt->GetTextSize(bstr, &size);

            SetText(SysStringLen(bstr) ? bstr : NULL);


            if (_sizeText.cx != size.cx)
            {
                _dwWidth += (size.cx - _sizeText.cx);
                _ptt->LocateItems();
            }

            _sizeText = size;
            fCallPaint = TRUE;
        }

        if (bstr)
            SysFreeString(bstr);
    }

    if (IsHiddenStatusControl())
        fPrevHidden = IsInHiddenStatus();

    CTipbarItem::OnUpdateHandler(dwFlags, dwStatus);

    if (_pBtn->GetToggleState() != IsToggled())
    {
       _pBtn->SetToggleState(IsToggled());
       fUpdateToggleStatus = TRUE;
    }

    if ((dwFlags & (TF_LBI_ICON | TF_LBI_TOOLTIP)) || 
        fUpdateToggleStatus ||
        (fPrevHidden != IsInHiddenStatus()))
    {
        // we need to call Thread's MoveToTray too keep the order of Icons.
        // _ptt->_ptw->MoveToTray();
        if (_ptt && _ptt->_ptw && _ptt->_ptw->IsShowTrayIcon())
        {
            _ptt->_ptw->KillTimer(TIPWND_TIMER_MOVETOTRAY);
            _ptt->_ptw->SetTimer(TIPWND_TIMER_MOVETOTRAY, g_uTimerElapseMOVETOTRAY);
        }
    }

    if (fCallPaint)
        CallOnPaint();

Exit:
    Release();
    return hr;
}

//+---------------------------------------------------------------------------
//
// OnRightClick
//
//----------------------------------------------------------------------------

void CTipbarButtonItem::OnRightClick()
{
    if (_plbiButton)
    {
        HRESULT hr;
        POINT pt;
        RECT rc;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiButton);

        if (pac)
        {
            hr = pac->OnClick(TF_LBI_CLK_RIGHT, pt, &rc);
            pac->_Release();
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }


        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);

            return;
        }
    }
}

//+---------------------------------------------------------------------------
//
// OnLeftClick
//
//----------------------------------------------------------------------------

void CTipbarButtonItem::OnLeftClick()
{
    if (_plbiButton)
    {
        HRESULT hr;
        POINT pt;
        RECT rc;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiButton);

        if (pac)
        {
            hr = pac->OnClick(TF_LBI_CLK_LEFT, pt, &rc);
            pac->_Release();
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }


        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
               _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            return;
        }

        if (!IsHiddenStatusControl() && IsVisibleInToolbar())
            StartDemotingTimer(TRUE);
    }
}

//+---------------------------------------------------------------------------
//
// OnShowMenu
//
//----------------------------------------------------------------------------

void CTipbarButtonItem::OnShowMenu()
{
    if (!_ptt)
        return;

    if (!_ptt->_ptw)
        return;

    if (_plbiButton)
    {
        POINT pt;
        RECT rc;
        GetRect(&rc);
        pt.x = rc.left;
        pt.y = rc.bottom;
        MyClientToScreen(&pt, &rc);

        DoModalMenu(&pt, &rc);
    }
}

//+---------------------------------------------------------------------------
//
// DoModalMenu
//
//----------------------------------------------------------------------------

void CTipbarButtonItem::DoModalMenu(POINT *ppt, RECT *prc)
{
    HRESULT hr;
    UINT uId;
    DWORD dwThreadId;
    CTipbarWnd *ptw;

    if (!_ptt)
        return;

    if (!_ptt->_ptw)
        return;

    CUTBLBarMenu *pMenu = new CUTBLBarMenu(g_hInst);
    if (!pMenu)
        return;

    AddRef();

    hr = _plbiButton->InitMenu(pMenu);
    if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
    {
        if (_ptt && _ptt->_ptw)
            _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
        goto Exit;
    }
    if (FAILED(hr))
        goto Exit;

    ptw = _ptt->_ptw;
    dwThreadId = _ptt->_dwThreadId;
    Assert(!_ptt->_ptw->_pttModal);
    ptw->_pttModal = _ptt;
    ptw->StartModalInput(ptw, dwThreadId);

    Assert(!ptw->_pModalMenu);
    ptw->_pModalMenu = pMenu;
    uId = pMenu->ShowPopup(ptw, *ppt, prc);

    ptw->_pModalMenu = NULL;

    ptw->StopModalInput(dwThreadId);
    ptw->_pttModal = NULL;

    if (IsConnected() && (uId != CUI_MENU_UNSELECTED))
    {
        CAsyncCall *pac = new CAsyncCall(_plbiButton);
        if (pac)
        {
            hr = pac->OnMenuSelect(uId);
            pac->_Release();
        }

        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            goto Exit;
        }

        if (FAILED(hr))
            goto Exit;
    }

Exit:
    pMenu->Release();
    Release();
}


//+---------------------------------------------------------------------------
//
// MoveToTray
//
//----------------------------------------------------------------------------

void CTipbarButtonItem::MoveToTray()
{
    if (!g_pTrayIconWnd)
        return;

    if (IsVisibleInToolbar() && (IsShownInTray() || IsShownInTrayOnly()))
    {
        HICON hIcon = GetIcon();
        if (hIcon)
        {
            SIZE size;
            if (IsToggled() && CUIGetIconSize(hIcon, &size))
            {
                COLORREF cr;
                RECT rc;
                CBitmapDC hdcSrc(TRUE);
                CBitmapDC hdcMask(TRUE);

#if 0
                CUIFScheme *pscheme = _ptt->_ptw->GetUIFScheme();
                if (!pscheme)
                   cr = GetSysColor(COLOR_HIGHLIGHT);
                else
                   cr = pscheme->GetColor(UIFCOLOR_MOUSEDOWNBKGND);
#else
                   cr = GetSysColor(COLOR_HIGHLIGHT);
#endif

                CSolidBrush hbrBk(cr);
                hdcSrc.SetDIB(size.cx, size.cy);
                hdcMask.SetBitmap(size.cx, size.cy, 1, 1);
                rc.left = 0;
                rc.top = 0;
                rc.right  = size.cx;
                rc.bottom = size.cy;
                FillRect(hdcSrc, &rc, (HBRUSH)hbrBk);
                DrawIconEx(hdcSrc, 0, 0, hIcon, size.cx, size.cy, 0, NULL, DI_NORMAL);
                FillRect(hdcMask, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
                ICONINFO ii;
                ii.fIcon = TRUE;
                ii.xHotspot = 0;
                ii.yHotspot = 0;
                ii.hbmMask = hdcMask.GetBitmap();
                ii.hbmColor = hdcSrc.GetBitmap();
                DestroyIcon(hIcon);
                hIcon = CreateIconIndirect(&ii);
            }
            
            if (hIcon)
            {
                g_pTrayIconWnd->SetIcon(*GetGUID(), IsMenuBtn(), hIcon, GetToolTip());
                DestroyIcon(hIcon);
            }
        }
         
    }
    else
    {
        g_pTrayIconWnd->SetIcon(*GetGUID(), IsMenuBtn(), NULL, NULL);
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarBitmapButtonItem
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// IUnknown
//
//----------------------------------------------------------------------------

STDAPI CTipbarBitmapButtonItem::QueryInterface(REFIID riid, void **ppvObj)
{
    *ppvObj = NULL;

    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_ITfLangBarItemSink))
    {
        *ppvObj = SAFECAST(this, ITfLangBarItemSink *);
    }
    else if (IsEqualIID(riid, IID_PRIV_BITMAPBUTTONITEM))
    {
        *ppvObj = this;
    }

    if (*ppvObj)
    {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

STDAPI_(ULONG) CTipbarBitmapButtonItem::AddRef()
{
    return ++_cRef;
}

STDAPI_(ULONG) CTipbarBitmapButtonItem::Release()
{
    _cRef--;
    Assert(_cRef >= 0);

    if (_cRef == 0)
    {
        delete this;
        return 0;
    }

    return _cRef;
}

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarBitmapButtonItem::CTipbarBitmapButtonItem(CTipbarThread *ptt, 
                                     ITfLangBarItem *plbi, 
                                     ITfLangBarItemBitmapButton *plbiBitmapButton, 
                                     DWORD dwId, 
                                     RECT *prc, 
                                     DWORD dwStyle, 
                                     DWORD dwNuiBtnStyle, 
                                     DWORD dwSBtnShowType, 
                                     TF_LANGBARITEMINFO *plbiInfo,
                                     DWORD dwStatus)
                    : CUIFToolbarButton(ptt->_ptw, 
                                     dwId, 
                                     prc, 
                                     dwStyle, 
                                     dwNuiBtnStyle, 
                                     dwSBtnShowType) , 
                    CTipbarItem(ptt, plbi, plbiInfo, dwStatus)
{
    Dbg_MemSetThisName(TEXT("CTipbarBitmapButtonItem"));

    _plbiBitmapButton = plbiBitmapButton;
    _plbiBitmapButton->AddRef();

    if (_dwStatus & TF_LBI_STATUS_DISABLED)
        Enable(FALSE);

    _cRef = 1;

}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarBitmapButtonItem::~CTipbarBitmapButtonItem()
{
    HBITMAP hbmpOld;
    HBITMAP hbmpMaskOld;

    hbmpOld = GetBitmap();
    hbmpMaskOld = GetBitmapMask();
    if (hbmpOld)
        DeleteObject(hbmpOld);
    if (hbmpMaskOld)
        DeleteObject(hbmpMaskOld);
    SetBitmap((HBITMAP)NULL);
    SetBitmapMask((HBITMAP)NULL);

    SafeRelease(_plbiBitmapButton);
}

//+---------------------------------------------------------------------------
//
// Update
//
//----------------------------------------------------------------------------

HRESULT CTipbarBitmapButtonItem::OnUpdateHandler(DWORD dwFlags, DWORD dwStatus)
{
    if (!IsConnected())
        return S_OK;

    HRESULT hr = S_OK;
    BOOL fCallPaint = FALSE;

    //
    // add ref count to be safe for releasing during marshaling.
    //
    AddRef();

    if (dwFlags & TF_LBI_BITMAP)
    {
        if (!_GetBitmapFromNUI())
        {
            hr = E_FAIL;
            goto Exit;
        }
        
        if (!IsHiddenStatusControl() && IsVisibleInToolbar())
            StartDemotingTimer(FALSE);

        fCallPaint = TRUE;
    }

    if ((dwFlags & TF_LBI_TEXT) && 
        _ptt &&
        _ptt->_ptw &&
        _ptt->_ptw->IsShowText())
    {
        BSTR bstr;
        hr = _plbiBitmapButton->GetText(&bstr);

        if (FAILED(hr))
            goto Exit;
        
        if (bstr && (!GetText() || wcscmp(GetText(), bstr)))
        {
            SIZE size;
            _ptt->GetTextSize(bstr, &size);

            SetText(SysStringLen(bstr) ? bstr : NULL);


            if (_sizeText.cx != size.cx)
            {
                _dwWidth += (size.cx - _sizeText.cx);
                _ptt->LocateItems();
            }

            _sizeText = size;
            fCallPaint = TRUE;
        }

        if (bstr)
            SysFreeString(bstr);
    }

    CTipbarItem::OnUpdateHandler(dwFlags, dwStatus);

    if (_pBtn->GetToggleState() != IsToggled())
    {
       _pBtn->SetToggleState(IsToggled());
    }

    if (fCallPaint)
        CallOnPaint();

Exit:
    Release();
    return hr;
}


//+---------------------------------------------------------------------------
//
// _GetBitmapFromNUI
//
//----------------------------------------------------------------------------

BOOL CTipbarBitmapButtonItem::_GetBitmapFromNUI()
{
    BOOL bRet = FALSE;
    HBITMAP hbmp;
    HBITMAP hbmpMask;
    HBITMAP hbmpOld;
    HBITMAP hbmpMaskOld;
    int x, y;

    hbmpOld = GetBitmap();
    if (hbmpOld)
        DeleteObject(hbmpOld);
    hbmpMaskOld = GetBitmapMask();
    if (hbmpMaskOld)
        DeleteObject(hbmpMaskOld);
    SetBitmap((HBITMAP)NULL);
    SetBitmapMask((HBITMAP)NULL);

    x = GetRectRef().right - GetRectRef().left;
    y = GetRectRef().bottom - GetRectRef().top;
    if (_ptt->_ptw->IsShowText())
        y -= 12;

    HRESULT hr = _plbiBitmapButton->DrawBitmap(x, y, 0, &hbmp, &hbmpMask);

    if (SUCCEEDED(hr))
    {
        SetBitmap(hbmp);
        SetBitmapMask(hbmpMask);
        bRet = TRUE;
    }

    return bRet;
}



//+---------------------------------------------------------------------------
//
// OnRightClick
//
//----------------------------------------------------------------------------

void CTipbarBitmapButtonItem::OnRightClick()
{
    if (_plbiBitmapButton)
    {
        HRESULT hr;
        POINT pt;
        RECT rc;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiBitmapButton);

        if (pac)
        {
            hr = pac->OnClick(TF_LBI_CLK_RIGHT, pt, &rc);
            pac->_Release();
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }

        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            return;
        }
    }
}

//+---------------------------------------------------------------------------
//
// OnLeftClick
//
//----------------------------------------------------------------------------

void CTipbarBitmapButtonItem::OnLeftClick()
{
    if (_plbiBitmapButton)
    {
        HRESULT hr;
        POINT pt;
        RECT rc;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiBitmapButton);

        if (pac)
        {
            hr = pac->OnClick(TF_LBI_CLK_LEFT, pt, &rc);
            pac->_Release();
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }

        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            return;
        }

        if (!IsHiddenStatusControl() && IsVisibleInToolbar())
            StartDemotingTimer(TRUE);
    }
}

//+---------------------------------------------------------------------------
//
// OnShowMenu
//
//----------------------------------------------------------------------------

void CTipbarBitmapButtonItem::OnShowMenu()
{
    if (!_ptt)
        return;

    if (!_ptt->_ptw)
        return;

    if (_plbiBitmapButton)
    {
        POINT pt;
        RECT rc;
        GetRect(&rc);
        pt.x = rc.left;
        pt.y = rc.bottom;
        MyClientToScreen(&pt, &rc);
        HRESULT hr;
        UINT uId;
        DWORD dwThreadId;
        CTipbarWnd *ptw;

        CUTBLBarMenu *pMenu = new CUTBLBarMenu(g_hInst);
        if (!pMenu)
            return;

        hr = _plbiBitmapButton->InitMenu(pMenu);
        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            goto Exit;
        }
        if (FAILED(hr))
            goto Exit;

        ptw = _ptt->_ptw;
        dwThreadId = _ptt->_dwThreadId;

        Assert(!ptw->_pttModal);
        ptw->_pttModal = _ptt;
        ptw->StartModalInput(ptw, dwThreadId);

        Assert(!ptw->_pModalMenu);
        ptw->_pModalMenu = pMenu;
        uId = pMenu->ShowPopup(ptw, pt, &rc);
        ptw->_pModalMenu = NULL;

        ptw->StopModalInput(dwThreadId);
        ptw->_pttModal = NULL;

        if (IsConnected() && (uId != CUI_MENU_UNSELECTED))
        {
            Assert(_ptt);
            CAsyncCall *pac = new CAsyncCall(_plbiBitmapButton);
            if (pac)
            {
                hr = pac->OnMenuSelect(uId);
                pac->_Release();
            }
            else
            {
                hr = E_OUTOFMEMORY;
            }

            if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
            {
                ptw->OnThreadTerminate(dwThreadId);
                goto Exit;
            }
            if (FAILED(hr))
                goto Exit;
        }

Exit:
        pMenu->Release();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarBitmapItem
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// IUnknown
//
//----------------------------------------------------------------------------

STDAPI CTipbarBitmapItem::QueryInterface(REFIID riid, void **ppvObj)
{
    *ppvObj = NULL;

    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_ITfLangBarItemSink))
    {
        *ppvObj = SAFECAST(this, ITfLangBarItemSink *);
    }
    else if (IsEqualIID(riid, IID_PRIV_BITMAPITEM))
    {
        *ppvObj = this;
    }

    if (*ppvObj)
    {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

STDAPI_(ULONG) CTipbarBitmapItem::AddRef()
{
    return ++_cRef;
}

STDAPI_(ULONG) CTipbarBitmapItem::Release()
{
    _cRef--;
    Assert(_cRef >= 0);

    if (_cRef == 0)
    {
        delete this;
        return 0;
    }

    return _cRef;
}

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarBitmapItem::CTipbarBitmapItem(CTipbarThread *ptt, 
                                     ITfLangBarItem *plbi,
                                     ITfLangBarItemBitmap *plbiBitmap, 
                                     DWORD dwId, 
                                     RECT *prc, 
                                     DWORD dwStyle, 
                                     TF_LANGBARITEMINFO *plbiInfo,
                                     DWORD dwStatus)
                   : CUIFObject(ptt->_ptw, 
                                dwId, 
                                prc, 
                                dwStyle) , 
                     CTipbarItem(ptt, plbi, plbiInfo, dwStatus)
{
    Dbg_MemSetThisName(TEXT("CTipbarBitmapItem"));

    _plbiBitmap = plbiBitmap;
    _plbiBitmap->AddRef();

    if (_dwStatus & TF_LBI_STATUS_DISABLED)
        Enable(FALSE);

    _cRef = 1;

}

//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------

CTipbarBitmapItem::~CTipbarBitmapItem()
{
    if (_hbmp)
        DeleteObject(_hbmp);
    SafeRelease(_plbiBitmap);
}

//+---------------------------------------------------------------------------
//
// Update
//
//----------------------------------------------------------------------------

HRESULT CTipbarBitmapItem::OnUpdateHandler(DWORD dwFlags, DWORD dwStatus)
{
    if (!IsConnected())
        return S_OK;

    HRESULT hr = S_OK;
    BOOL fCallPaint = FALSE;

    //
    // add ref count to be safe for releasing during marshaling.
    //
    AddRef();


    if (dwFlags & TF_LBI_BITMAP)
    {
        if (!_GetBitmapFromNUI())
        {
            hr = E_FAIL;
            goto Exit;
        }
        
        fCallPaint = TRUE;
    }

    CTipbarItem::OnUpdateHandler(dwFlags, dwStatus);

    if (fCallPaint)
        CallOnPaint();

Exit:
    Release();
    return hr;
}

//+---------------------------------------------------------------------------
//
// _GetBitmapFromNUI
//
//----------------------------------------------------------------------------

BOOL CTipbarBitmapItem::_GetBitmapFromNUI()
{
    BOOL bRet = TRUE;
    HBITMAP hbmp = NULL;
    HBITMAP hbmpMask = NULL;
    int x = GetRectRef().right - GetRectRef().left;
    int y = GetRectRef().bottom - GetRectRef().top;

    HRESULT hr = _plbiBitmap->DrawBitmap(x, y, 0, &hbmp, &hbmpMask);

    if (FAILED(hr))
    {
        if (_hbmp)
           DeleteObject(_hbmp);
        _hbmp = NULL;
        bRet = FALSE;
    }

    if (!hbmpMask)
    {
        if (_hbmp)
           DeleteObject(_hbmp);
        _hbmp = hbmp;
    }
    else
    {
        CUIFScheme *pScheme = GetUIFScheme();

        if (_hbmp)
           DeleteObject(_hbmp);

        _hbmp = CreateMaskBmp(&GetRectRef(), hbmp, hbmpMask,
                              pScheme->GetBrush(UIFCOLOR_CTRLBKGND), 0, 0);
    }

    if (hbmp)
        DeleteObject(hbmp);
    if (hbmpMask)
        DeleteObject(hbmpMask);

    return bRet;
}

//+---------------------------------------------------------------------------
//
// OnPaint
//
//----------------------------------------------------------------------------

void CTipbarBitmapItem::OnPaint( HDC hdc )
{
    CBitmapDC hdcMem(TRUE);
    hdcMem.SetBitmap(_hbmp);

    BitBlt(hdc, 
           GetRectRef().left, 
           GetRectRef().top, 
           GetRectRef().right - GetRectRef().left,
           GetRectRef().bottom - GetRectRef().top, 
           hdcMem, 
           0, 
           0, 
           SRCCOPY);

}

//+---------------------------------------------------------------------------
//
// SetRect
//
//----------------------------------------------------------------------------

void CTipbarBitmapItem::SetRect( const RECT *prc ) 
{

    if (((GetRectRef().bottom - GetRectRef().top) != (prc->bottom - prc->top)) ||
        ((GetRectRef().right - GetRectRef().left) != (prc->right - prc->left)))
    {
        if (_hbmp)
            DeleteObject(_hbmp);
        _hbmp = NULL;
    }

    CUIFObject::SetRect(prc);
}

//+---------------------------------------------------------------------------
//
// OnRightClick
//
//----------------------------------------------------------------------------

void CTipbarBitmapItem::OnRightClick()
{
    if (_plbiBitmap)
    {
        POINT pt;
        RECT rc;
        HRESULT hr;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiBitmap);
        if (!pac)
            return;

        hr = pac->OnClick(TF_LBI_CLK_RIGHT, pt, &rc);
        pac->_Release();

        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            return;
        }
    }
}

//+---------------------------------------------------------------------------
//
// OnLeftClick
//
//----------------------------------------------------------------------------

void CTipbarBitmapItem::OnLeftClick()
{
    if (_plbiBitmap)
    {
        HRESULT hr;
        POINT pt;
        RECT rc;
        GetCursorPos(&pt);
        GetRect(&rc);
        MyClientToScreen(&rc);

        CAsyncCall *pac = new CAsyncCall(_plbiBitmap);

        if (pac)
        {
            hr = pac->OnClick(TF_LBI_CLK_LEFT, pt, &rc);
            pac->_Release();
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }


        if (RPC_S_SERVER_UNAVAILABLE == HRESULT_CODE(hr))
        {
            if (_ptt && _ptt->_ptw)
                _ptt->_ptw->OnThreadTerminate(_ptt->_dwThreadId);
            return;
        }

        if (!IsHiddenStatusControl() && IsVisibleInToolbar())
            StartDemotingTimer(TRUE);
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// CTipbarCtrlButtonHolder
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarCtrlButtonHolder::CTipbarCtrlButtonHolder()
{
}

//+---------------------------------------------------------------------------
//
// Init
//
//+---------------------------------------------------------------------------

void CTipbarCtrlButtonHolder::Init(CTipbarWnd *ptw)
{
    int i;
    RECT rc;
    ::SetRect(&rc, 0, 0, 0, 0);

    if (ptw->IsInDeskBand())
        _pcbCtrlBtn = g_cbCtrlBtnDeskBand;
    else
        _pcbCtrlBtn = g_cbCtrlBtn;

    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        Assert(!_rgpCtrlBtn[i]);

        _rgpCtrlBtn[i] = new CTipbarCtrlButton(ptw, 
                                               _pcbCtrlBtn[i].dwId, 
                                               &rc,
                                               _pcbCtrlBtn[i].dwStyle);
        _rgpCtrlBtn[i]->Initialize();

        ptw->AddUIObj(_rgpCtrlBtn[i]);

        if (_pcbCtrlBtn[i].dwFlags & CTRL_USEMARLETT)
            _rgpCtrlBtn[i]->SetFont(ptw->GetMarlett());
 
        if (_pcbCtrlBtn[i].dwFlags & CTRL_ICONFROMRES)
        {
            if (_pcbCtrlBtn[i].dwId == ID_CBTN_CAPSKEY)
            {
                _rgpCtrlBtn[i]->SetVKey(VK_CAPITAL);
            }
            else
            {
                _rgpCtrlBtn[i]->SetVKey(VK_KANA);
            }
            _rgpCtrlBtn[i]->SetToggleStateByVKey();
        }
        else
            _rgpCtrlBtn[i]->SetText(_pcbCtrlBtn[i].wsz);

    }
}

//+---------------------------------------------------------------------------
//
// EnableBtns
//
//+---------------------------------------------------------------------------

void CTipbarCtrlButtonHolder::EnableBtns()
{
    int i;
    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        if (_pcbCtrlBtn[i].dwFlags & CTRL_DISABLEONWINLOGON)
        {
            if (g_bWinLogon || (g_pTipbarWnd && g_pTipbarWnd->IsSFMinmized()))
                _rgpCtrlBtn[i]->Enable(FALSE);
            else
                _rgpCtrlBtn[i]->Enable(TRUE);
        }
    }
}

//+---------------------------------------------------------------------------
//
// UpdateBitmap
//
//+---------------------------------------------------------------------------

void CTipbarCtrlButtonHolder::UpdateBitmap(CTipbarWnd *ptw)
{
    int i;

    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        if (_pcbCtrlBtn[i].dwFlags & CTRL_ICONFROMRES)
        {
            HBITMAP hbmp;
            HBITMAP hbmpMask;
            COLORREF rgbText = GetSysColor(COLOR_BTNTEXT);
            if (SUCCEEDED(_rgpCtrlBtn[i]->EnsureThemeData(ptw->GetWnd())))
            {
                COLORREF col;
                if (SUCCEEDED(_rgpCtrlBtn[i]->GetThemeColor(TS_NORMAL, TMT_TEXTCOLOR, &col)))
                    rgbText = col;
            }

            if (_pcbCtrlBtn[i].dwId == ID_CBTN_CAPSKEY)
            {
                if (!ptw->IsVertical())
                    _maskbmpCap.Init(ID_BITMAP_CAPS , 
                                     KANACAPSBMP_WIDTH,  
                                     KANACAPSBMP_HEIGHT, 
                                     rgbText);
                else
                    _maskbmpCap.Init(ID_BITMAP_CAPSV,  
                                     KANACAPSBMP_HEIGHT, 
                                     KANACAPSBMP_WIDTH, 
                                     rgbText);

                hbmp = _maskbmpCap.GetBmp();
                hbmpMask = _maskbmpCap.GetBmpMask();
            }
            else
            {
                if (!ptw->IsVertical())
                    _maskbmpKana.Init(ID_BITMAP_KANA , 
                                      KANACAPSBMP_WIDTH,  
                                      KANACAPSBMP_HEIGHT, 
                                      rgbText);
                else
                    _maskbmpKana.Init(ID_BITMAP_KANAV,  
                                      KANACAPSBMP_HEIGHT, 
                                      KANACAPSBMP_WIDTH, 
                                      rgbText);

                hbmp = _maskbmpKana.GetBmp();
                hbmpMask = _maskbmpKana.GetBmpMask();
            }

            _rgpCtrlBtn[i]->SetBitmap(hbmp);
            _rgpCtrlBtn[i]->SetBitmapMask(hbmpMask);
        }
    }
}
 
//+---------------------------------------------------------------------------
//
// Locate
//
//+---------------------------------------------------------------------------

void CTipbarCtrlButtonHolder::Locate(CTipbarWnd *ptw, int x, int y, int nHeight, DWORD dwFlags, BOOL fVertical)
{
    int i;
    int nCtrlItemHeight = (nHeight - ptw->GetCtrlItemHeightMargin() * 2) / 2;
    c_nColumnStart[0] = 0;
    c_nColumnStart[1] = CX_COLUMN0  +
                        ptw->GetThemeMargins()->cxLeftWidth +
                        ptw->GetThemeMargins()->cxRightWidth;
    c_nColumnStart[2] = CX_COLUMN1  +
                        ptw->GetThemeMargins()->cxLeftWidth +
                        ptw->GetThemeMargins()->cxRightWidth;

    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        RECT rc;
        int nColumn = _pcbCtrlBtn[i].nColumn;
        int nRow = _pcbCtrlBtn[i].nRow;

        if (dwFlags & TCBH_NOCOLUMN)
        {
            rc.left = 0;
            rc.top = 0;
            rc.right = 0;
            rc.bottom = 0;
            _rgpCtrlBtn[i]->SetRect(&rc);
            continue;
        }
        
        if (dwFlags & TCBH_NOCOLUMN0)
        {
            if (!_pcbCtrlBtn[i].nColumn)
            {
                rc.left = 0;
                rc.top = 0;
                rc.right = 0;
                rc.bottom = 0;
                _rgpCtrlBtn[i]->SetRect(&rc);
                continue;
            }
 
            nColumn--;
        }
 
        if (!fVertical)
        {
            rc.left = x + c_nColumnStart[nColumn];
            rc.top = ptw->GetCtrlItemHeightMargin() + y + nRow * nCtrlItemHeight;
            rc.right = rc.left + c_nColumnStart[_pcbCtrlBtn[i].nColumn + 1];
            rc.bottom = rc.top + nCtrlItemHeight;
        }
        else
        {
            //
            // swap Row when this is the vertical langbar.
            //
            rc.left = ptw->GetCtrlItemHeightMargin() + x + (1 - nRow) * nCtrlItemHeight;
            rc.top = y + c_nColumnStart[nColumn];
            rc.right = rc.left + nCtrlItemHeight;
            rc.bottom = rc.top + c_nColumnStart[_pcbCtrlBtn[i].nColumn + 1];
        }
 
        _rgpCtrlBtn[i]->SetRect(&rc);

    }
}

//+---------------------------------------------------------------------------
//
// GetWidth
//
//+---------------------------------------------------------------------------

int CTipbarCtrlButtonHolder::GetWidth(DWORD dwFlags)
{
    if (dwFlags & TCBH_NOCOLUMN)
        return 0;

    int nWidth = 0;

    if (!(dwFlags & TCBH_NOCOLUMN0))
        nWidth += c_nColumnStart[1];

    nWidth += c_nColumnStart[2];
    return nWidth;
}

//+---------------------------------------------------------------------------
//
// UpdateCapsKanaState
//
//+---------------------------------------------------------------------------

void CTipbarCtrlButtonHolder::UpdateCapsKanaState(LPARAM lParam)
{
    int i;
    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        if (_rgpCtrlBtn[i]->GetVKey())
        {
            if (_rgpCtrlBtn[i]->GetVKey() == VK_CAPITAL)
                _rgpCtrlBtn[i]->SetToggleState((lParam & TF_LBUF_CAPS) ? TRUE: FALSE);
            else if (_rgpCtrlBtn[i]->GetVKey() == VK_KANA)
                _rgpCtrlBtn[i]->SetToggleState((lParam & TF_LBUF_KANA) ? TRUE: FALSE);
        }
    }
}

//+---------------------------------------------------------------------------
//
// GetCtrlBtn
//
//+---------------------------------------------------------------------------

CTipbarCtrlButton *CTipbarCtrlButtonHolder::GetCtrlBtn(DWORD dwId)
{
    int i;
    for (i = 0; i < NUM_CTRLBUTTONS; i++)
    {
        if (_rgpCtrlBtn[i]->GetID() == dwId)
            return _rgpCtrlBtn[i];
    }

    return NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
// CTipbarCtrlButton
//
//////////////////////////////////////////////////////////////////////////////

//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------

CTipbarCtrlButton::CTipbarCtrlButton(CTipbarWnd *ptw, 
                                     DWORD dwId, 
                                     const RECT *prc,
                                     DWORD dwStyle) 
                  : CUIFButton2(ptw, 
                                dwId, 
                                prc, 
                                dwStyle)
{
    _ptw = ptw;
    _fInMenu = FALSE;
    SetToolTip(CRStr(IDS_CONTROLBUTTONTOOLTIP + dwId));
}


//+---------------------------------------------------------------------------
//
// OnLButtonUp
//
//----------------------------------------------------------------------------

void CTipbarCtrlButton::OnLButtonUp(POINT pt)
{
    CUIFButton2::OnLButtonUp(pt);
    CUTBMinimizeLangBarDlg *pMinimizeDlg;

    switch (GetID())
    {
        case ID_CBTN_MINIMIZE:
            //
            // Use Deskband object instead of system tray icon on NT51
            //
            if (IsOnNT51())
            {
                if (!_ptw->IsSFDeskband())
                {
                    _ptw->GetLangBarMgr()->ShowFloating(TF_SFT_DESKBAND);

                    if (pMinimizeDlg = new CUTBMinimizeLangBarDlg)
                    {
                        pMinimizeDlg->DoModal(_ptw->GetWnd());
                        pMinimizeDlg->_Release();
                    }
                }
                break;
            }
            else
            {
                _ptw->GetLangBarMgr()->ShowFloating(TF_SFT_MINIMIZED);

                if (pMinimizeDlg = new CUTBMinimizeLangBarDlg)
                {
                    pMinimizeDlg->DoModal(_ptw->GetWnd());
                    pMinimizeDlg->_Release();
                }
                break;
            }

        case ID_CBTN_RESTORE:
            //
            // Use Deskband object instead of system tray icon on NT51
            //
            Assert(IsOnNT51());
            if (_ptw->IsSFDeskband())
            {
                _ptw->GetLangBarMgr()->ShowFloating(TF_SFT_SHOWNORMAL);
            }
            break;

        case ID_CBTN_EXTMENU:
            ShowExtendMenu(pt);
            break;

        case ID_CBTN_KANAKEY:
            keybd_event(VK_KANA, 0, 0, 0);
            keybd_event(VK_KANA, 0, KEYEVENTF_KEYUP, 0);
            break;

        case ID_CBTN_CAPSKEY:
            keybd_event(VK_CAPITAL, 0, 0, 0);
            keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
            break;
    }

}

//+---------------------------------------------------------------------------
//
// ShowExtendMenu
//
//----------------------------------------------------------------------------

void CTipbarCtrlButton::ShowExtendMenu(POINT pt)
{
    CUTBIntelliMenu *pMenu;
    RECT rc;
    GetRect(&rc);
    MyClientToScreen(&pt, &rc);
    DWORD dwThreadId;
    UINT uId = CUI_MENU_UNSELECTED;

    if (!_ptw)
        return;

    if (!_ptw->GetFocusThread())
        return;

    dwThreadId = _ptw->GetFocusThread()->_dwThreadId;

    pMenu = new CUTBIntelliMenu(_ptw);
    if (!pMenu)
        return;

    if (!pMenu->Init())
        goto Exit;

    _ptw->_pttModal = _ptw->GetFocusThread();

    _ptw->StartModalInput(_ptw, dwThreadId);

    _ptw->_pModalMenu = pMenu;

    uId = pMenu->ShowPopup(_ptw, pt, &rc);

    _ptw->_pModalMenu = NULL;

    _ptw->StopModalInput(dwThreadId);
    _ptw->_pttModal = NULL;

    if (uId != CUI_MENU_UNSELECTED)
    {
        pMenu->SelectMenuItem(uId);
    }

Exit:
    delete pMenu;
}