https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f8cb6458e482a797e70ca…
commit f8cb6458e482a797e70cae777b8510d9f8e6926b
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Feb 11 17:21:14 2024 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Feb 11 17:21:14 2024 +0900
[MSUTB][SDK] Add CTipbarWnd Part 4 (#6478)
Supporting the Language bar...
JIRA issue: CORE-19363
- Add implementation to CTipbarWnd.
- Implement GetLibTls function.
---
dll/win32/msutb/msutb.cpp | 770 ++++++++++++++++++++++++++++++------
sdk/include/reactos/cicero/cicutb.h | 8 +-
2 files changed, 663 insertions(+), 115 deletions(-)
diff --git a/dll/win32/msutb/msutb.cpp b/dll/win32/msutb/msutb.cpp
index 31b05578656..c5e3c337614 100644
--- a/dll/win32/msutb/msutb.cpp
+++ b/dll/win32/msutb/msutb.cpp
@@ -20,6 +20,7 @@ LONG g_DllRefCount = 0;
BOOL g_bWinLogon = FALSE;
BOOL g_fInClosePopupTipbar = FALSE;
HWND g_hwndParent = NULL;
+LIBTHREAD g_libTLS = { NULL, NULL };
#ifdef ENABLE_DESKBAND
BOOL g_bEnableDeskBand = TRUE;
#else
@@ -76,6 +77,23 @@ class CMsUtbModule : public CComModule
CMsUtbModule gModule;
+void TFUninitLib_Thread(LIBTHREAD *libThread)
+{
+ if (!libThread)
+ return;
+
+ if (libThread->m_pUnknown1)
+ {
+ libThread->m_pUnknown1->Release();
+ libThread->m_pUnknown1 = NULL;
+ }
+ if (libThread->m_pDisplayAttrMgr)
+ {
+ libThread->m_pDisplayAttrMgr->Release();
+ libThread->m_pDisplayAttrMgr = NULL;
+ }
+}
+
class CCicLibMenuItem;
class CTipbarAccItem;
class CUTBMenuItem;
@@ -1259,6 +1277,7 @@ public:
/***********************************************************************/
class CTipbarItem;
+class CTipbarBalloonItem;
class CTipbarThread
{
@@ -1306,6 +1325,18 @@ public:
LONG _AddRef() { return ++m_cRefs; }
LONG _Release();
+ /// @unimplemented
+ BOOL SetFocus(CTipbarBalloonItem *pTarget)
+ {
+ return FALSE;
+ }
+
+ /// @unimplemented
+ HRESULT CallOnUpdateHandler()
+ {
+ return E_NOTIMPL;
+ }
+
//FIXME
};
@@ -1383,6 +1414,24 @@ public:
class CTipbarCtrlButtonHolder;
class CDeskBand;
+// Flags for m_dwTipbarWndFlags
+enum
+{
+ TIPBAR_ATTACHED = 0x1,
+ TIPBAR_CHILD = 0x2,
+ TIPBAR_VERTICAL = 0x4,
+ TIPBAR_HIGHCONTRAST = 0x10,
+ TIPBAR_TRAYICON = 0x20,
+ TIPBAR_UPDATING = 0x400,
+ TIPBAR_ENSURING = 0x2000,
+ TIPBAR_NODESKBAND = 0x4000,
+ TIPBAR_TOOLBARENDED = 0x10000,
+ TIPBAR_TOPFIT = 0x40000,
+ TIPBAR_BOTTOMFIT = 0x80000,
+ TIPBAR_RIGHTFIT = 0x100000,
+ TIPBAR_LEFTFIT = 0x200000,
+};
+
class CTipbarWnd
: public ITfLangBarEventSink
, public ITfLangBarEventSink_P
@@ -1434,6 +1483,7 @@ class CTipbarWnd
friend class CTipbarGripper;
friend class CTipbarThread;
friend class CTipbarItem;
+ friend class CLBarInatItem;
friend VOID WINAPI ClosePopupTipbar(VOID);
friend BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand *pDeskBand);
friend LONG MyWaitForInputIdle(DWORD dwThreadId, DWORD dwMilliseconds);
@@ -1522,6 +1572,12 @@ public:
void OnTerminateToolbar();
HRESULT OnThreadTerminateInternal(DWORD dwThreadId);
+ /// @unimplemented
+ HRESULT OnThreadItemChangeInternal(DWORD dwThreadId)
+ {
+ return E_NOTIMPL;
+ }
+
// IUnknown methods
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
STDMETHOD_(ULONG, AddRef)();
@@ -2807,7 +2863,7 @@ CUTBMenuWnd *CUTBContextMenu::CreateMenuUI(BOOL bFlag)
CUTBMenuItem *pVertical = InsertItem(pMenuUI, ID_VERTICAL, IDS_VERTICAL);
if (pVertical)
- pVertical->Check(!!(m_pTipbarWnd->m_dwTipbarWndFlags &
0x800000));
+ pVertical->Check(!!(m_pTipbarWnd->m_dwTipbarWndFlags &
TIPBAR_VERTICAL));
}
}
@@ -2940,12 +2996,12 @@ BOOL CUTBContextMenu::SelectMenuItem(UINT nCommandId)
}
case ID_EXTRAICONS:
- m_pTipbarWnd->m_dwTipbarWndFlags &= ~0x4000;
+ m_pTipbarWnd->m_dwTipbarWndFlags &= ~TIPBAR_NODESKBAND;
m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_EXTRAICONSONMINIMIZED);
break;
case ID_NOEXTRAICONS:
- m_pTipbarWnd->m_dwTipbarWndFlags &= ~0x4000;
+ m_pTipbarWnd->m_dwTipbarWndFlags &= ~TIPBAR_NODESKBAND;
m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOEXTRAICONSONMINIMIZED);
break;
@@ -2954,7 +3010,7 @@ BOOL CUTBContextMenu::SelectMenuItem(UINT nCommandId)
break;
case ID_VERTICAL:
- m_pTipbarWnd->SetVertical((m_pTipbarWnd->m_dwTipbarWndFlags & 0x4)
? TRUE : FALSE);
+ m_pTipbarWnd->SetVertical(!!(m_pTipbarWnd->m_dwTipbarWndFlags &
TIPBAR_VERTICAL));
break;
case ID_ADJUSTDESKBAND:
@@ -3759,7 +3815,6 @@ STDMETHODIMP CLBarInatItem::InitMenu(ITfMenu *pMenu)
}
}
-#if 0 // FIXME: g_pTipbarWnd
DWORD dwStatus;
if (g_pTipbarWnd &&
g_pTipbarWnd->m_pLangBarMgr &&
@@ -3772,7 +3827,6 @@ STDMETHODIMP CLBarInatItem::InitMenu(ITfMenu *pMenu)
::LoadStringW(g_hInst, IDS_RESTORELANGBAR2, szText, _countof(szText));
LangBarInsertMenu(pMenu, 2000, szText, FALSE, NULL);
}
-#endif
return S_OK;
}
@@ -3785,18 +3839,14 @@ STDMETHODIMP CLBarInatItem::OnMenuSelect(INT nCommandId)
{
if (g_pTipbarWnd)
{
-#if 0 // FIXME: g_pTipbarWnd
ITfLangBarMgr *pLangBarMgr = g_pTipbarWnd->m_pLangBarMgr;
if (pLangBarMgr)
pLangBarMgr->ShowFloating(TF_SFT_SHOWNORMAL);
-#endif
}
}
else if (TF_GetMlngHKL(nCommandId, &hKL, NULL, 0))
{
-#if 0 // FIXME: g_pTipbarWnd
- g_pTipbarWnd->RestoreLastFocus(0, (g_pTipbarWnd->m_dwTipbarWndFlags &
2) != 0);
-#endif
+ g_pTipbarWnd->RestoreLastFocus(NULL, !!(g_pTipbarWnd->m_dwTipbarWndFlags
& TIPBAR_CHILD));
HWND hwndFore = ::GetForegroundWindow();
if (m_dwThreadId == ::GetWindowThreadProcessId(hwndFore, NULL))
{
@@ -3912,7 +3962,6 @@ CTipbarWnd::CTipbarWnd(DWORD style)
m_cRefs = 1;
}
-/// @unimplemented
CTipbarWnd::~CTipbarWnd()
{
UnInit();
@@ -3922,23 +3971,66 @@ CTipbarWnd::~CTipbarWnd()
if (m_hTextFont)
::DeleteObject(m_hTextFont);
- //TFUninitLib_Thread(&g_libTLS); //FIXME
+ TFUninitLib_Thread(&g_libTLS);
}
/// @unimplemented
void CTipbarWnd::Init(BOOL bChild, CDeskBand *pDeskBand)
{
+ if (bChild)
+ m_dwTipbarWndFlags |= TIPBAR_CHILD;
+ else
+ m_dwTipbarWndFlags &= ~TIPBAR_CHILD;
+
+ if (m_dwTipbarWndFlags & TIPBAR_CHILD)
+ m_dwTipbarWndFlags &= TIPBAR_HIGHCONTRAST;
+
+ m_pDeskBand = pDeskBand;
+
+ RECT rc = { 0, 0, 0, 0 };
+
+ if (g_bNewLook && !m_pWndFrame && (m_style & 0x20000000))
+ {
+ CUIFWndFrame *pWndFrame = new(cicNoThrow) CUIFWndFrame(GetWindow(), &rc, 0);
+ if (pWndFrame)
+ {
+ pWndFrame->Initialize();
+ AddUIObj(m_pWndFrame);
+ }
+ }
+
+ if (!m_pTipbarGripper && !(m_dwTipbarWndFlags & TIPBAR_CHILD))
+ {
+ m_pTipbarGripper =
+ new(cicNoThrow) CTipbarGripper(this, &rc, !!(m_dwTipbarWndFlags &
TIPBAR_VERTICAL));
+ if (m_pTipbarGripper)
+ {
+ m_pTipbarGripper->Initialize();
+ AddUIObj(m_pTipbarGripper);
+ }
+ }
+
+ //FIXME: CTipbarCtrlButtonHolder
+
+ if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
+ {
+ Move(m_nLeft, m_nTop, GetTipbarHeight(), 0);
+ }
+ else
+ {
+ Move(m_nLeft, m_nTop, 0, GetTipbarHeight());
+ }
}
void CTipbarWnd::InitHighContrast()
{
- m_dwTipbarWndFlags &= ~0x10;
+ m_dwTipbarWndFlags &= ~TIPBAR_HIGHCONTRAST;
HIGHCONTRAST HiCon = { sizeof(HiCon) };
if (::SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HiCon), &HiCon, 0))
{
if (HiCon.dwFlags & HCF_HIGHCONTRASTON)
- m_dwTipbarWndFlags |= 0x10;
+ m_dwTipbarWndFlags |= TIPBAR_HIGHCONTRAST;
}
}
@@ -3999,9 +4091,29 @@ void CTipbarWnd::InitThemeMargins()
theme.CloseThemeData();
}
-/// @unimplemented
void CTipbarWnd::UnInit()
{
+ SetFocusThread(NULL);
+ for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
+ {
+ CTipbarThread* pThread = m_Threads[iItem];
+ if (pThread)
+ {
+ pThread->_UninitItemList(TRUE);
+ pThread->m_pTipbarWnd = NULL;
+ pThread->_Release();
+ }
+ }
+ m_Threads.clear();
+
+ if (m_pLangBarMgr)
+ m_pLangBarMgr->UnAdviseEventSink(m_dwSinkCookie);
+
+ if (m_pLangBarMgr)
+ {
+ m_pLangBarMgr->Release();
+ m_pLangBarMgr = NULL;
+ }
}
BOOL CTipbarWnd::IsFullScreenWindow(HWND hWnd)
@@ -4029,10 +4141,11 @@ BOOL CTipbarWnd::IsHKLToSkipRedrawOnNoItem()
return IsSkipRedrawHKL(hKL);
}
-/// @unimplemented
BOOL CTipbarWnd::IsInItemChangeOrDirty(CTipbarThread *pTarget)
{
- return FALSE;
+ if (pTarget->m_dwThreadId == m_dwChangingThreadId)
+ return TRUE;
+ return pTarget->IsDirtyItem();
}
void CTipbarWnd::AddThreadToThreadCreatingList(CTipbarThread *pThread)
@@ -4047,9 +4160,30 @@ void CTipbarWnd::RemoveThredFromThreadCreatingList(CTipbarThread
*pTarget)
m_ThreadCreatingList.Remove(iItem);
}
-/// @unimplemented
void CTipbarWnd::MoveToStub(BOOL bFlag)
{
+ m_dwTipbarWndFlags |= 0x40;
+
+ RECT rcWorkArea;
+ ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+
+ if (bFlag)
+ {
+ m_nLeft = rcWorkArea.right - 38;
+ m_dwTipbarWndFlags &= ~0x80;
+ }
+ else
+ {
+ RECT Rect;
+ ::GetWindowRect(m_hWnd, &Rect);
+ m_nLeft = rcWorkArea.right + Rect.left - Rect.right;
+ m_dwTipbarWndFlags |= 0x80;
+ }
+
+ m_nTop = rcWorkArea.bottom - m_cyDlgFrameX2 - GetTipbarHeight();
+
+ if (m_pFocusThread)
+ m_pFocusThread->MyMoveWnd(0, 0);
}
void CTipbarWnd::RestoreFromStub()
@@ -4099,10 +4233,23 @@ INT CTipbarWnd::GetTipbarHeight()
return m_cySmallIcon + cy + (2 * size.cy);
}
-/// @unimplemented
BOOL CTipbarWnd::AutoAdjustDeskBandSize()
{
- return FALSE;
+ if ((m_dwTipbarWndFlags & TIPBAR_NODESKBAND) ||
+ !m_pFocusThread ||
+ (m_pFocusThread->m_dwFlags1 & 0x800))
+ {
+ return FALSE;
+ }
+
+ DWORD dwOldWndFlags = m_dwTipbarWndFlags;
+ m_dwTipbarWndFlags &= ~0x8000;
+
+ if (!AdjustDeskBandSize(!(dwOldWndFlags & 0x8000)))
+ return FALSE;
+
+ m_dwTipbarWndFlags |= TIPBAR_NODESKBAND;
+ return TRUE;
}
/// @unimplemented
@@ -4124,13 +4271,13 @@ void CTipbarWnd::AdjustPosOnDisplayChange()
return;
INT x = m_nLeft, y = m_nTop;
- if (m_dwTipbarWndFlags & 0x200000)
+ if (m_dwTipbarWndFlags & TIPBAR_LEFTFIT)
x = rcWorkArea.left;
- if (m_dwTipbarWndFlags & 0x40000)
+ if (m_dwTipbarWndFlags & TIPBAR_TOPFIT)
y = rcWorkArea.top;
- if (m_dwTipbarWndFlags & 0x100000)
+ if (m_dwTipbarWndFlags & TIPBAR_RIGHTFIT)
x = rcWorkArea.right - m_nWidth;
- if (m_dwTipbarWndFlags & 0x80000)
+ if (m_dwTipbarWndFlags & TIPBAR_BOTTOMFIT)
y = rcWorkArea.bottom - m_nHeight;
if (x != m_nLeft || y != m_nTop)
Move(x, y, m_nWidth, m_nHeight);
@@ -4139,9 +4286,9 @@ void CTipbarWnd::AdjustPosOnDisplayChange()
void CTipbarWnd::SetVertical(BOOL bVertical)
{
if (bVertical)
- m_dwTipbarWndFlags |= 0x4;
+ m_dwTipbarWndFlags |= TIPBAR_VERTICAL;
else
- m_dwTipbarWndFlags &= ~0x4;
+ m_dwTipbarWndFlags &= ~TIPBAR_VERTICAL;
if (m_pTipbarGripper)
{
@@ -4154,11 +4301,11 @@ void CTipbarWnd::SetVertical(BOOL bVertical)
}
if (g_fTaskbarTheme)
- SetActiveTheme(L"TASKBAR", !!(m_dwTipbarWndFlags & 0x4), 1);
+ SetActiveTheme(L"TASKBAR", !!(m_dwTipbarWndFlags &
TIPBAR_VERTICAL), 1);
- if (!(m_dwTipbarWndFlags & 2))
+ if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
{
- if (m_dwTipbarWndFlags & 4)
+ if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
{
Move(m_nLeft, m_nTop, GetTipbarHeight(), 0);
}
@@ -4177,37 +4324,48 @@ void CTipbarWnd::SetVertical(BOOL bVertical)
void CTipbarWnd::UpdatePosFlags()
{
- if (m_dwTipbarWndFlags & 0x2)
+ if (m_dwTipbarWndFlags & TIPBAR_CHILD)
return;
RECT rc = { m_nLeft, m_nTop, m_nLeft + m_nWidth, m_nTop + m_nHeight }, rcWorkArea;
if (!GetWorkArea(&rc, &rcWorkArea))
return;
- if (m_nLeft > rcWorkArea.left + 2)
- m_dwTipbarWndFlags &= ~0x200000;
+ if (rcWorkArea.left + 2 < m_nLeft)
+ m_dwTipbarWndFlags &= ~TIPBAR_LEFTFIT;
else
- m_dwTipbarWndFlags |= 0x200000;
+ m_dwTipbarWndFlags |= TIPBAR_LEFTFIT;
- if ( m_nTop> rcWorkArea.top + 2 )
- m_dwTipbarWndFlags &= ~0x40000;
+ if (rcWorkArea.top + 2 < m_nTop)
+ m_dwTipbarWndFlags &= ~TIPBAR_TOPFIT;
else
- m_dwTipbarWndFlags |= 0x40000;
+ m_dwTipbarWndFlags |= TIPBAR_TOPFIT;
if (m_nLeft + m_nWidth < rcWorkArea.right - 2)
- m_dwTipbarWndFlags &= ~0x100000;
+ m_dwTipbarWndFlags &= ~TIPBAR_RIGHTFIT;
else
- m_dwTipbarWndFlags |= 0x100000;
+ m_dwTipbarWndFlags |= TIPBAR_RIGHTFIT;
if (m_nTop + m_nHeight < rcWorkArea.bottom - 2)
- m_dwTipbarWndFlags &= ~0x80000;
+ m_dwTipbarWndFlags &= ~TIPBAR_BOTTOMFIT;
else
- m_dwTipbarWndFlags |= 0x80000;
+ m_dwTipbarWndFlags |= TIPBAR_BOTTOMFIT;
}
-/// @unimplemented
void CTipbarWnd::CancelMenu()
{
+ if (!m_pThread)
+ return;
+
+ CTipbarWnd *pTipbarWnd = m_pThread->m_pTipbarWnd;
+ if (pTipbarWnd)
+ {
+ if (pTipbarWnd->m_pLangBarMgr)
+ pTipbarWnd->StartModalInput(NULL, m_pThread->m_dwThreadId);
+ }
+
+ m_pModalMenu->CancelMenu();
+ StartBackToAlphaTimer();
}
BOOL CTipbarWnd::CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT prc2)
@@ -4215,9 +4373,11 @@ BOOL CTipbarWnd::CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT
prc2)
return (prc1->top < prc2->top + 5) && (prc2->right <=
prc1->right + (5 * m_ButtonWidth));
}
-/// @unimplemented
void CTipbarWnd::ClearLBItemList()
{
+ m_TipbarGUIDArray.clear();
+ if (m_pFocusThread)
+ OnThreadItemChange(m_pFocusThread->m_dwThreadId);
}
HFONT CTipbarWnd::CreateVerticalFont()
@@ -4253,7 +4413,7 @@ HFONT CTipbarWnd::CreateVerticalFont()
void CTipbarWnd::UpdateVerticalFont()
{
- if (m_dwTipbarWndFlags & 4)
+ if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
{
if (m_hTextFont)
{
@@ -4273,6 +4433,7 @@ void CTipbarWnd::UpdateVerticalFont()
/// @unimplemented
void CTipbarWnd::ShowOverScreenSizeBalloon()
{
+ //FIXME: CTipbarCtrlButtonHolder
}
void CTipbarWnd::DestroyOverScreenSizeBalloon()
@@ -4292,15 +4453,26 @@ void CTipbarWnd::DestroyWnd()
::DestroyWindow(m_hWnd);
}
-/// @unimplemented
HKL CTipbarWnd::GetFocusKeyboardLayout()
{
- return NULL;
+ DWORD dwThreadId = 0;
+ if (m_pFocusThread)
+ dwThreadId = m_pFocusThread->m_dwThreadId;
+ return ::GetKeyboardLayout(dwThreadId);
}
-/// @unimplemented
void CTipbarWnd::KillOnTheadItemChangeTimer()
{
+ DWORD dwChangingThreadId = m_dwChangingThreadId;
+ m_dwChangingThreadId = 0;
+ KillTimer(4);
+
+ if (dwChangingThreadId)
+ {
+ CTipbarThread *pThread = _FindThread(dwChangingThreadId);
+ if (pThread)
+ pThread->m_dwUnknown34 |= 0x1;
+ }
}
UINT_PTR CTipbarWnd::SetTimer(UINT_PTR nIDEvent, UINT uElapse)
@@ -4347,7 +4519,7 @@ void CTipbarWnd::SavePosition()
::ClientToScreen(m_hWnd, &pt);
regKey.SetDword(TEXT("Left"), pt.x);
regKey.SetDword(TEXT("Top"), pt.y);
- regKey.SetDword(TEXT("Vertical"), !!(m_dwTipbarWndFlags & 4));
+ regKey.SetDword(TEXT("Vertical"), !!(m_dwTipbarWndFlags &
TIPBAR_VERTICAL));
}
}
@@ -4379,13 +4551,10 @@ BOOL CTipbarWnd::SetLangBand(BOOL bDeskBand, BOOL bFlag2)
ret = FALSE;
}
- if (!(m_dwTipbarWndFlags & 2))
+ if (!(m_dwTipbarWndFlags & TIPBAR_CHILD) && bDeskBand)
{
- if (bDeskBand)
- {
- KillTimer(7);
- SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
- }
+ KillTimer(7);
+ SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
}
return ret;
@@ -4393,7 +4562,7 @@ BOOL CTipbarWnd::SetLangBand(BOOL bDeskBand, BOOL bFlag2)
void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight)
{
- if (m_dwTipbarWndFlags & 0x2)
+ if (m_dwTipbarWndFlags & TIPBAR_CHILD)
{
m_nWidth = nWidth;
m_nHeight = nHeight;
@@ -4402,7 +4571,7 @@ void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight)
++m_bInCallOn;
- m_dwTipbarWndFlags |= 0x400;
+ m_dwTipbarWndFlags |= TIPBAR_UPDATING;
m_X = X;
m_Y = Y;
@@ -4420,7 +4589,7 @@ void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight)
if (m_pTipbarGripper)
{
- if (m_dwTipbarWndFlags & 4)
+ if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
{
INT GripperWidth = GetGripperWidth();
::SetRect(&rc, size.cx, size.cy, nWidth - m_cxDlgFrameX2 - size.cx,
size.cy + GripperWidth);
@@ -4437,19 +4606,27 @@ void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT
nHeight)
--m_bInCallOn;
}
-/// @unimplemented
void CTipbarWnd::SetShowText(BOOL bShow)
{
+ if (bShow)
+ m_dwTipbarWndFlags |= TIPBAR_HIGHCONTRAST;
+ else
+ m_dwTipbarWndFlags &= ~TIPBAR_HIGHCONTRAST;
+
+ if (m_pFocusThread)
+ OnThreadItemChange(m_pFocusThread->m_dwThreadId);
+
+ TerminateAllThreads(FALSE);
}
void CTipbarWnd::SetShowTrayIcon(BOOL bShow)
{
- if (m_dwTipbarWndFlags & 0x20)
- m_dwTipbarWndFlags &= ~0x20;
+ if (m_dwTipbarWndFlags & TIPBAR_TRAYICON)
+ m_dwTipbarWndFlags &= ~TIPBAR_TRAYICON;
else
- m_dwTipbarWndFlags |= 0x20;
+ m_dwTipbarWndFlags |= TIPBAR_TRAYICON;
- if ((m_dwTipbarWndFlags & 0x20) && m_pFocusThread)
+ if ((m_dwTipbarWndFlags & TIPBAR_TRAYICON) && m_pFocusThread)
{
KillTimer(10);
SetTimer(10, g_uTimerElapseMOVETOTRAY);
@@ -4461,9 +4638,45 @@ void CTipbarWnd::SetShowTrayIcon(BOOL bShow)
}
}
-/// @unimplemented
void CTipbarWnd::ShowContextMenu(POINT pt, LPCRECT prc, BOOL bFlag)
{
+ AddRef();
+
+ RECT rc;
+ if (!prc)
+ {
+ rc = { pt.x, pt.y, pt.x, pt.y };
+ prc = &rc;
+ }
+
+ if (m_pFocusThread)
+ {
+ CUTBContextMenu *pContextMenu = new(cicNoThrow) CUTBContextMenu(this);
+ if (pContextMenu)
+ {
+ if (pContextMenu->Init())
+ {
+ m_pThread = m_pFocusThread;
+ StartModalInput(this, m_pFocusThread->m_dwThreadId);
+
+ m_pModalMenu = pContextMenu;
+ DWORD dwCommandId = pContextMenu->ShowPopup(GetWindow(), pt, prc,
bFlag);
+ m_pModalMenu = NULL;
+
+ if (m_pThread)
+ StopModalInput(m_pThread->m_dwThreadId);
+
+ m_pThread = NULL;
+
+ if (dwCommandId != (DWORD)-1)
+ pContextMenu->SelectMenuItem(dwCommandId);
+ }
+
+ delete pContextMenu;
+ }
+ }
+
+ Release();
}
void CTipbarWnd::StartBackToAlphaTimer()
@@ -4472,10 +4685,17 @@ void CTipbarWnd::StartBackToAlphaTimer()
::SetTimer(m_hWnd, 3, 3 * uTime, NULL);
}
-/// @unimplemented
BOOL CTipbarWnd::StartDoAccDefaultActionTimer(CTipbarItem *pTarget)
{
- return FALSE;
+ if (!m_pTipbarAccessible)
+ return FALSE;
+ INT IDOfItem = m_pTipbarAccessible->GetIDOfItem(pTarget);
+ m_nID = IDOfItem;
+ if (!IDOfItem || IDOfItem == -1)
+ return FALSE;
+ KillTimer(11);
+ SetTimer(11, g_uTimerElapseDOACCDEFAULTACTION);
+ return TRUE;
}
void CTipbarWnd::StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId)
@@ -4504,27 +4724,87 @@ void CTipbarWnd::StopModalInput(DWORD dwThreadId)
m_pLangBarMgr->SetModalInput(NULL, dwCurThreadId, 0);
}
-/// @unimplemented
+LONG MyWaitForInputIdle(DWORD dwThreadId, DWORD dwMilliseconds)
+{
+ if (g_pTipbarWnd && (g_pTipbarWnd->m_dwShowType & TF_SFT_DESKBAND))
+ return 0;
+
+ if (TF_IsInMarshaling(dwThreadId))
+ return STATUS_TIMEOUT;
+
+ DWORD dwFlags1 = 0, dwFlags2 = 0;
+ if (!TF_GetThreadFlags(dwThreadId, &dwFlags1, &dwFlags2, NULL) &&
dwFlags2)
+ return -1;
+
+ return TF_CheckThreadInputIdle(dwThreadId, dwMilliseconds);
+}
+
CTipbarThread *CTipbarWnd::_CreateThread(DWORD dwThreadId)
{
- return NULL;
+ CTipbarThread *pTarget = _FindThread(dwThreadId);
+ if (pTarget)
+ return pTarget;
+
+ MyWaitForInputIdle(dwThreadId, 2000);
+
+ pTarget = new(cicNoThrow) CTipbarThread(this);
+ if (!pTarget)
+ return NULL;
+
+ AddThreadToThreadCreatingList(pTarget);
+
+ HRESULT hr = pTarget->Init(dwThreadId);
+
+ RemoveThredFromThreadCreatingList(pTarget);
+
+ if (SUCCEEDED(hr) && !m_Threads.Add(pTarget))
+ {
+ pTarget->_UninitItemList(TRUE);
+ pTarget->m_pTipbarWnd = NULL;
+ pTarget->_Release();
+ return NULL;
+ }
+
+ return pTarget;
}
-/// @unimplemented
CTipbarThread *CTipbarWnd::_FindThread(DWORD dwThreadId)
{
- return NULL;
+ if (g_bWinLogon)
+ return NULL;
+
+ CTipbarThread *pTarget = NULL;
+ for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
+ {
+ CTipbarThread *pThread = m_Threads[iItem];
+ if (pThread && pThread->m_dwThreadId == dwThreadId)
+ {
+ pTarget = pThread;
+ break;
+ }
+ }
+
+ if (!pTarget)
+ return NULL;
+
+ DWORD dwFlags1, dwFlags2, dwFlags3;
+ TF_GetThreadFlags(dwThreadId, &dwFlags1, &dwFlags2, &dwFlags3);
+
+ if (!dwFlags2 || (dwFlags2 != pTarget->m_dwFlags2) || (dwFlags3 !=
pTarget->m_dwFlags3))
+ {
+ OnThreadTerminateInternal(dwThreadId);
+ return NULL;
+ }
+
+ return pTarget;
}
void CTipbarWnd::EnsureFocusThread()
{
- if (m_pFocusThread)
- return;
-
- if (m_dwTipbarWndFlags & 0x12000)
+ if (m_pFocusThread || (m_dwTipbarWndFlags & (TIPBAR_TOOLBARENDED |
TIPBAR_ENSURING)))
return;
- m_dwTipbarWndFlags |= 0x2000;
+ m_dwTipbarWndFlags |= TIPBAR_ENSURING;
HWND hwndFore = ::GetForegroundWindow();
if (!hwndFore)
@@ -4534,19 +4814,41 @@ void CTipbarWnd::EnsureFocusThread()
if (dwThreadId)
OnSetFocus(dwThreadId);
- m_dwTipbarWndFlags &= ~0x2000;
+ m_dwTipbarWndFlags &= ~TIPBAR_ENSURING;
}
-/// @unimplemented
HRESULT CTipbarWnd::SetFocusThread(CTipbarThread *pFocusThread)
{
- return E_NOTIMPL;
+ if (pFocusThread == m_pFocusThread)
+ return S_OK;
+
+ DWORD dwThreadId = ::GetCurrentThreadId();
+ DestroyOverScreenSizeBalloon();
+
+ if (m_pFocusThread)
+ {
+ m_pFocusThread->SetFocus(NULL);
+ ::AttachThreadInput(dwThreadId, m_pFocusThread->m_dwThreadId, FALSE);
+ }
+
+ m_dwTipbarWndFlags &= ~TIPBAR_ATTACHED;
+ m_pFocusThread = pFocusThread;
+ return S_OK;
}
-/// @unimplemented
HRESULT CTipbarWnd::AttachFocusThread()
{
- return E_NOTIMPL;
+ if (m_dwTipbarWndFlags & TIPBAR_ATTACHED)
+ return S_FALSE;
+
+ if (m_pFocusThread)
+ {
+ DWORD dwThreadId = ::GetCurrentThreadId();
+ ::AttachThreadInput(dwThreadId, m_pFocusThread->m_dwThreadId, TRUE);
+ m_dwTipbarWndFlags |= TIPBAR_ATTACHED;
+ }
+
+ return S_OK;
}
void CTipbarWnd::RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev)
@@ -4574,9 +4876,31 @@ void CTipbarWnd::CleanUpThreadPointer(CTipbarThread *pThread, BOOL
bRemove)
m_pUnknownThread = NULL;
}
-/// @unimplemented
void CTipbarWnd::TerminateAllThreads(BOOL bFlag)
{
+ const size_t cItems = m_Threads.size();
+
+ DWORD *pdwThreadIds = new(cicNoThrow) DWORD[cItems];
+ if (!pdwThreadIds)
+ return;
+
+ for (size_t iItem = 0; iItem < cItems; ++iItem)
+ {
+ pdwThreadIds[iItem] = 0;
+ CTipbarThread* pThread = m_Threads[iItem];
+ if (pThread && (bFlag || (pThread != m_pFocusThread)))
+ {
+ pdwThreadIds[iItem] = pThread->m_dwThreadId;
+ }
+ }
+
+ for (size_t iItem = 0; iItem < cItems; ++iItem)
+ {
+ if (pdwThreadIds[iItem])
+ OnThreadTerminateInternal(pdwThreadIds[iItem]);
+ }
+
+ delete[] pdwThreadIds;
}
STDMETHODIMP CTipbarWnd::QueryInterface(REFIID riid, void **ppvObj)
@@ -4632,16 +4956,61 @@ STDMETHODIMP CTipbarWnd::OnThreadTerminate(DWORD dwThreadId)
return hr;
}
-/// @unimplemented
HRESULT CTipbarWnd::OnThreadTerminateInternal(DWORD dwThreadId)
{
- return E_NOTIMPL;
+ for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
+ {
+ CTipbarThread *pThread = m_Threads[iItem];
+ if (pThread && pThread->m_dwThreadId == dwThreadId)
+ {
+ m_Threads.Remove(iItem);
+ pThread->RemoveUIObjs();
+ CleanUpThreadPointer(pThread, FALSE);
+ pThread->_UninitItemList(TRUE);
+ pThread->m_pTipbarWnd = NULL;
+ pThread->_Release();
+ break;
+ }
+ }
+
+ return S_OK;
}
-/// @unimplemented
STDMETHODIMP CTipbarWnd::OnThreadItemChange(DWORD dwThreadId)
{
- return E_NOTIMPL;
+ if (m_dwTipbarWndFlags & TIPBAR_TOOLBARENDED)
+ return S_OK;
+ if (!(m_dwTipbarWndFlags & TIPBAR_CHILD) && (m_dwShowType &
TF_SFT_DESKBAND))
+ return S_OK;
+
+ CTipbarThread *pThread = _FindThread(dwThreadId);
+ if (pThread)
+ {
+ if ((!m_dwUnknown23 || m_dwUnknown23 == dwThreadId) && pThread ==
m_pFocusThread)
+ {
+ KillOnTheadItemChangeTimer();
+ m_dwChangingThreadId = dwThreadId;
+ KillTimer(6);
+ SetTimer(4, g_uTimerElapseONTHREADITEMCHANGE);
+ }
+ else
+ {
+ pThread->m_dwUnknown34 |= 0x1;
+ }
+ }
+ else
+ {
+ for (size_t iItem = 0; iItem < m_ThreadCreatingList.size(); ++iItem)
+ {
+ CTipbarThread *pItem = m_ThreadCreatingList[iItem];
+ if (pItem && pItem->m_dwThreadId == dwThreadId)
+ {
+ pItem->m_dwUnknown34 |= 0x1;
+ }
+ }
+ }
+
+ return S_OK;
}
STDMETHODIMP CTipbarWnd::OnModalInput(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM
lParam)
@@ -4700,10 +5069,28 @@ STDMETHODIMP CTipbarWnd::ShowFloating(DWORD dwFlags)
return E_NOTIMPL;
}
-/// @unimplemented
STDMETHODIMP CTipbarWnd::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
{
- return E_NOTIMPL;
+ if (m_dwTipbarWndFlags & TIPBAR_TRAYICON)
+ return E_UNEXPECTED;
+
+ if (!m_pFocusThread || (m_pFocusThread->m_dwThreadId != dwThreadId))
+ return E_FAIL;
+
+ for (size_t iItem = 0; iItem < m_pFocusThread->m_UIObjects.size(); ++iItem)
+ {
+ CTipbarItem* pItem = m_pFocusThread->m_UIObjects[iItem];
+ if (pItem)
+ {
+ if ((pItem->m_dwItemFlags & 0x8) &&
IsEqualGUID(pItem->m_ItemInfo.guidItem, rguid))
+ {
+ pItem->OnUnknown57(prc);
+ return S_OK;
+ }
+ }
+ }
+
+ return E_FAIL;
}
/// @unimplemented
@@ -4724,9 +5111,20 @@ STDMETHODIMP_(void) CTipbarWnd::GetAccLocation(LPRECT lprc)
GetRect(lprc);
}
-/// @unimplemented
STDMETHODIMP_(void) CTipbarWnd::PaintObject(HDC hDC, LPCRECT prc)
{
+ if (m_dwTipbarWndFlags & TIPBAR_UPDATING)
+ {
+ Move(m_X, m_Y, m_CX, m_CY);
+ m_dwTipbarWndFlags &= ~TIPBAR_UPDATING;
+ }
+
+ if (!m_pFocusThread || !m_pFocusThread->IsDirtyItem())
+ {
+ m_pFocusThread->CallOnUpdateHandler();
+ if (g_pTipbarWnd)
+ CUIFWindow::PaintObject(hDC, prc);
+ }
}
STDMETHODIMP_(DWORD) CTipbarWnd::GetWndStyle()
@@ -4775,6 +5173,140 @@ STDMETHODIMP_(void) CTipbarWnd::OnDestroy(HWND hWnd)
/// @unimplemented
STDMETHODIMP_(void) CTipbarWnd::OnTimer(WPARAM wParam)
{
+ AddRef();
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(1);
+ MoveToStub(FALSE);
+ break;
+ case 2:
+ KillTimer(2);
+ MoveToStub(TRUE);
+ break;
+ case 3:
+ KillTimer(3);
+ SetAlpha((BYTE)m_dwAlphaValue, TRUE);
+ break;
+ case 4:
+ {
+ LONG status = MyWaitForInputIdle(m_dwChangingThreadId, 2000);
+ if (status)
+ {
+ if (status != STATUS_TIMEOUT)
+ {
+ KillTimer(4);
+ m_dwChangingThreadId = 0;
+ }
+ }
+ else if (!m_pThread)
+ {
+ KillTimer(4);
+ DWORD dwOldThreadId = m_dwChangingThreadId;
+ m_dwChangingThreadId = 0;
+ OnThreadItemChangeInternal(dwOldThreadId);
+ }
+ break;
+ }
+ case 5:
+ KillTimer(5);
+ ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |
SWP_NOSIZE);
+ break;
+ case 6:
+ KillTimer(6);
+ if (m_pFocusThread)
+ {
+ if (m_pFocusThread->m_dwThreadId != m_dwChangingThreadId &&
+ !m_pFocusThread->CallOnUpdateHandler())
+ {
+ if (m_pFocusThread)
+ OnThreadItemChange(m_pFocusThread->m_dwThreadId);
+ }
+ }
+ break;
+ case 7:
+ {
+ DWORD dwThreadId = 0;
+ if (KillTimer(7))
+ {
+ if (m_pFocusThread)
+ dwThreadId = m_pFocusThread->m_dwThreadId;
+
+ TerminateAllThreads(TRUE);
+ UpdateVerticalFont();
+
+ if (dwThreadId)
+ OnSetFocus(dwThreadId);
+
+ InitMetrics();
+ // FIXME: CTipbarCtrlButtonHolder
+
+ InitHighContrast();
+ SetAlpha(0xFF, TRUE);
+ ::RedrawWindow(m_hWnd, NULL, NULL, (RDW_FRAME | RDW_UPDATENOW |
RDW_INVALIDATE));
+ }
+ break;
+ }
+ case 8:
+ KillTimer(8);
+ UpdateUI(NULL);
+ break;
+ case 9:
+ KillTimer(9);
+ //FIXME
+ if (m_pUnknownThread == m_pFocusThread)
+ Show(!!(m_dwUnknown23_5[3] & 0x80000000));
+ m_pUnknownThread = NULL;
+ if ((m_dwUnknown23_5[3] & 0x2))
+ ShowOverScreenSizeBalloon();
+ break;
+ case 10:
+ KillTimer(10);
+ MoveToTray();
+ break;
+ case 11:
+ KillTimer(11);
+ if (m_pTipbarAccessible)
+ {
+ if (m_nID)
+ {
+ m_pTipbarAccessible->DoDefaultActionReal(m_nID);
+ m_nID = 0;
+ }
+ }
+ break;
+ case 12:
+ KillTimer(12);
+ AdjustPosOnDisplayChange();
+ break;
+ case 13:
+#ifdef ENABLE_DESKBAND
+ if (!m_pDeskBand || !m_pDeskBand->m_dwUnknown19)
+ {
+ KillTimer(13);
+ if (!m_pFocusThread)
+ EnsureFocusThread();
+ }
+#endif
+ break;
+ case 14:
+ if (SetLangBand(TRUE, TRUE))
+ {
+ m_dwShowType = TF_SFT_DESKBAND;
+ KillTimer(14);
+ }
+ break;
+ default:
+ {
+ if ((10000 <= wParam) && (wParam <= 10049))
+ {
+ // FIXME: CLangBarItemList
+ }
+ break;
+ }
+ }
+
+ Release();
}
STDMETHODIMP_(void) CTipbarWnd::OnSysColorChange()
@@ -4785,10 +5317,10 @@ STDMETHODIMP_(void) CTipbarWnd::OnSysColorChange()
void CTipbarWnd::OnTerminateToolbar()
{
- m_dwTipbarWndFlags |= 0x10000;
+ m_dwTipbarWndFlags |= TIPBAR_TOOLBARENDED;
DestroyOverScreenSizeBalloon();
TerminateAllThreads(TRUE);
- if (!(m_dwTipbarWndFlags & 0x2))
+ if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
SavePosition();
}
@@ -4829,11 +5361,20 @@ STDMETHODIMP_(void) CTipbarWnd::OnUser(HWND hWnd, UINT uMsg,
WPARAM wParam, LPAR
}
}
-/// @unimplemented
STDMETHODIMP_(LRESULT)
CTipbarWnd::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- return 0;
+ if (m_pFocusThread)
+ {
+ for (size_t iItem = 0; iItem < m_pFocusThread->m_UIObjects.size();
++iItem)
+ {
+ CTipbarItem *pItem = m_pFocusThread->m_UIObjects[iItem];
+ if (pItem)
+ pItem->OnUnknown44();
+ }
+ }
+
+ return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
STDMETHODIMP_(LRESULT)
@@ -4880,7 +5421,7 @@ CTipbarWnd::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
STDMETHODIMP_(LRESULT)
CTipbarWnd::OnDisplayChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- if (!(m_dwTipbarWndFlags & 2))
+ if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
{
KillTimer(12);
SetTimer(12, g_uTimerElapseDISPLAYCHANGE);
@@ -4927,9 +5468,25 @@ STDMETHODIMP_(void) CTipbarWnd::OnThemeChanged(HWND hWnd, WPARAM
wParam, LPARAM
CUIFWindow::OnThemeChanged(hWnd, wParam, lParam);
}
-/// @unimplemented
STDMETHODIMP_(void) CTipbarWnd::UpdateUI(LPCRECT prc)
{
+ KillTimer(8);
+
+ if (m_dwChangingThreadId || m_bInCallOn || (m_pFocusThread &&
m_pFocusThread->IsDirtyItem()))
+ {
+ SetTimer(8, g_uTimerElapseUPDATEUI);
+ return;
+ }
+
+ if (m_dwTipbarWndFlags & TIPBAR_UPDATING)
+ {
+ ++m_bInCallOn;
+ Move(m_X, m_Y, m_CX, m_CY);
+ m_dwTipbarWndFlags &= ~TIPBAR_UPDATING;
+ --m_bInCallOn;
+ }
+
+ CUIFWindow::UpdateUI(NULL);
}
/// @unimplemented
@@ -4984,21 +5541,6 @@ HRESULT CTipbarThread::InitItemList()
return E_NOTIMPL;
}
-LONG MyWaitForInputIdle(DWORD dwThreadId, DWORD dwMilliseconds)
-{
- if (g_pTipbarWnd && (g_pTipbarWnd->m_dwShowType & TF_SFT_DESKBAND))
- return 0;
-
- if (TF_IsInMarshaling(dwThreadId))
- return STATUS_TIMEOUT;
-
- DWORD dwFlags1 = 0, dwFlags2 = 0;
- if (!TF_GetThreadFlags(dwThreadId, &dwFlags1, &dwFlags2, NULL) &&
dwFlags2)
- return -1;
-
- return TF_CheckThreadInputIdle(dwThreadId, dwMilliseconds);
-}
-
HRESULT CTipbarThread::_UninitItemList(BOOL bUnAdvise)
{
for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
@@ -5175,7 +5717,7 @@ BOOL CTipbarThread::IsVertical()
{
if (!m_pTipbarWnd)
return FALSE;
- return !!(m_pTipbarWnd->m_dwTipbarWndFlags & 0x20000000);
+ return !!(m_pTipbarWnd->m_dwTipbarWndFlags & TIPBAR_VERTICAL);
}
/// @unimplemented
@@ -5522,7 +6064,7 @@ BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand
*pDeskBand)
g_pTipbarWnd->ShowFloating(dwStatus);
if (!bParent && (dwOldStatus & TF_SFT_DESKBAND))
- g_pTipbarWnd->m_dwTipbarWndFlags |= 0x4000;
+ g_pTipbarWnd->m_dwTipbarWndFlags |= TIPBAR_NODESKBAND;
g_hwndParent = hWnd;
return TRUE;
@@ -5531,13 +6073,13 @@ BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand
*pDeskBand)
/***********************************************************************
* GetLibTls (MSUTB.@)
*
- * @unimplemented
+ * @implemented
*/
-EXTERN_C LPVOID WINAPI
+EXTERN_C PLIBTHREAD WINAPI
GetLibTls(VOID)
{
- FIXME("stub:()\n");
- return NULL;
+ TRACE("()\n");
+ return &g_libTLS;
}
/***********************************************************************
diff --git a/sdk/include/reactos/cicero/cicutb.h b/sdk/include/reactos/cicero/cicutb.h
index 774be036cb4..abda6e7baff 100644
--- a/sdk/include/reactos/cicero/cicutb.h
+++ b/sdk/include/reactos/cicero/cicutb.h
@@ -18,7 +18,13 @@ DEFINE_GUID(IID_ITfLangBarEventSink_P, 0x7A460360, 0xDA21,
0x4B09, 0xA8,
DEFINE_GUID(CLSID_MSUTBDeskBand, 0x540D8A8B, 0x1C3F, 0x4E32, 0x81, 0x32,
0x53, 0x0F, 0x6A, 0x50, 0x20, 0x90);
DEFINE_GUID(CATID_DeskBand, 0x00021492, 0x0000, 0x0000, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
-EXTERN_C LPVOID WINAPI GetLibTls(VOID);
+typedef struct LIBTHREAD
+{
+ IUnknown *m_pUnknown1;
+ ITfDisplayAttributeMgr *m_pDisplayAttrMgr;
+} LIBTHREAD, *PLIBTHREAD;
+
+EXTERN_C PLIBTHREAD WINAPI GetLibTls(VOID);
EXTERN_C BOOL WINAPI GetPopupTipbar(HWND hWnd, BOOL fWinLogon);
EXTERN_C HRESULT WINAPI SetRegisterLangBand(BOOL bRegister);
EXTERN_C VOID WINAPI ClosePopupTipbar(VOID);