xref: /reactos/dll/win32/msutb/msutb.cpp (revision 152af475)
1 /*
2  * PROJECT:     ReactOS msutb.dll
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Language Bar (Tipbar)
5  * COPYRIGHT:   Copyright 2023-2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include "precomp.h"
9 
10 WINE_DEFAULT_DEBUG_CHANNEL(msutb);
11 
12 HINSTANCE g_hInst = NULL;
13 UINT g_wmTaskbarCreated = 0;
14 UINT g_uACP = CP_ACP;
15 DWORD g_dwOSInfo = 0;
16 CRITICAL_SECTION g_cs;
17 LONG g_DllRefCount = 0;
18 BOOL g_bWinLogon = FALSE;
19 BOOL g_fInClosePopupTipbar = FALSE;
20 HWND g_hwndParent = NULL;
21 
22 BOOL g_bShowTipbar = TRUE;
23 BOOL g_bShowDebugMenu = FALSE;
24 BOOL g_bNewLook = TRUE;
25 BOOL g_bIntelliSense = FALSE;
26 BOOL g_bShowCloseMenu = FALSE;
27 UINT g_uTimeOutNonIntentional = 60 * 1000;
28 UINT g_uTimeOutIntentional = 10 * 60 * 1000;
29 UINT g_uTimeOutMax = 60 * 60 * 1000;
30 BOOL g_bShowMinimizedBalloon = TRUE;
31 POINT g_ptTipbar = { -1, -1 };
32 BOOL g_bExcludeCaptionButtons = TRUE;
33 BOOL g_bShowShadow = FALSE;
34 BOOL g_fTaskbarTheme = TRUE;
35 BOOL g_fVertical = FALSE;
36 UINT g_uTimerElapseSTUBSTART = 100;
37 UINT g_uTimerElapseSTUBEND = 2 * 1000;
38 UINT g_uTimerElapseBACKTOALPHA = 3 * 1000;
39 UINT g_uTimerElapseONTHREADITEMCHANGE = 200;
40 UINT g_uTimerElapseSETWINDOWPOS = 100;
41 UINT g_uTimerElapseONUPDATECALLED = 50;
42 UINT g_uTimerElapseSYSCOLORCHANGED = 20;
43 UINT g_uTimerElapseDISPLAYCHANGE = 20;
44 UINT g_uTimerElapseUPDATEUI = 70;
45 UINT g_uTimerElapseSHOWWINDOW = 50;
46 UINT g_uTimerElapseMOVETOTRAY = 50;
47 UINT g_uTimerElapseTRAYWNDONDELAYMSG = 50;
48 UINT g_uTimerElapseDOACCDEFAULTACTION = 200;
49 UINT g_uTimerElapseENSUREFOCUS = 50;
50 BOOL g_bShowDeskBand = FALSE;
51 UINT g_uTimerElapseSHOWDESKBAND = 3 * 1000;
52 BOOL g_fPolicyDisableCloseButton = FALSE;
53 BOOL g_fPolicyEnableLanguagebarInFullscreen = FALSE;
54 DWORD g_dwWndStyle = 0;
55 DWORD g_dwMenuStyle = 0;
56 DWORD g_dwChildWndStyle = 0;
57 BOOL g_fRTL = FALSE;
58 
59 #define TIMER_ID_DOACCDEFAULTACTION 11
60 
61 EXTERN_C void __cxa_pure_virtual(void)
62 {
63     ERR("__cxa_pure_virtual\n");
64 }
65 
66 class CMsUtbModule : public CComModule
67 {
68 };
69 
70 BEGIN_OBJECT_MAP(ObjectMap)
71     //OBJECT_ENTRY(CLSID_MSUTBDeskBand, CDeskBand) // FIXME: Implement this
72 END_OBJECT_MAP()
73 
74 CMsUtbModule gModule;
75 
76 class CCicLibMenuItem;
77 class CTipbarAccItem;
78 class CUTBMenuItem;
79 class CMainIconItem;
80 class CTrayIconItem;
81 class CTipbarWnd;
82 class CButtonIconItem;
83 class CTrayIconWnd;
84 
85 CTipbarWnd *g_pTipbarWnd = NULL;
86 CTrayIconWnd *g_pTrayIconWnd = NULL;
87 
88 CicArray<HKL> *g_prghklSkipRedrawing = NULL;
89 
90 BOOL IsSkipRedrawHKL(HKL hSkipKL)
91 {
92     if (LOWORD(hSkipKL) == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT))
93         return FALSE; // Japanese HKL will be skipped
94     if (!g_prghklSkipRedrawing)
95         return FALSE;
96 
97     for (size_t iItem = 0; iItem < g_prghklSkipRedrawing->size(); ++iItem)
98     {
99         if ((*g_prghklSkipRedrawing)[iItem] == hSkipKL)
100             return TRUE; // To be skipped
101     }
102 
103     return FALSE; // To be not skipped
104 }
105 
106 BOOL IsBiDiLocalizedSystem(void)
107 {
108     LOCALESIGNATURE Sig;
109     LANGID LangID = ::GetUserDefaultUILanguage();
110     if (!LangID)
111         return FALSE;
112 
113     INT size = sizeof(Sig) / sizeof(WCHAR);
114     if (!::GetLocaleInfoW(LangID, LOCALE_FONTSIGNATURE, (LPWSTR)&Sig, size))
115         return FALSE;
116     return (Sig.lsUsb[3] & 0x8000000) != 0;
117 }
118 
119 BOOL GetFontSig(HWND hWnd, HKL hKL)
120 {
121     LOCALESIGNATURE Sig;
122     INT size = sizeof(Sig) / sizeof(WCHAR);
123     if (!::GetLocaleInfoW(LOWORD(hKL), LOCALE_FONTSIGNATURE, (LPWSTR)&Sig, size))
124         return FALSE;
125 
126     HDC hDC = ::GetDC(hWnd);
127     DWORD CharSet = ::GetTextCharsetInfo(hDC, NULL, 0);
128     CHARSETINFO CharSetInfo;
129     ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)CharSet, &CharSetInfo, TCI_SRCCHARSET);
130     ::ReleaseDC(hWnd, hDC);
131 
132     return !!(CharSetInfo.fs.fsCsb[0] & Sig.lsCsbSupported[0]);
133 }
134 
135 void InitSkipRedrawHKLArray(void)
136 {
137     g_prghklSkipRedrawing = new(cicNoThrow) CicArray<HKL>();
138     if (!g_prghklSkipRedrawing)
139         return;
140 
141     g_prghklSkipRedrawing->Add((HKL)UlongToHandle(0xE0010411)); // Japanese IME will be skipped
142 
143     CicRegKey regKey;
144     LSTATUS error = regKey.Open(HKEY_LOCAL_MACHINE,
145                                 TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\SkipRedrawHKL"));
146     if (error != ERROR_SUCCESS)
147         return;
148 
149     TCHAR szValueName[256];
150     for (DWORD dwIndex = 0; ; ++dwIndex)
151     {
152         error = regKey.EnumValue(dwIndex, szValueName, _countof(szValueName));
153         if (error != ERROR_SUCCESS)
154             break;
155 
156         if (szValueName[0] == TEXT('0') &&
157             (szValueName[1] == TEXT('x') || szValueName[1] == TEXT('X')))
158         {
159             HKL hKL = (HKL)UlongToHandle(_tcstoul(szValueName, NULL, 16));
160             g_prghklSkipRedrawing->Add(hKL); // This hKL will be skipped
161         }
162     }
163 }
164 
165 void UninitSkipRedrawHKLArray(void)
166 {
167     if (g_prghklSkipRedrawing)
168     {
169         delete g_prghklSkipRedrawing;
170         g_prghklSkipRedrawing = NULL;
171     }
172 }
173 
174 HRESULT GetGlobalCompartment(REFGUID rguid, ITfCompartment **ppComp)
175 {
176     ITfCompartmentMgr *pCompMgr = NULL;
177     HRESULT hr = TF_GetGlobalCompartment(&pCompMgr);
178     if (FAILED(hr))
179         return hr;
180 
181     if (!pCompMgr)
182         return E_FAIL;
183 
184     hr = pCompMgr->GetCompartment(rguid, ppComp);
185     pCompMgr->Release();
186     return hr;
187 }
188 
189 HRESULT GetGlobalCompartmentDWORD(REFGUID rguid, LPDWORD pdwValue)
190 {
191     *pdwValue = 0;
192     ITfCompartment *pComp;
193     HRESULT hr = GetGlobalCompartment(rguid, &pComp);
194     if (SUCCEEDED(hr))
195     {
196         VARIANT vari;
197         hr = pComp->GetValue(&vari);
198         if (hr == S_OK)
199             *pdwValue = V_I4(&vari);
200         pComp->Release();
201     }
202     return hr;
203 }
204 
205 HRESULT SetGlobalCompartmentDWORD(REFGUID rguid, DWORD dwValue)
206 {
207     VARIANT vari;
208     ITfCompartment *pComp;
209     HRESULT hr = GetGlobalCompartment(rguid, &pComp);
210     if (SUCCEEDED(hr))
211     {
212         V_VT(&vari) = VT_I4;
213         V_I4(&vari) = dwValue;
214         hr = pComp->SetValue(0, &vari);
215         pComp->Release();
216     }
217     return hr;
218 }
219 
220 void TurnOffSpeechIfItsOn(void)
221 {
222     DWORD dwValue = 0;
223     HRESULT hr = GetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, &dwValue);
224     if (SUCCEEDED(hr) && dwValue)
225         SetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0);
226 }
227 
228 void DoCloseLangbar(void)
229 {
230     ITfLangBarMgr *pLangBarMgr = NULL;
231     HRESULT hr = TF_CreateLangBarMgr(&pLangBarMgr);
232     if (FAILED(hr))
233         return;
234 
235     if (pLangBarMgr)
236     {
237         hr = pLangBarMgr->ShowFloating(TF_SFT_HIDDEN);
238         pLangBarMgr->Release();
239     }
240 
241     if (SUCCEEDED(hr))
242         TurnOffSpeechIfItsOn();
243 
244     CicRegKey regKey;
245     LSTATUS error = regKey.Open(HKEY_CURRENT_USER,
246                                 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
247                                 KEY_ALL_ACCESS);
248     if (error == ERROR_SUCCESS)
249         ::RegDeleteValue(regKey, TEXT("ctfmon.exe"));
250 }
251 
252 INT GetIconIndexFromhKL(_In_ HKL hKL)
253 {
254     HKL hGotKL;
255 
256     INT iKL, cKLs = TF_MlngInfoCount();
257     for (iKL = 0; iKL < cKLs; ++iKL)
258     {
259         if (TF_GetMlngHKL(iKL, &hGotKL, NULL, 0) && hKL == hGotKL)
260             return TF_GetMlngIconIndex(iKL);
261     }
262 
263     if (!TF_GetMlngHKL(0, &hGotKL, NULL, 0))
264         return -1;
265 
266     return TF_GetMlngIconIndex(0);
267 }
268 
269 BOOL GethKLDesc(_In_ HKL hKL, _Out_ LPWSTR pszDesc, _In_ UINT cchDesc)
270 {
271     HKL hGotKL;
272 
273     INT iKL, cKLs = TF_MlngInfoCount();
274     for (iKL = 0; iKL < cKLs; ++iKL)
275     {
276         if (TF_GetMlngHKL(iKL, &hGotKL, pszDesc, cchDesc) && hKL == hGotKL)
277             return TRUE;
278     }
279 
280     return TF_GetMlngHKL(0, &hGotKL, pszDesc, cchDesc);
281 }
282 
283 HRESULT
284 LangBarInsertMenu(
285     _In_ ITfMenu *pMenu,
286     _In_ UINT uId,
287     _In_ LPCWSTR pszText,
288     _In_ BOOL bChecked,
289     _Inout_opt_ HICON hIcon)
290 {
291     HBITMAP hbmp = NULL, hbmpMask = NULL;
292     if (hIcon)
293     {
294         HICON hIconNew = (HICON)::CopyImage(hIcon, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE);
295         SIZE iconSize = { 16, 16 };
296         if (!hIconNew)
297             hIconNew = hIcon;
298         if (!cicGetIconBitmaps(hIconNew, &hbmp, &hbmpMask, &iconSize))
299             return E_FAIL;
300         if (hIconNew)
301             ::DestroyIcon(hIconNew);
302         ::DestroyIcon(hIcon);
303     }
304 
305     INT cchText = lstrlenW(pszText);
306     DWORD dwFlags = (bChecked ? TF_LBMENUF_CHECKED : 0);
307     return pMenu->AddMenuItem(uId, dwFlags, hbmp, hbmpMask, pszText, cchText, NULL);
308 }
309 
310 HRESULT LangBarInsertSeparator(_In_ ITfMenu *pMenu)
311 {
312     return pMenu->AddMenuItem(-1, TF_LBMENUF_SEPARATOR, NULL, NULL, NULL, 0, NULL);
313 }
314 
315 // Is it a Far-East language ID?
316 BOOL IsFELangId(LANGID LangID)
317 {
318     switch (LangID)
319     {
320         case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): // Chinese (Simplified)
321         case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): // Chinese (Traditional)
322         case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): // Japanese
323         case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT): // Korean
324             return TRUE;
325         default:
326             return FALSE;
327     }
328 }
329 
330 BOOL CheckCloseMenuAvailable(void)
331 {
332     BOOL ret = FALSE;
333     ITfInputProcessorProfiles *pProfiles = NULL;
334     LANGID *pLangIds = NULL;
335     ULONG iItem, cItems;
336 
337     if (g_fPolicyDisableCloseButton)
338         return FALSE;
339 
340     if (g_bShowCloseMenu)
341         return TRUE;
342 
343     if (SUCCEEDED(TF_CreateInputProcessorProfiles(&pProfiles)) &&
344         SUCCEEDED(pProfiles->GetLanguageList(&pLangIds, &cItems)))
345     {
346         for (iItem = 0; iItem < cItems; ++iItem)
347         {
348             if (IsFELangId(pLangIds[iItem]))
349                 break;
350         }
351 
352         ret = (iItem == cItems);
353     }
354 
355     if (pLangIds)
356         CoTaskMemFree(pLangIds);
357     if (pProfiles)
358         pProfiles->Release();
359 
360     return ret;
361 }
362 
363 /// @unimplemented
364 BOOL IsTransparecyAvailable(void)
365 {
366     return FALSE;
367 }
368 
369 static INT CALLBACK
370 FindEAEnumFontProc(ENUMLOGFONT *pLF, NEWTEXTMETRIC *pTM, INT nFontType, LPARAM lParam)
371 {
372     if ((nFontType != TRUETYPE_FONTTYPE) || (pLF->elfLogFont.lfFaceName[0] != '@'))
373         return TRUE;
374     *(BOOL*)lParam = TRUE;
375     return FALSE;
376 }
377 
378 /// Are there East-Asian vertical fonts?
379 BOOL CheckEAFonts(void)
380 {
381     BOOL bHasVertical = FALSE;
382     HDC hDC = ::GetDC(NULL);
383     ::EnumFonts(hDC, NULL, (FONTENUMPROC)FindEAEnumFontProc, (LPARAM)&bHasVertical);
384     ::ReleaseDC(NULL, hDC);
385     return bHasVertical;
386 }
387 
388 BOOL IsDeskBandFromReg()
389 {
390     if (!(g_dwOSInfo & CIC_OSINFO_XPPLUS)) // Desk band is for XP+
391         return FALSE;
392 
393     CicRegKey regKey;
394     if (regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\")))
395     {
396         DWORD dwValue = 0;
397         regKey.QueryDword(TEXT("ShowDeskBand"), &dwValue);
398         return !!dwValue;
399     }
400 
401     return FALSE;
402 }
403 
404 void SetDeskBandToReg(BOOL bShow)
405 {
406     CicRegKey regKey;
407     if (regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"), KEY_ALL_ACCESS))
408         regKey.SetDword(TEXT("ShowDeskBand"), bShow);
409 }
410 
411 BOOL RegisterComCat(REFCLSID rclsid, REFCATID rcatid, BOOL bRegister)
412 {
413     if (FAILED(::CoInitialize(NULL)))
414         return FALSE;
415 
416     ICatRegister *pCat;
417     HRESULT hr = ::CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER,
418                                     IID_ICatRegister, (void**)&pCat);
419     if (SUCCEEDED(hr))
420     {
421         if (bRegister)
422             hr = pCat->RegisterClassImplCategories(rclsid, 1, const_cast<CATID*>(&rcatid));
423         else
424             hr = pCat->UnRegisterClassImplCategories(rclsid, 1, const_cast<CATID*>(&rcatid));
425 
426         pCat->Release();
427     }
428 
429     ::CoUninitialize();
430 
431     //if (IsIE5())
432     //    ::RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Component Categories\\{00021492-0000-0000-C000-000000000046}\\Enum"));
433 
434     return SUCCEEDED(hr);
435 }
436 
437 BOOL InitFromReg(void)
438 {
439     DWORD dwValue;
440     LSTATUS error;
441 
442     CicRegKey regKey1;
443     error = regKey1.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\"));
444     if (error == ERROR_SUCCESS)
445     {
446         error = regKey1.QueryDword(TEXT("ShowTipbar"), &dwValue);
447         if (error == ERROR_SUCCESS)
448             g_bShowTipbar = !!dwValue;
449     }
450 
451     CicRegKey regKey2;
452     error = regKey2.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
453     if (error == ERROR_SUCCESS)
454     {
455         error = regKey2.QueryDword(TEXT("ShowDebugMenu"), &dwValue);
456         if (error == ERROR_SUCCESS)
457             g_bShowDebugMenu = !!dwValue;
458         error = regKey2.QueryDword(TEXT("NewLook"), &dwValue);
459         if (error == ERROR_SUCCESS)
460             g_bNewLook = !!dwValue;
461         error = regKey2.QueryDword(TEXT("IntelliSense"), &dwValue);
462         if (error == ERROR_SUCCESS)
463             g_bIntelliSense = !!dwValue;
464         error = regKey2.QueryDword(TEXT("ShowCloseMenu"), &dwValue);
465         if (error == ERROR_SUCCESS)
466             g_bShowCloseMenu = !!dwValue;
467         error = regKey2.QueryDword(TEXT("TimeOutNonIntentional"), &dwValue);
468         if (error == ERROR_SUCCESS)
469             g_uTimeOutNonIntentional = 1000 * dwValue;
470         error = regKey2.QueryDword(TEXT("TimeOutIntentional"), &dwValue);
471         if (error == ERROR_SUCCESS)
472         {
473             g_uTimeOutIntentional = 1000 * dwValue;
474             g_uTimeOutMax = 6000 * dwValue;
475         }
476         error = regKey2.QueryDword(TEXT("ShowMinimizedBalloon"), &dwValue);
477         if (error == ERROR_SUCCESS)
478             g_bShowMinimizedBalloon = !!dwValue;
479         error = regKey2.QueryDword(TEXT("Left"), &dwValue);
480         if (error == ERROR_SUCCESS)
481             g_ptTipbar.x = dwValue;
482         error = regKey2.QueryDword(TEXT("Top"), &dwValue);
483         if (error == ERROR_SUCCESS)
484             g_ptTipbar.y = dwValue;
485         error = regKey2.QueryDword(TEXT("ExcludeCaptionButtons"), &dwValue);
486         if (error == ERROR_SUCCESS)
487             g_bExcludeCaptionButtons = !!dwValue;
488         error = regKey2.QueryDword(TEXT("ShowShadow"), &dwValue);
489         if (error == ERROR_SUCCESS)
490             g_bShowShadow = !!dwValue;
491         error = regKey2.QueryDword(TEXT("TaskbarTheme"), &dwValue);
492         if (error == ERROR_SUCCESS)
493             g_fTaskbarTheme = !!dwValue;
494         error = regKey2.QueryDword(TEXT("Vertical"), &dwValue);
495         if (error == ERROR_SUCCESS)
496             g_fVertical = !!dwValue;
497         error = regKey2.QueryDword(TEXT("TimerElapseSTUBSTART"), &dwValue);
498         if (error == ERROR_SUCCESS)
499             g_uTimerElapseSTUBSTART = dwValue;
500         error = regKey2.QueryDword(TEXT("TimerElapseSTUBEND"), &dwValue);
501         if (error == ERROR_SUCCESS)
502             g_uTimerElapseSTUBEND = dwValue;
503         error = regKey2.QueryDword(TEXT("TimerElapseBACKTOALPHA"), &dwValue);
504         if (error == ERROR_SUCCESS)
505             g_uTimerElapseBACKTOALPHA = dwValue;
506         error = regKey2.QueryDword(TEXT("TimerElapseONTHREADITEMCHANGE"), &dwValue);
507         if (error == ERROR_SUCCESS)
508             g_uTimerElapseONTHREADITEMCHANGE = dwValue;
509         error = regKey2.QueryDword(TEXT("TimerElapseSETWINDOWPOS"), &dwValue);
510         if (error == ERROR_SUCCESS)
511             g_uTimerElapseSETWINDOWPOS = dwValue;
512         error = regKey2.QueryDword(TEXT("TimerElapseONUPDATECALLED"), &dwValue);
513         if (error == ERROR_SUCCESS)
514             g_uTimerElapseONUPDATECALLED = dwValue;
515         error = regKey2.QueryDword(TEXT("TimerElapseSYSCOLORCHANGED"), &dwValue);
516         if (error == ERROR_SUCCESS)
517             g_uTimerElapseSYSCOLORCHANGED = dwValue;
518         error = regKey2.QueryDword(TEXT("TimerElapseDISPLAYCHANGE"), &dwValue);
519         if (error == ERROR_SUCCESS)
520             g_uTimerElapseDISPLAYCHANGE = dwValue;
521         error = regKey2.QueryDword(TEXT("TimerElapseUPDATEUI"), &dwValue);
522         if (error == ERROR_SUCCESS)
523             g_uTimerElapseUPDATEUI = dwValue;
524         error = regKey2.QueryDword(TEXT("TimerElapseSHOWWINDOW"), &dwValue);
525         if (error == ERROR_SUCCESS)
526             g_uTimerElapseSHOWWINDOW = dwValue;
527         error = regKey2.QueryDword(TEXT("TimerElapseMOVETOTRAY"), &dwValue);
528         if (error == ERROR_SUCCESS)
529             g_uTimerElapseMOVETOTRAY = dwValue;
530         error = regKey2.QueryDword(TEXT("TimerElapseTRAYWNDONDELAYMSG"), &dwValue);
531         if (error == ERROR_SUCCESS)
532             g_uTimerElapseTRAYWNDONDELAYMSG = dwValue;
533         error = regKey2.QueryDword(TEXT("TimerElapseDOACCDEFAULTACTION"), &dwValue);
534         if (error == ERROR_SUCCESS)
535             g_uTimerElapseDOACCDEFAULTACTION = dwValue;
536         error = regKey2.QueryDword(TEXT("TimerElapseENSUREFOCUS"), &dwValue);
537         if (error == ERROR_SUCCESS)
538             g_uTimerElapseENSUREFOCUS = dwValue;
539         error = regKey2.QueryDword(TEXT("ShowDeskBand"), &dwValue);
540         if (error == ERROR_SUCCESS)
541             g_bShowDeskBand = !!dwValue;
542         error = regKey2.QueryDword(TEXT("TimerElapseSHOWWDESKBAND"), &dwValue);
543         if (error == ERROR_SUCCESS)
544             g_uTimerElapseSHOWDESKBAND = dwValue;
545     }
546 
547     CicRegKey regKey3;
548     error = regKey3.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Policies\\Microsoft\\MSCTF"));
549     if (error == ERROR_SUCCESS)
550     {
551         error = regKey3.QueryDword(TEXT("DisableCloseButton"), &dwValue);
552         if (error == ERROR_SUCCESS)
553             g_fPolicyDisableCloseButton = !!dwValue;
554     }
555 
556     CicRegKey regKey4;
557     error = regKey4.Open(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Policies\\Microsoft\\MSCTF"));
558     if (error == ERROR_SUCCESS)
559     {
560         error = regKey4.QueryDword(TEXT("EnableLanguagebarInFullscreen"), &dwValue);
561         if (error == ERROR_SUCCESS)
562             g_fPolicyEnableLanguagebarInFullscreen = !!dwValue;
563     }
564 
565     InitSkipRedrawHKLArray();
566 
567     if (g_bNewLook)
568     {
569         g_dwWndStyle = UIF_WINDOW_ENABLETHEMED | UIF_WINDOW_WORKAREA | UIF_WINDOW_TOOLTIP |
570                        UIF_WINDOW_TOOLWINDOW | UIF_WINDOW_TOPMOST;
571         if (g_bShowShadow)
572             g_dwWndStyle |= UIF_WINDOW_SHADOW;
573         g_dwMenuStyle = 0x10000000 | UIF_WINDOW_MONITOR | UIF_WINDOW_SHADOW |
574                         UIF_WINDOW_TOOLWINDOW | UIF_WINDOW_TOPMOST;
575     }
576     else
577     {
578         g_dwWndStyle = UIF_WINDOW_WORKAREA | UIF_WINDOW_TOOLTIP | UIF_WINDOW_DLGFRAME |
579                        UIF_WINDOW_TOPMOST;
580         g_dwMenuStyle = UIF_WINDOW_MONITOR | UIF_WINDOW_DLGFRAME | UIF_WINDOW_TOPMOST;
581     }
582 
583     g_dwChildWndStyle =
584         UIF_WINDOW_ENABLETHEMED | UIF_WINDOW_NOMOUSEMSG | UIF_WINDOW_TOOLTIP | UIF_WINDOW_CHILD;
585 
586     if (IsBiDiLocalizedSystem())
587     {
588         g_dwWndStyle |= UIF_WINDOW_LAYOUTRTL;
589         g_dwChildWndStyle |= UIF_WINDOW_LAYOUTRTL;
590         g_dwMenuStyle |= UIF_WINDOW_LAYOUTRTL;
591         g_fRTL = TRUE;
592     }
593 
594     return TRUE;
595 }
596 
597 /***********************************************************************/
598 
599 struct CShellWndThread
600 {
601     HWND m_hTrayWnd = NULL;
602     HWND m_hProgmanWnd = NULL;
603 
604     HWND GetWndTray()
605     {
606         if (!m_hTrayWnd || !::IsWindow(m_hTrayWnd))
607             m_hTrayWnd = ::FindWindowW(L"Shell_TrayWnd", NULL);
608         return m_hTrayWnd;
609     }
610 
611     HWND GetWndProgman()
612     {
613         if (!m_hProgmanWnd || !::IsWindow(m_hProgmanWnd))
614             m_hProgmanWnd = ::FindWindowW(L"Progman", NULL);
615         return m_hProgmanWnd;
616     }
617 
618     void clear()
619     {
620         m_hTrayWnd = m_hProgmanWnd = NULL;
621     }
622 };
623 
624 /***********************************************************************/
625 
626 class CUTBLangBarDlg
627 {
628 protected:
629     LPTSTR m_pszDialogName;
630     LONG m_cRefs;
631 
632 public:
633     CUTBLangBarDlg() { }
634     virtual ~CUTBLangBarDlg() { }
635 
636     static CUTBLangBarDlg *GetThis(HWND hDlg);
637     static void SetThis(HWND hDlg, CUTBLangBarDlg *pThis);
638     static DWORD WINAPI s_ThreadProc(LPVOID pParam);
639     static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
640 
641     BOOL StartThread();
642     LONG _Release();
643 
644     STDMETHOD_(BOOL, DoModal)(HWND hDlg) = 0;
645     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) = 0;
646     STDMETHOD_(BOOL, IsDlgShown)() = 0;
647     STDMETHOD_(void, SetDlgShown)(BOOL bShown) = 0;
648     STDMETHOD_(BOOL, ThreadProc)();
649 };
650 
651 /***********************************************************************/
652 
653 class CUTBCloseLangBarDlg : public CUTBLangBarDlg
654 {
655 public:
656     CUTBCloseLangBarDlg();
657 
658     static BOOL s_bIsDlgShown;
659 
660     STDMETHOD_(BOOL, DoModal)(HWND hDlg) override;
661     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) override;
662     STDMETHOD_(BOOL, IsDlgShown)() override;
663     STDMETHOD_(void, SetDlgShown)(BOOL bShown) override;
664 };
665 
666 BOOL CUTBCloseLangBarDlg::s_bIsDlgShown = FALSE;
667 
668 /***********************************************************************/
669 
670 class CUTBMinimizeLangBarDlg : public CUTBLangBarDlg
671 {
672 public:
673     CUTBMinimizeLangBarDlg();
674 
675     static BOOL s_bIsDlgShown;
676 
677     STDMETHOD_(BOOL, DoModal)(HWND hDlg) override;
678     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) override;
679     STDMETHOD_(BOOL, IsDlgShown)() override;
680     STDMETHOD_(void, SetDlgShown)(BOOL bShown) override;
681     STDMETHOD_(BOOL, ThreadProc)() override;
682 };
683 
684 BOOL CUTBMinimizeLangBarDlg::s_bIsDlgShown = FALSE;
685 
686 /***********************************************************************/
687 
688 class CCicLibMenu : public ITfMenu
689 {
690 protected:
691     CicArray<CCicLibMenuItem*> m_MenuItems;
692     LONG m_cRefs;
693 
694 public:
695     CCicLibMenu();
696     virtual ~CCicLibMenu();
697 
698     STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj) override;
699     STDMETHOD_(ULONG, AddRef)() override;
700     STDMETHOD_(ULONG, Release)() override;
701     STDMETHOD(AddMenuItem)(
702         UINT uId,
703         DWORD dwFlags,
704         HBITMAP hbmp,
705         HBITMAP hbmpMask,
706         const WCHAR *pch,
707         ULONG cch,
708         ITfMenu **ppSubMenu) override;
709     STDMETHOD_(CCicLibMenu*, CreateSubMenu)();
710     STDMETHOD_(CCicLibMenuItem*, CreateMenuItem)();
711 };
712 
713 /***********************************************************************/
714 
715 class CCicLibMenuItem
716 {
717 protected:
718     DWORD m_uId;
719     DWORD m_dwFlags;
720     HBITMAP m_hbmp;
721     HBITMAP m_hbmpMask;
722     BSTR m_bstrText;
723     ITfMenu *m_pMenu;
724 
725 public:
726     CCicLibMenuItem();
727     virtual ~CCicLibMenuItem();
728 
729     BOOL Init(
730         UINT uId,
731         DWORD dwFlags,
732         HBITMAP hbmp,
733         HBITMAP hbmpMask,
734         const WCHAR *pch,
735         ULONG cch,
736         ITfMenu *pMenu);
737     HBITMAP CreateBitmap(HANDLE hBitmap);
738 };
739 
740 /***********************************************************************/
741 
742 class CTipbarAccessible : public IAccessible
743 {
744 protected:
745     LONG m_cRefs;
746     HWND m_hWnd;
747     IAccessible *m_pStdAccessible;
748     ITypeInfo *m_pTypeInfo;
749     BOOL m_bInitialized;
750     CicArray<CTipbarAccItem*> m_AccItems;
751     LONG m_cSelection;
752     friend class CUTBMenuWnd;
753     friend class CTipbarWnd;
754 
755 public:
756     CTipbarAccessible(CTipbarAccItem *pItem);
757     virtual ~CTipbarAccessible();
758 
759     HRESULT Initialize();
760 
761     BOOL AddAccItem(CTipbarAccItem *pItem);
762     HRESULT RemoveAccItem(CTipbarAccItem *pItem);
763     void ClearAccItems();
764     CTipbarAccItem *AccItemFromID(INT iItem);
765     INT GetIDOfItem(CTipbarAccItem *pTarget);
766 
767     LONG_PTR CreateRefToAccObj(WPARAM wParam);
768     BOOL DoDefaultActionReal(INT nID);
769     void NotifyWinEvent(DWORD event, CTipbarAccItem *pItem);
770     void SetWindow(HWND hWnd);
771 
772     // IUnknown methods
773     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
774     STDMETHOD_(ULONG, AddRef)();
775     STDMETHOD_(ULONG, Release)();
776 
777     // IDispatch methods
778     STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
779     STDMETHOD(GetTypeInfo)(
780         UINT iTInfo,
781         LCID lcid,
782         ITypeInfo **ppTInfo);
783     STDMETHOD(GetIDsOfNames)(
784         REFIID riid,
785         LPOLESTR *rgszNames,
786         UINT cNames,
787         LCID lcid,
788         DISPID *rgDispId);
789     STDMETHOD(Invoke)(
790         DISPID dispIdMember,
791         REFIID riid,
792         LCID lcid,
793         WORD wFlags,
794         DISPPARAMS *pDispParams,
795         VARIANT *pVarResult,
796         EXCEPINFO *pExcepInfo,
797         UINT *puArgErr);
798 
799     // IAccessible methods
800     STDMETHOD(get_accParent)(IDispatch **ppdispParent);
801     STDMETHOD(get_accChildCount)(LONG *pcountChildren);
802     STDMETHOD(get_accChild)(VARIANT varChildID, IDispatch **ppdispChild);
803     STDMETHOD(get_accName)(VARIANT varID, BSTR *pszName);
804     STDMETHOD(get_accValue)(VARIANT varID, BSTR *pszValue);
805     STDMETHOD(get_accDescription)(VARIANT varID, BSTR *description);
806     STDMETHOD(get_accRole)(VARIANT varID, VARIANT *role);
807     STDMETHOD(get_accState)(VARIANT varID, VARIANT *state);
808     STDMETHOD(get_accHelp)(VARIANT varID, BSTR *help);
809     STDMETHOD(get_accHelpTopic)(BSTR *helpfile, VARIANT varID, LONG *pidTopic);
810     STDMETHOD(get_accKeyboardShortcut)(VARIANT varID, BSTR *shortcut);
811     STDMETHOD(get_accFocus)(VARIANT *pvarID);
812     STDMETHOD(get_accSelection)(VARIANT *pvarID);
813     STDMETHOD(get_accDefaultAction)(VARIANT varID, BSTR *action);
814     STDMETHOD(accSelect)(LONG flagsSelect, VARIANT varID);
815     STDMETHOD(accLocation)(
816         LONG *left,
817         LONG *top,
818         LONG *width,
819         LONG *height,
820         VARIANT varID);
821     STDMETHOD(accNavigate)(LONG dir, VARIANT varStart, VARIANT *pvarEnd);
822     STDMETHOD(accHitTest)(LONG left, LONG top, VARIANT *pvarID);
823     STDMETHOD(accDoDefaultAction)(VARIANT varID);
824     STDMETHOD(put_accName)(VARIANT varID, BSTR name);
825     STDMETHOD(put_accValue)(VARIANT varID, BSTR value);
826 };
827 
828 /***********************************************************************/
829 
830 class CTipbarAccItem
831 {
832 public:
833     CTipbarAccItem() { }
834     virtual ~CTipbarAccItem() { }
835 
836     STDMETHOD_(BSTR, GetAccName)()
837     {
838         return SysAllocString(L"");
839     }
840     STDMETHOD_(BSTR, GetAccValue)()
841     {
842         return NULL;
843     }
844     STDMETHOD_(INT, GetAccRole)()
845     {
846         return 10;
847     }
848     STDMETHOD_(INT, GetAccState)()
849     {
850         return 256;
851     }
852     STDMETHOD_(void, GetAccLocation)(LPRECT lprc)
853     {
854         *lprc = { 0, 0, 0, 0 };
855     }
856     STDMETHOD_(BSTR, GetAccDefaultAction)()
857     {
858         return NULL;
859     }
860     STDMETHOD_(BOOL, DoAccDefaultAction)()
861     {
862         return FALSE;
863     }
864     STDMETHOD_(BOOL, DoAccDefaultActionReal)()
865     {
866         return FALSE;
867     }
868 };
869 
870 /***********************************************************************/
871 
872 class CTipbarCoInitialize
873 {
874 public:
875     BOOL m_bCoInit;
876 
877     CTipbarCoInitialize() : m_bCoInit(FALSE) { }
878     ~CTipbarCoInitialize() { CoUninit(); }
879 
880     HRESULT EnsureCoInit()
881     {
882         if (m_bCoInit)
883             return S_OK;
884         HRESULT hr = ::CoInitialize(NULL);
885         if (FAILED(hr))
886             return hr;
887         m_bCoInit = TRUE;
888         return S_OK;
889     }
890 
891     void CoUninit()
892     {
893         if (m_bCoInit)
894         {
895             ::CoUninitialize();
896             m_bCoInit = FALSE;
897         }
898     }
899 };
900 
901 /***********************************************************************/
902 
903 class CUTBMenuWnd : public CTipbarAccItem, public CUIFMenu
904 {
905 protected:
906     CTipbarCoInitialize m_coInit;
907     CTipbarAccessible *m_pAccessible;
908     UINT m_nMenuWndID;
909     friend class CUTBMenuItem;
910 
911 public:
912     CUTBMenuWnd(HINSTANCE hInst, DWORD style, DWORD dwUnknown14);
913 
914     BOOL StartDoAccDefaultActionTimer(CUTBMenuItem *pTarget);
915 
916     CTipbarAccItem* GetAccItem()
917     {
918         return static_cast<CTipbarAccItem*>(this);
919     }
920     CUIFMenu* GetMenu()
921     {
922         return static_cast<CUIFMenu*>(this);
923     }
924 
925     STDMETHOD_(BSTR, GetAccName)() override;
926     STDMETHOD_(INT, GetAccRole)() override;
927     STDMETHOD_(BOOL, Initialize)() override;
928     STDMETHOD_(void, OnCreate)(HWND hWnd) override;
929     STDMETHOD_(void, OnDestroy)(HWND hWnd) override;
930     STDMETHOD_(HRESULT, OnGetObject)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
931     STDMETHOD_(LRESULT, OnShowWindow)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
932     STDMETHOD_(void, OnTimer)(WPARAM wParam) override;
933 };
934 
935 /***********************************************************************/
936 
937 class CUTBMenuItem : public CTipbarAccItem, public CUIFMenuItem
938 {
939 protected:
940     CUTBMenuWnd *m_pMenuUI;
941     friend class CUTBMenuWnd;
942 
943 public:
944     CUTBMenuItem(CUTBMenuWnd *pMenuUI);
945     ~CUTBMenuItem() override;
946 
947     CUIFMenuItem* GetMenuItem()
948     {
949         return static_cast<CUIFMenuItem*>(this);
950     }
951 
952     STDMETHOD_(BOOL, DoAccDefaultAction)() override;
953     STDMETHOD_(BOOL, DoAccDefaultActionReal)() override;
954     STDMETHOD_(BSTR, GetAccDefaultAction)() override;
955     STDMETHOD_(void, GetAccLocation)(LPRECT lprc) override;
956     STDMETHOD_(BSTR, GetAccName)() override;
957     STDMETHOD_(INT, GetAccRole)() override;
958 };
959 
960 /***********************************************************************/
961 
962 class CModalMenu
963 {
964 public:
965     DWORD m_dwUnknown26;
966     CUTBMenuWnd *m_pMenuUI;
967 
968 public:
969     CModalMenu() { }
970     virtual ~CModalMenu() { }
971 
972     CUTBMenuItem *InsertItem(CUTBMenuWnd *pMenuUI, INT nCommandId, INT nStringID);
973     void PostKey(BOOL bUp, WPARAM wParam, LPARAM lParam);
974     void CancelMenu();
975 };
976 
977 /***********************************************************************/
978 
979 class CTipbarThread;
980 
981 class CUTBContextMenu : public CModalMenu
982 {
983 public:
984     CTipbarWnd *m_pTipbarWnd;
985     CTipbarThread *m_pTipbarThread;
986 
987 public:
988     CUTBContextMenu(CTipbarWnd *pTipbarWnd);
989 
990     BOOL Init();
991     CUTBMenuWnd *CreateMenuUI(BOOL bFlag);
992 
993     UINT ShowPopup(
994         CUIFWindow *pWindow,
995         POINT pt,
996         LPCRECT prc,
997         BOOL bFlag);
998 
999     BOOL SelectMenuItem(UINT nCommandId);
1000 };
1001 
1002 /***********************************************************************/
1003 
1004 class CUTBLBarMenuItem;
1005 
1006 class CUTBLBarMenu : public CCicLibMenu
1007 {
1008 protected:
1009     CUTBMenuWnd *m_pMenuUI;
1010     HINSTANCE m_hInst;
1011 
1012 public:
1013     CUTBLBarMenu(HINSTANCE hInst);
1014     ~CUTBLBarMenu() override;
1015 
1016     CUTBMenuWnd *CreateMenuUI();
1017     INT ShowPopup(CUIFWindow *pWindow, POINT pt, LPCRECT prcExclude);
1018 
1019     STDMETHOD_(CCicLibMenuItem*, CreateMenuItem)() override;
1020     STDMETHOD_(CCicLibMenu*, CreateSubMenu)() override;
1021 };
1022 
1023 /***********************************************************************/
1024 
1025 class CUTBLBarMenuItem : public CCicLibMenuItem
1026 {
1027 public:
1028     CUTBLBarMenu *m_pLBarMenu;
1029 
1030 public:
1031     CUTBLBarMenuItem() { m_pLBarMenu = NULL; }
1032     BOOL InsertToUI(CUTBMenuWnd *pMenuUI);
1033 };
1034 
1035 /***********************************************************************/
1036 
1037 class CTipbarGripper : public CUIFGripper
1038 {
1039 protected:
1040     CTipbarWnd *m_pTipbarWnd;
1041     BOOL m_bInDebugMenu;
1042     friend class CTipbarWnd;
1043 
1044 public:
1045     CTipbarGripper(CTipbarWnd *pTipbarWnd, LPCRECT prc, DWORD style);
1046 
1047     STDMETHOD_(void, OnLButtonUp)(LONG x, LONG y) override;
1048     STDMETHOD_(void, OnRButtonUp)(LONG x, LONG y) override;
1049     STDMETHOD_(BOOL, OnSetCursor)(UINT uMsg, LONG x, LONG y) override;
1050 };
1051 
1052 /***********************************************************************/
1053 
1054 class CTrayIconWnd
1055 {
1056 protected:
1057     DWORD m_dwUnknown20;
1058     BOOL m_bBusy;
1059     UINT m_uCallbackMessage;
1060     UINT m_uMsg;
1061     HWND m_hWnd;
1062     DWORD m_dwUnknown21[2];
1063     HWND m_hTrayWnd;
1064     HWND m_hNotifyWnd;
1065     DWORD m_dwTrayWndThreadId;
1066     DWORD m_dwUnknown22;
1067     HWND m_hwndProgman;
1068     DWORD m_dwProgmanThreadId;
1069     CMainIconItem *m_pMainIconItem;
1070     CicArray<CButtonIconItem*> m_Items;
1071     UINT m_uCallbackMsg;
1072     UINT m_uNotifyIconID;
1073     friend class CTipbarWnd;
1074 
1075     static BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam);
1076     static LRESULT CALLBACK _WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
1077 
1078 public:
1079     CTrayIconWnd();
1080     ~CTrayIconWnd();
1081 
1082     static BOOL RegisterClass();
1083     static CTrayIconWnd *GetThis(HWND hWnd);
1084     static void SetThis(HWND hWnd, LPCREATESTRUCT pCS);
1085 
1086     HWND CreateWnd();
1087     void DestroyWnd();
1088 
1089     BOOL SetMainIcon(HKL hKL);
1090     BOOL SetIcon(REFGUID rguid, DWORD dwUnknown24, HICON hIcon, LPCWSTR psz);
1091 
1092     void RemoveAllIcon(DWORD dwFlags);
1093     void RemoveUnusedIcons(int unknown);
1094 
1095     CButtonIconItem *FindIconItem(REFGUID rguid);
1096     BOOL FindTrayEtc();
1097     HWND GetNotifyWnd();
1098     BOOL OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
1099 
1100     void CallOnDelayMsg();
1101 };
1102 
1103 /***********************************************************************/
1104 
1105 class CTrayIconItem
1106 {
1107 protected:
1108     HWND m_hWnd;
1109     UINT m_uCallbackMessage;
1110     UINT m_uNotifyIconID;
1111     DWORD m_dwIconAddOrModify;
1112     BOOL m_bIconAdded;
1113     CTrayIconWnd *m_pTrayIconWnd;
1114     DWORD m_dwUnknown25;
1115     GUID m_guid;
1116     RECT m_rcMenu;
1117     POINT m_ptCursor;
1118     friend class CTrayIconWnd;
1119 
1120 public:
1121     CTrayIconItem(CTrayIconWnd *pTrayIconWnd);
1122     virtual ~CTrayIconItem() { }
1123 
1124     BOOL _Init(HWND hWnd, UINT uCallbackMessage, UINT uNotifyIconID, const GUID& rguid);
1125     BOOL UpdateMenuRectPoint();
1126     BOOL RemoveIcon();
1127 
1128     STDMETHOD_(BOOL, SetIcon)(HICON hIcon, LPCWSTR pszTip);
1129     STDMETHOD_(BOOL, OnMsg)(WPARAM wParam, LPARAM lParam) { return FALSE; };
1130     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) { return 0; };
1131 };
1132 
1133 /***********************************************************************/
1134 
1135 class CButtonIconItem : public CTrayIconItem
1136 {
1137 protected:
1138     DWORD m_dwUnknown24;
1139     HKL m_hKL;
1140     friend class CTrayIconWnd;
1141 
1142 public:
1143     CButtonIconItem(CTrayIconWnd *pWnd, DWORD dwUnknown24);
1144 
1145     STDMETHOD_(BOOL, OnMsg)(WPARAM wParam, LPARAM lParam) override;
1146     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) override;
1147 };
1148 
1149 /***********************************************************************/
1150 
1151 class CMainIconItem : public CButtonIconItem
1152 {
1153 public:
1154     CMainIconItem(CTrayIconWnd *pWnd);
1155 
1156     BOOL Init(HWND hWnd);
1157     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) override;
1158 };
1159 
1160 /***********************************************************************/
1161 
1162 class CLBarItemBase
1163 {
1164 protected:
1165     DWORD m_dwItemStatus;
1166     TF_LANGBARITEMINFO m_NewUIInfo;
1167     WCHAR m_szToolTipText[256];
1168     LONG m_cRefs;
1169     ITfLangBarItemSink *m_pLangBarItemSink;
1170 
1171 public:
1172     CLBarItemBase();
1173     virtual ~CLBarItemBase();
1174 
1175     HRESULT ShowInternal(BOOL bShow, BOOL bUpdate);
1176 
1177     void InitNuiInfo(
1178         REFIID clsidService,
1179         REFGUID guidItem,
1180         DWORD dwStyle,
1181         DWORD ulSort,
1182         LPCWSTR Source);
1183 
1184     HRESULT GetInfo(TF_LANGBARITEMINFO *pInfo);
1185     HRESULT GetStatus(DWORD *pdwStatus);
1186     HRESULT Show(BOOL fShow);
1187     HRESULT GetTooltipString(BSTR *pbstrToolTip);
1188 
1189     HRESULT AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie);
1190     HRESULT UnadviseSink(DWORD dwCookie);
1191 };
1192 
1193 /***********************************************************************/
1194 
1195 class CLBarItemButtonBase
1196     : public CLBarItemBase
1197     , public ITfLangBarItem
1198     , public ITfLangBarItemButton
1199     , public ITfSource
1200 {
1201 public:
1202     HICON m_hIcon;
1203 
1204 public:
1205     CLBarItemButtonBase() { m_hIcon = NULL; }
1206     ~CLBarItemButtonBase() override;
1207 
1208     // IUnknown methods
1209     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override;
1210     STDMETHOD_(ULONG, AddRef)() override;
1211     STDMETHOD_(ULONG, Release)() override;
1212 
1213     // ITfLangBarItem methods
1214     STDMETHOD(GetInfo)(TF_LANGBARITEMINFO *pInfo) override;
1215     STDMETHOD(GetStatus)(DWORD *pdwStatus) override;
1216     STDMETHOD(Show)(BOOL fShow) override;
1217     STDMETHOD(GetTooltipString)(BSTR *pbstrToolTip) override;
1218 
1219     // ITfLangBarItemButton methods
1220     STDMETHOD(OnClick)(TfLBIClick click, POINT pt, LPCRECT prc) override;
1221     STDMETHOD(InitMenu)(ITfMenu *pMenu) override;
1222     STDMETHOD(OnMenuSelect)(UINT wID) override;
1223     STDMETHOD(GetIcon)(HICON *phIcon) override;
1224     STDMETHOD(GetText)(BSTR *pbstr) override;
1225 
1226     // ITfSource methods
1227     STDMETHOD(AdviseSink)(REFIID riid, IUnknown *punk, DWORD *pdwCookie) override;
1228     STDMETHOD(UnadviseSink)(DWORD dwCookie) override;
1229 };
1230 
1231 /***********************************************************************/
1232 
1233 /// Language Bar international item
1234 class CLBarInatItem : public CLBarItemButtonBase
1235 {
1236 protected:
1237     HKL m_hKL;
1238     DWORD m_dwThreadId;
1239 
1240 public:
1241     CLBarInatItem(DWORD dwThreadId);
1242 
1243     STDMETHOD(InitMenu)(ITfMenu *pMenu) override;
1244     STDMETHOD(OnMenuSelect)(INT nCommandId);
1245     STDMETHOD(GetIcon)(HICON *phIcon) override;
1246     STDMETHOD(GetText)(BSTR *pbstr) override;
1247 };
1248 
1249 /***********************************************************************/
1250 
1251 class CTipbarItem;
1252 class CTipbarThread;
1253 class CTipbarCtrlButtonHolder;
1254 class CDeskBand;
1255 
1256 class CTipbarWnd
1257     : public ITfLangBarEventSink
1258     , public ITfLangBarEventSink_P
1259     , public CTipbarAccItem
1260     , public CUIFWindow
1261 {
1262     CTipbarCoInitialize m_coInit;
1263     DWORD m_dwSinkCookie;
1264     CModalMenu *m_pModalMenu;
1265     CTipbarThread *m_pThread;
1266     CicArray<GUID*> m_TipbarGUIDArray;
1267     DWORD m_dwUnknown20;
1268     CUIFWndFrame *m_pWndFrame;
1269     CTipbarGripper *m_pTipbarGripper;
1270     CTipbarThread *m_pFocusThread;
1271     CicArray<CTipbarThread*> m_Threads;
1272     CicArray<CTipbarThread*> m_ThreadCreatingList;
1273     DWORD m_dwAlphaValue;
1274     DWORD m_dwTipbarWndFlags;
1275     LONG m_ButtonWidth;
1276     DWORD m_dwShowType;
1277     DWORD m_dwUnknown21;
1278     INT m_cxSmallIcon;
1279     INT m_cySmallIcon;
1280     INT m_cxDlgFrameX2;
1281     INT m_cyDlgFrameX2;
1282     HFONT m_hMarlettFont;
1283     HFONT m_hTextFont;
1284     ITfLangBarMgr_P *m_pLangBarMgr;
1285     DWORD m_dwUnknown23;
1286     CTipbarCtrlButtonHolder *m_pTipbarCtrlButtonHolder;
1287     DWORD m_dwUnknown23_1[8];
1288     CUIFWindow *m_pBalloon;
1289     DWORD m_dwChangingThreadId;
1290     LONG m_bInCallOn;
1291     LONG m_X;
1292     LONG m_Y;
1293     LONG m_CX;
1294     LONG m_CY;
1295     CTipbarAccessible *m_pTipbarAccessible;
1296     INT m_nID;
1297     MARGINS m_Margins;
1298     DWORD m_dwUnknown23_5[4];
1299     CTipbarThread *m_pUnknownThread;
1300     CDeskBand *m_pDeskBand;
1301     CShellWndThread m_ShellWndThread;
1302     LONG m_cRefs;
1303     friend class CUTBContextMenu;
1304     friend class CTipbarGripper;
1305     friend VOID WINAPI ClosePopupTipbar(VOID);
1306     friend BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand *pDeskBand);
1307 
1308 public:
1309     CTipbarWnd(DWORD style);
1310     ~CTipbarWnd() override;
1311 
1312     CUIFWindow *GetWindow()
1313     {
1314         return static_cast<CUIFWindow*>(this);
1315     }
1316 
1317     CTipbarAccItem *GetAccItem()
1318     {
1319         return static_cast<CTipbarAccItem*>(this);
1320     }
1321 
1322     void Init(BOOL bChild, CDeskBand *pDeskBand);
1323     void InitHighContrast();
1324     void InitMetrics();
1325     void InitThemeMargins();
1326     void UnInit();
1327 
1328     BOOL IsFullScreenWindow(HWND hWnd);
1329     BOOL IsHKLToSkipRedrawOnNoItem();
1330     BOOL IsInItemChangeOrDirty(CTipbarThread *pTarget);
1331 
1332     void AddThreadToThreadCreatingList(CTipbarThread *pThread);
1333     void RemoveThredFromThreadCreatingList(CTipbarThread *pTarget);
1334 
1335     void MoveToStub(BOOL bFlag);
1336     void RestoreFromStub();
1337 
1338     INT GetCtrlButtonWidth();
1339     INT GetGripperWidth();
1340     INT GetTipbarHeight();
1341     BOOL AutoAdjustDeskBandSize();
1342     INT AdjustDeskBandSize(BOOL bFlag);
1343     void LocateCtrlButtons();
1344     void AdjustPosOnDisplayChange();
1345     void SetVertical(BOOL bVertical);
1346     void UpdatePosFlags();
1347 
1348     void CancelMenu();
1349     BOOL CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT prc2);
1350     void ClearLBItemList();
1351 
1352     HFONT CreateVerticalFont();
1353     void UpdateVerticalFont();
1354 
1355     void ShowOverScreenSizeBalloon();
1356     void DestroyOverScreenSizeBalloon();
1357     void DestroyWnd();
1358 
1359     HKL GetFocusKeyboardLayout();
1360     void KillOnTheadItemChangeTimer();
1361 
1362     UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT uElapse);
1363     BOOL KillTimer(UINT_PTR uIDEvent);
1364 
1365     void MoveToTray();
1366     void MyClientToScreen(LPPOINT lpPoint, LPRECT prc);
1367     void SavePosition();
1368     void SetAlpha(BYTE bAlpha, BOOL bFlag);
1369     BOOL SetLangBand(BOOL bDeskBand, BOOL bFlag2);
1370     void SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight);
1371     void SetShowText(BOOL bShow);
1372     void SetShowTrayIcon(BOOL bShow);
1373 
1374     void ShowContextMenu(POINT pt, LPCRECT prc, BOOL bFlag);
1375     void StartBackToAlphaTimer();
1376     BOOL StartDoAccDefaultActionTimer(CTipbarItem *pTarget);
1377 
1378     void StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId);
1379     void StopModalInput(DWORD dwThreadId);
1380 
1381     CTipbarThread *_CreateThread(DWORD dwThreadId);
1382     CTipbarThread *_FindThread(DWORD dwThreadId);
1383     void EnsureFocusThread();
1384     HRESULT SetFocusThread(CTipbarThread *pFocusThread);
1385     HRESULT AttachFocusThread();
1386     void RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev);
1387     void CleanUpThreadPointer(CTipbarThread *pThread, BOOL bRemove);
1388     void TerminateAllThreads(BOOL bFlag);
1389     void OnTerminateToolbar();
1390     HRESULT OnThreadTerminateInternal(DWORD dwThreadId);
1391 
1392     // IUnknown methods
1393     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
1394     STDMETHOD_(ULONG, AddRef)();
1395     STDMETHOD_(ULONG, Release)();
1396 
1397     // ITfLangBarEventSink methods
1398     STDMETHOD(OnSetFocus)(DWORD dwThreadId) override;
1399     STDMETHOD(OnThreadTerminate)(DWORD dwThreadId) override;
1400     STDMETHOD(OnThreadItemChange)(DWORD dwThreadId) override;
1401     STDMETHOD(OnModalInput)(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1402     STDMETHOD(ShowFloating)(DWORD dwFlags) override;
1403     STDMETHOD(GetItemFloatingRect)(DWORD dwThreadId, REFGUID rguid, RECT *prc) override;
1404 
1405     // ITfLangBarEventSink_P methods
1406     STDMETHOD(OnLangBarUpdate)(TfLBIClick click, BOOL bFlag) override;
1407 
1408     // CTipbarAccItem methods
1409     STDMETHOD_(BSTR, GetAccName)() override;
1410     STDMETHOD_(void, GetAccLocation)(LPRECT lprc) override;
1411 
1412     // CUIFWindow methods
1413     STDMETHOD_(void, PaintObject)(HDC hDC, LPCRECT prc) override;
1414     STDMETHOD_(DWORD, GetWndStyle)() override;
1415     STDMETHOD_(void, Move)(INT x, INT y, INT nWidth, INT nHeight) override;
1416     STDMETHOD_(void, OnMouseOutFromWindow)(LONG x, LONG y) override;
1417     STDMETHOD_(void, OnCreate)(HWND hWnd) override;
1418     STDMETHOD_(void, OnDestroy)(HWND hWnd) override;
1419     STDMETHOD_(void, OnTimer)(WPARAM wParam) override;
1420     STDMETHOD_(void, OnSysColorChange)() override;
1421     STDMETHOD_(void, OnEndSession)(HWND hWnd, WPARAM wParam, LPARAM lParam) override;
1422     STDMETHOD_(void, OnUser)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1423     STDMETHOD_(LRESULT, OnWindowPosChanged)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1424     STDMETHOD_(LRESULT, OnWindowPosChanging)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1425     STDMETHOD_(LRESULT, OnShowWindow)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1426     STDMETHOD_(LRESULT, OnSettingChange)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1427     STDMETHOD_(LRESULT, OnDisplayChange)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1428     STDMETHOD_(HRESULT, OnGetObject)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1429     STDMETHOD_(BOOL, OnEraseBkGnd)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1430     STDMETHOD_(void, OnThemeChanged)(HWND hWnd, WPARAM wParam, LPARAM lParam) override;
1431     STDMETHOD_(void, UpdateUI)(LPCRECT prc) override;
1432     STDMETHOD_(void, HandleMouseMsg)(UINT uMsg, LONG x, LONG y) override;
1433 };
1434 
1435 /***********************************************************************
1436  * CUTBLangBarDlg
1437  */
1438 
1439 CUTBLangBarDlg *CUTBLangBarDlg::GetThis(HWND hDlg)
1440 {
1441     return (CUTBLangBarDlg*)::GetWindowLongPtr(hDlg, DWLP_USER);
1442 }
1443 
1444 void CUTBLangBarDlg::SetThis(HWND hDlg, CUTBLangBarDlg *pThis)
1445 {
1446     ::SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pThis);
1447 }
1448 
1449 DWORD WINAPI CUTBLangBarDlg::s_ThreadProc(LPVOID pParam)
1450 {
1451     return ((CUTBLangBarDlg *)pParam)->ThreadProc();
1452 }
1453 
1454 BOOL CUTBLangBarDlg::StartThread()
1455 {
1456     if (IsDlgShown())
1457         return FALSE;
1458 
1459     SetDlgShown(TRUE);
1460 
1461     DWORD dwThreadId;
1462     HANDLE hThread = ::CreateThread(NULL, 0, s_ThreadProc, this, 0, &dwThreadId);
1463     if (!hThread)
1464     {
1465         SetDlgShown(FALSE);
1466         return TRUE;
1467     }
1468 
1469     ++m_cRefs;
1470     ::CloseHandle(hThread);
1471     return TRUE;
1472 }
1473 
1474 LONG CUTBLangBarDlg::_Release()
1475 {
1476     if (--m_cRefs == 0)
1477     {
1478         delete this;
1479         return 0;
1480     }
1481     return m_cRefs;
1482 }
1483 
1484 STDMETHODIMP_(BOOL) CUTBLangBarDlg::ThreadProc()
1485 {
1486     extern HINSTANCE g_hInst;
1487     ::DialogBoxParam(g_hInst, m_pszDialogName, NULL, DlgProc, (LPARAM)this);
1488     SetDlgShown(FALSE);
1489     _Release();
1490     return TRUE;
1491 }
1492 
1493 INT_PTR CALLBACK
1494 CUTBLangBarDlg::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1495 {
1496     if (uMsg == WM_INITDIALOG)
1497     {
1498         SetThis(hDlg, (CUTBLangBarDlg *)lParam);
1499         ::ShowWindow(hDlg, SW_RESTORE);
1500         ::UpdateWindow(hDlg);
1501         return TRUE;
1502     }
1503 
1504     if (uMsg == WM_COMMAND)
1505     {
1506         CUTBLangBarDlg *pThis = CUTBLangBarDlg::GetThis(hDlg);
1507         pThis->OnCommand(hDlg, wParam, lParam);
1508         return TRUE;
1509     }
1510 
1511     return FALSE;
1512 }
1513 
1514 /***********************************************************************
1515  * CUTBCloseLangBarDlg
1516  */
1517 
1518 CUTBCloseLangBarDlg::CUTBCloseLangBarDlg()
1519 {
1520     m_cRefs = 1;
1521     m_pszDialogName = MAKEINTRESOURCE(IDD_CLOSELANGBAR);
1522 }
1523 
1524 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::DoModal(HWND hDlg)
1525 {
1526     CicRegKey regKey;
1527     LSTATUS error;
1528     DWORD dwValue = FALSE;
1529     error = regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1530     if (error == ERROR_SUCCESS)
1531         regKey.QueryDword(TEXT("DontShowCloseLangBarDlg"), &dwValue);
1532 
1533     if (dwValue)
1534         return FALSE;
1535 
1536     StartThread();
1537     return TRUE;
1538 }
1539 
1540 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
1541 {
1542     switch (LOWORD(wParam))
1543     {
1544         case IDOK:
1545             DoCloseLangbar();
1546             if (::IsDlgButtonChecked(hDlg, IDC_CLOSELANGBAR_CHECK))
1547             {
1548                 CicRegKey regKey;
1549                 LSTATUS error;
1550                 error = regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1551                 if (error == ERROR_SUCCESS)
1552                     regKey.SetDword(TEXT("DontShowCloseLangBarDlg"), TRUE);
1553             }
1554             ::EndDialog(hDlg, TRUE);
1555             break;
1556 
1557         case IDCANCEL:
1558             ::EndDialog(hDlg, FALSE);
1559             break;
1560 
1561         default:
1562             return FALSE;
1563     }
1564     return TRUE;
1565 }
1566 
1567 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::IsDlgShown()
1568 {
1569     return s_bIsDlgShown;
1570 }
1571 
1572 STDMETHODIMP_(void) CUTBCloseLangBarDlg::SetDlgShown(BOOL bShown)
1573 {
1574     s_bIsDlgShown = bShown;
1575 }
1576 
1577 /***********************************************************************
1578  * CUTBMinimizeLangBarDlg
1579  */
1580 
1581 CUTBMinimizeLangBarDlg::CUTBMinimizeLangBarDlg()
1582 {
1583     m_cRefs = 1;
1584     m_pszDialogName = MAKEINTRESOURCE(IDD_MINIMIZELANGBAR);
1585 }
1586 
1587 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::DoModal(HWND hDlg)
1588 {
1589     CicRegKey regKey;
1590     LSTATUS error;
1591 
1592     DWORD dwValue = FALSE;
1593     error = regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1594     if (error == ERROR_SUCCESS)
1595         regKey.QueryDword(TEXT("DontShowMinimizeLangBarDlg"), &dwValue);
1596 
1597     if (dwValue)
1598         return FALSE;
1599 
1600     StartThread();
1601     return TRUE;
1602 }
1603 
1604 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
1605 {
1606     switch (LOWORD(wParam))
1607     {
1608         case IDOK:
1609             if (::IsDlgButtonChecked(hDlg, IDC_MINIMIZELANGBAR_CHECK))
1610             {
1611                 LSTATUS error;
1612                 CicRegKey regKey;
1613                 error = regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1614                 if (error == ERROR_SUCCESS)
1615                     regKey.SetDword(TEXT("DontShowMinimizeLangBarDlg"), TRUE);
1616             }
1617             ::EndDialog(hDlg, TRUE);
1618             break;
1619         case IDCANCEL:
1620             ::EndDialog(hDlg, FALSE);
1621             break;
1622         default:
1623             return FALSE;
1624     }
1625     return TRUE;
1626 }
1627 
1628 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::IsDlgShown()
1629 {
1630     return s_bIsDlgShown;
1631 }
1632 
1633 STDMETHODIMP_(void) CUTBMinimizeLangBarDlg::SetDlgShown(BOOL bShown)
1634 {
1635     s_bIsDlgShown = bShown;
1636 }
1637 
1638 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::ThreadProc()
1639 {
1640     ::Sleep(700);
1641     return CUTBLangBarDlg::ThreadProc();
1642 }
1643 
1644 /***********************************************************************
1645  * CCicLibMenu
1646  */
1647 
1648 CCicLibMenu::CCicLibMenu() : m_cRefs(1)
1649 {
1650 }
1651 
1652 CCicLibMenu::~CCicLibMenu()
1653 {
1654     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
1655     {
1656         delete m_MenuItems[iItem];
1657         m_MenuItems[iItem] = NULL;
1658     }
1659 }
1660 
1661 STDMETHODIMP CCicLibMenu::QueryInterface(REFIID riid, LPVOID *ppvObj)
1662 {
1663     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfMenu))
1664     {
1665         *ppvObj = this;
1666         AddRef();
1667         return S_OK;
1668     }
1669     return E_NOINTERFACE;
1670 }
1671 
1672 STDMETHODIMP_(ULONG) CCicLibMenu::AddRef()
1673 {
1674     return ++m_cRefs;
1675 }
1676 
1677 STDMETHODIMP_(ULONG) CCicLibMenu::Release()
1678 {
1679     if (--m_cRefs == 0)
1680     {
1681         delete this;
1682         return 0;
1683     }
1684     return m_cRefs;
1685 }
1686 
1687 STDMETHODIMP_(CCicLibMenu*) CCicLibMenu::CreateSubMenu()
1688 {
1689     return new(cicNoThrow) CCicLibMenu();
1690 }
1691 
1692 STDMETHODIMP_(CCicLibMenuItem*) CCicLibMenu::CreateMenuItem()
1693 {
1694     return new(cicNoThrow) CCicLibMenuItem();
1695 }
1696 
1697 STDMETHODIMP CCicLibMenu::AddMenuItem(
1698     UINT uId,
1699     DWORD dwFlags,
1700     HBITMAP hbmp,
1701     HBITMAP hbmpMask,
1702     const WCHAR *pch,
1703     ULONG cch,
1704     ITfMenu **ppSubMenu)
1705 {
1706     if (ppSubMenu)
1707         *ppSubMenu = NULL;
1708 
1709     CCicLibMenu *pSubMenu = NULL;
1710     if (dwFlags & TF_LBMENUF_SUBMENU)
1711     {
1712         if (!ppSubMenu)
1713             return E_INVALIDARG;
1714         pSubMenu = CreateSubMenu();
1715     }
1716 
1717     CCicLibMenuItem *pMenuItem = CreateMenuItem();
1718     if (!pMenuItem)
1719         return E_OUTOFMEMORY;
1720 
1721     if (!pMenuItem->Init(uId, dwFlags, hbmp, hbmpMask, pch, cch, pSubMenu))
1722         return E_FAIL;
1723 
1724     if (ppSubMenu && pSubMenu)
1725     {
1726         *ppSubMenu = pSubMenu;
1727         pSubMenu->AddRef();
1728     }
1729 
1730     m_MenuItems.Add(pMenuItem);
1731     return S_OK;
1732 }
1733 
1734 /***********************************************************************
1735  * CCicLibMenuItem
1736  */
1737 
1738 CCicLibMenuItem::CCicLibMenuItem()
1739 {
1740     m_uId = 0;
1741     m_dwFlags = 0;
1742     m_hbmp = NULL;
1743     m_hbmpMask = NULL;
1744     m_bstrText = NULL;
1745     m_pMenu = NULL;
1746 }
1747 
1748 CCicLibMenuItem::~CCicLibMenuItem()
1749 {
1750     if (m_pMenu)
1751     {
1752         m_pMenu->Release();
1753         m_pMenu = NULL;
1754     }
1755 
1756     if (m_hbmp)
1757     {
1758         ::DeleteObject(m_hbmp);
1759         m_hbmp = NULL;
1760     }
1761 
1762     if (m_hbmpMask)
1763     {
1764         ::DeleteObject(m_hbmpMask);
1765         m_hbmpMask = NULL;
1766     }
1767 
1768     ::SysFreeString(m_bstrText);
1769     m_bstrText = NULL;
1770 }
1771 
1772 BOOL CCicLibMenuItem::Init(
1773     UINT uId,
1774     DWORD dwFlags,
1775     HBITMAP hbmp,
1776     HBITMAP hbmpMask,
1777     const WCHAR *pch,
1778     ULONG cch,
1779     ITfMenu *pMenu)
1780 {
1781     m_uId = uId;
1782     m_dwFlags = dwFlags;
1783     m_bstrText = ::SysAllocStringLen(pch, cch);
1784     if (!m_bstrText && cch)
1785         return FALSE;
1786 
1787     m_pMenu = pMenu;
1788     m_hbmp = CreateBitmap(hbmp);
1789     m_hbmpMask = CreateBitmap(hbmpMask);
1790     if (hbmp)
1791         ::DeleteObject(hbmp);
1792     if (hbmpMask)
1793         ::DeleteObject(hbmpMask);
1794 
1795     return TRUE;
1796 }
1797 
1798 HBITMAP CCicLibMenuItem::CreateBitmap(HANDLE hBitmap)
1799 {
1800     if (!hBitmap)
1801         return NULL;
1802 
1803     HDC hDC = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
1804     if (!hDC)
1805         return NULL;
1806 
1807     HBITMAP hbmMem = NULL;
1808 
1809     BITMAP bm;
1810     ::GetObject(hBitmap, sizeof(bm), &bm);
1811 
1812     HGDIOBJ hbmOld1 = NULL;
1813     HDC hdcMem1 = ::CreateCompatibleDC(hDC);
1814     if (hdcMem1)
1815         hbmOld1 = ::SelectObject(hdcMem1, hBitmap);
1816 
1817     HGDIOBJ hbmOld2 = NULL;
1818     HDC hdcMem2 = ::CreateCompatibleDC(hDC);
1819     if (hdcMem2)
1820     {
1821         hbmMem = ::CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
1822         hbmOld2 = ::SelectObject(hdcMem2, hbmMem);
1823     }
1824 
1825     ::BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
1826 
1827     if (hbmOld1)
1828         ::SelectObject(hdcMem1, hbmOld1);
1829     if (hbmOld2)
1830         ::SelectObject(hdcMem2, hbmOld2);
1831 
1832     ::DeleteDC(hDC);
1833     if (hdcMem1)
1834         ::DeleteDC(hdcMem1);
1835     if (hdcMem2)
1836         ::DeleteDC(hdcMem2);
1837 
1838     return hbmMem;
1839 }
1840 
1841 /***********************************************************************
1842  * CTipbarAccessible
1843  */
1844 
1845 CTipbarAccessible::CTipbarAccessible(CTipbarAccItem *pItem)
1846 {
1847     m_cRefs = 1;
1848     m_hWnd = NULL;
1849     m_pTypeInfo = NULL;
1850     m_pStdAccessible = NULL;
1851     m_bInitialized = FALSE;
1852     m_cSelection = 1;
1853     m_AccItems.Add(pItem);
1854     ++g_DllRefCount;
1855 }
1856 
1857 CTipbarAccessible::~CTipbarAccessible()
1858 {
1859     m_pTypeInfo = m_pTypeInfo;
1860     if (m_pTypeInfo)
1861     {
1862         m_pTypeInfo->Release();
1863         m_pTypeInfo = NULL;
1864     }
1865     if (m_pStdAccessible)
1866     {
1867         m_pStdAccessible->Release();
1868         m_pStdAccessible = NULL;
1869     }
1870     --g_DllRefCount;
1871 }
1872 
1873 HRESULT CTipbarAccessible::Initialize()
1874 {
1875     m_bInitialized = TRUE;
1876 
1877     HRESULT hr = ::CreateStdAccessibleObject(m_hWnd, OBJID_CLIENT, IID_IAccessible,
1878                                              (void **)&m_pStdAccessible);
1879     if (FAILED(hr))
1880         return hr;
1881 
1882     ITypeLib *pTypeLib;
1883     hr = ::LoadRegTypeLib(LIBID_Accessibility, 1, 0, 0, &pTypeLib);
1884     if (FAILED(hr))
1885         hr = ::LoadTypeLib(L"OLEACC.DLL", &pTypeLib);
1886 
1887     if (SUCCEEDED(hr))
1888     {
1889         hr = pTypeLib->GetTypeInfoOfGuid(IID_IAccessible, &m_pTypeInfo);
1890         pTypeLib->Release();
1891     }
1892 
1893     return hr;
1894 }
1895 
1896 BOOL CTipbarAccessible::AddAccItem(CTipbarAccItem *pItem)
1897 {
1898     return m_AccItems.Add(pItem);
1899 }
1900 
1901 HRESULT CTipbarAccessible::RemoveAccItem(CTipbarAccItem *pItem)
1902 {
1903     for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem)
1904     {
1905         if (m_AccItems[iItem] == pItem)
1906         {
1907             m_AccItems.Remove(iItem, 1);
1908             break;
1909         }
1910     }
1911     return S_OK;
1912 }
1913 
1914 void CTipbarAccessible::ClearAccItems()
1915 {
1916     m_AccItems.clear();
1917 }
1918 
1919 CTipbarAccItem *CTipbarAccessible::AccItemFromID(INT iItem)
1920 {
1921     if (iItem < 0 || (INT)m_AccItems.size() <= iItem)
1922         return NULL;
1923     return m_AccItems[iItem];
1924 }
1925 
1926 INT CTipbarAccessible::GetIDOfItem(CTipbarAccItem *pTarget)
1927 {
1928     for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem)
1929     {
1930         if (pTarget == m_AccItems[iItem])
1931             return (INT)iItem;
1932     }
1933     return -1;
1934 }
1935 
1936 LONG_PTR CTipbarAccessible::CreateRefToAccObj(WPARAM wParam)
1937 {
1938     return ::LresultFromObject(IID_IAccessible, wParam, this);
1939 }
1940 
1941 BOOL CTipbarAccessible::DoDefaultActionReal(INT nID)
1942 {
1943     CTipbarAccItem *pItem = AccItemFromID(nID);
1944     if (!pItem)
1945         return FALSE;
1946     return pItem->DoAccDefaultActionReal();
1947 }
1948 
1949 void CTipbarAccessible::NotifyWinEvent(DWORD event, CTipbarAccItem *pItem)
1950 {
1951     INT nID = GetIDOfItem(pItem);
1952     if (nID < 0)
1953         return;
1954 
1955     ::NotifyWinEvent(event, m_hWnd, -4, nID);
1956 }
1957 
1958 void CTipbarAccessible::SetWindow(HWND hWnd)
1959 {
1960     m_hWnd = hWnd;
1961 }
1962 
1963 STDMETHODIMP CTipbarAccessible::QueryInterface(
1964     REFIID riid,
1965     void **ppvObject)
1966 {
1967     if (IsEqualIID(riid, IID_IUnknown) ||
1968         IsEqualIID(riid, IID_IDispatch) ||
1969         IsEqualIID(riid, IID_IAccessible))
1970     {
1971         *ppvObject = this;
1972         AddRef();
1973         return S_OK;
1974     }
1975     return E_NOINTERFACE;
1976 }
1977 
1978 STDMETHODIMP_(ULONG) CTipbarAccessible::AddRef()
1979 {
1980     return ::InterlockedIncrement(&m_cRefs);
1981 }
1982 
1983 STDMETHODIMP_(ULONG) CTipbarAccessible::Release()
1984 {
1985     LONG count = ::InterlockedDecrement(&m_cRefs);
1986     if (count == 0)
1987     {
1988         delete this;
1989         return 0;
1990     }
1991     return count;
1992 }
1993 
1994 STDMETHODIMP CTipbarAccessible::GetTypeInfoCount(UINT *pctinfo)
1995 {
1996     if (!pctinfo)
1997         return E_INVALIDARG;
1998     *pctinfo = (m_pTypeInfo == NULL);
1999     return S_OK;
2000 }
2001 
2002 STDMETHODIMP CTipbarAccessible::GetTypeInfo(
2003     UINT iTInfo,
2004     LCID lcid,
2005     ITypeInfo **ppTInfo)
2006 {
2007     if (!ppTInfo)
2008         return E_INVALIDARG;
2009     *ppTInfo = NULL;
2010     if (iTInfo != 0)
2011         return TYPE_E_ELEMENTNOTFOUND;
2012     if (!m_pTypeInfo)
2013         return E_NOTIMPL;
2014     *ppTInfo = m_pTypeInfo;
2015     m_pTypeInfo->AddRef();
2016     return S_OK;
2017 }
2018 
2019 STDMETHODIMP CTipbarAccessible::GetIDsOfNames(
2020     REFIID riid,
2021     LPOLESTR *rgszNames,
2022     UINT cNames,
2023     LCID lcid,
2024     DISPID *rgDispId)
2025 {
2026     if (!m_pTypeInfo)
2027         return E_NOTIMPL;
2028     return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
2029 }
2030 
2031 STDMETHODIMP CTipbarAccessible::Invoke(
2032     DISPID dispIdMember,
2033     REFIID riid,
2034     LCID lcid,
2035     WORD wFlags,
2036     DISPPARAMS *pDispParams,
2037     VARIANT *pVarResult,
2038     EXCEPINFO *pExcepInfo,
2039     UINT *puArgErr)
2040 {
2041     if (!m_pTypeInfo)
2042         return E_NOTIMPL;
2043     return m_pTypeInfo->Invoke(this,
2044                                dispIdMember,
2045                                wFlags,
2046                                pDispParams,
2047                                pVarResult,
2048                                pExcepInfo,
2049                                puArgErr);
2050 }
2051 
2052 STDMETHODIMP CTipbarAccessible::get_accParent(IDispatch **ppdispParent)
2053 {
2054     return m_pStdAccessible->get_accParent(ppdispParent);
2055 }
2056 
2057 STDMETHODIMP CTipbarAccessible::get_accChildCount(LONG *pcountChildren)
2058 {
2059     if (!pcountChildren)
2060         return E_INVALIDARG;
2061     INT cItems = (INT)m_AccItems.size();
2062     if (!cItems)
2063         return E_FAIL;
2064     *pcountChildren = cItems - 1;
2065     return S_OK;
2066 }
2067 
2068 STDMETHODIMP CTipbarAccessible::get_accChild(
2069     VARIANT varChildID,
2070     IDispatch **ppdispChild)
2071 {
2072     if (!ppdispChild)
2073         return E_INVALIDARG;
2074     *ppdispChild = NULL;
2075     return S_FALSE;
2076 }
2077 
2078 STDMETHODIMP CTipbarAccessible::get_accName(
2079     VARIANT varID,
2080     BSTR *pszName)
2081 {
2082     if (!pszName)
2083         return E_INVALIDARG;
2084     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2085     if (!pItem)
2086         return E_INVALIDARG;
2087     *pszName = pItem->GetAccName();
2088     if (!*pszName)
2089         return DISP_E_MEMBERNOTFOUND;
2090     return S_OK;
2091 }
2092 
2093 STDMETHODIMP CTipbarAccessible::get_accValue(
2094     VARIANT varID,
2095     BSTR *pszValue)
2096 {
2097     if (!pszValue)
2098         return E_INVALIDARG;
2099     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2100     if (!pItem)
2101         return E_INVALIDARG;
2102     *pszValue = pItem->GetAccValue();
2103     if (!*pszValue)
2104         return DISP_E_MEMBERNOTFOUND;
2105     return S_OK;
2106 }
2107 
2108 STDMETHODIMP CTipbarAccessible::get_accDescription(
2109     VARIANT varID,
2110     BSTR *description)
2111 {
2112     if (!description)
2113         return E_INVALIDARG;
2114     return m_pStdAccessible->get_accDescription(varID, description);
2115 }
2116 
2117 STDMETHODIMP CTipbarAccessible::get_accRole(
2118     VARIANT varID,
2119     VARIANT *role)
2120 {
2121     if (!role)
2122         return E_INVALIDARG;
2123     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2124     if (!pItem)
2125         return E_INVALIDARG;
2126     V_VT(role) = VT_I4;
2127     V_I4(role) = pItem->GetAccRole();
2128     return S_OK;
2129 }
2130 
2131 STDMETHODIMP CTipbarAccessible::get_accState(
2132     VARIANT varID,
2133     VARIANT *state)
2134 {
2135     if (!state)
2136         return E_INVALIDARG;
2137     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2138     if (!pItem)
2139         return E_INVALIDARG;
2140     V_VT(state) = VT_I4;
2141     V_I4(state) = pItem->GetAccState();
2142     return S_OK;
2143 }
2144 
2145 STDMETHODIMP CTipbarAccessible::get_accHelp(VARIANT varID, BSTR *help)
2146 {
2147     return DISP_E_MEMBERNOTFOUND;
2148 }
2149 
2150 STDMETHODIMP CTipbarAccessible::get_accHelpTopic(
2151     BSTR *helpfile,
2152     VARIANT varID,
2153     LONG *pidTopic)
2154 {
2155     return DISP_E_MEMBERNOTFOUND;
2156 }
2157 
2158 STDMETHODIMP CTipbarAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *shortcut)
2159 {
2160     return DISP_E_MEMBERNOTFOUND;
2161 }
2162 
2163 STDMETHODIMP CTipbarAccessible::get_accFocus(VARIANT *pvarID)
2164 {
2165     if (!pvarID)
2166         return E_INVALIDARG;
2167     V_VT(pvarID) = VT_EMPTY;
2168     return S_FALSE;
2169 }
2170 
2171 STDMETHODIMP CTipbarAccessible::get_accSelection(VARIANT *pvarID)
2172 {
2173     if (!pvarID)
2174         return E_INVALIDARG;
2175 
2176     V_VT(pvarID) = VT_EMPTY;
2177 
2178     INT cItems = (INT)m_AccItems.size();
2179     if (cItems < m_cSelection)
2180         return S_FALSE;
2181 
2182     if (cItems > m_cSelection)
2183     {
2184         V_VT(pvarID) = VT_I4;
2185         V_I4(pvarID) = m_cSelection;
2186     }
2187 
2188     return S_OK;
2189 }
2190 
2191 STDMETHODIMP CTipbarAccessible::get_accDefaultAction(
2192     VARIANT varID,
2193     BSTR *action)
2194 {
2195     if (!action)
2196         return E_INVALIDARG;
2197     *action = NULL;
2198 
2199     if (V_VT(&varID) != VT_I4)
2200         return E_INVALIDARG;
2201 
2202     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2203     if (!pItem)
2204         return DISP_E_MEMBERNOTFOUND;
2205     *action = pItem->GetAccDefaultAction();
2206     if (!*action)
2207         return S_FALSE;
2208     return S_OK;
2209 }
2210 
2211 STDMETHODIMP CTipbarAccessible::accSelect(
2212     LONG flagsSelect,
2213     VARIANT varID)
2214 {
2215     if ((flagsSelect & SELFLAG_ADDSELECTION) && (flagsSelect & SELFLAG_REMOVESELECTION))
2216         return E_INVALIDARG;
2217     if (flagsSelect & (SELFLAG_TAKEFOCUS | SELFLAG_ADDSELECTION | SELFLAG_EXTENDSELECTION))
2218         return S_FALSE;
2219     if (flagsSelect & SELFLAG_REMOVESELECTION)
2220         return S_OK;
2221     if (V_VT(&varID) != VT_I4)
2222         return E_INVALIDARG;
2223     if (flagsSelect & SELFLAG_TAKESELECTION)
2224     {
2225         m_cSelection = V_I4(&varID);
2226         return S_OK;
2227     }
2228     return S_FALSE;
2229 }
2230 
2231 STDMETHODIMP CTipbarAccessible::accLocation(
2232     LONG *left,
2233     LONG *top,
2234     LONG *width,
2235     LONG *height,
2236     VARIANT varID)
2237 {
2238     if (!left || !top || !width || !height)
2239         return E_INVALIDARG;
2240 
2241     if (!V_I4(&varID))
2242         return m_pStdAccessible->accLocation(left, top, width, height, varID);
2243 
2244     RECT rc;
2245     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2246     pItem->GetAccLocation(&rc);
2247 
2248     *left = rc.left;
2249     *top = rc.top;
2250     *width = rc.right - rc.left;
2251     *height = rc.bottom - rc.top;
2252     return S_OK;
2253 }
2254 
2255 STDMETHODIMP CTipbarAccessible::accNavigate(
2256     LONG dir,
2257     VARIANT varStart,
2258     VARIANT *pvarEnd)
2259 {
2260     if (m_AccItems.size() <= 1)
2261     {
2262         V_VT(pvarEnd) = VT_EMPTY;
2263         return S_OK;
2264     }
2265 
2266     switch (dir)
2267     {
2268         case NAVDIR_UP:
2269         case NAVDIR_LEFT:
2270         case NAVDIR_PREVIOUS:
2271             V_VT(pvarEnd) = VT_I4;
2272             V_I4(pvarEnd) = V_I4(&varStart) - 1;
2273             if (V_I4(&varStart) - 1 <= 0)
2274                 V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1);
2275             return S_OK;
2276 
2277         case NAVDIR_DOWN:
2278         case NAVDIR_RIGHT:
2279         case NAVDIR_NEXT:
2280             V_VT(pvarEnd) = VT_I4;
2281             V_I4(pvarEnd) = V_I4(&varStart) + 1;
2282             if ((INT)m_AccItems.size() <= V_I4(&varStart) + 1)
2283                 V_I4(pvarEnd) = 1;
2284             return S_OK;
2285 
2286         case NAVDIR_FIRSTCHILD:
2287             V_VT(pvarEnd) = VT_I4;
2288             V_I4(pvarEnd) = 1;
2289             return S_OK;
2290 
2291         case NAVDIR_LASTCHILD:
2292             V_VT(pvarEnd) = VT_I4;
2293             V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1);
2294             return S_OK;
2295 
2296         default:
2297             break;
2298     }
2299 
2300     V_VT(pvarEnd) = VT_EMPTY;
2301     return S_OK;
2302 }
2303 
2304 STDMETHODIMP CTipbarAccessible::accHitTest(LONG left, LONG top, VARIANT *pvarID)
2305 {
2306     if (!pvarID)
2307         return E_INVALIDARG;
2308     POINT Point = { left, top };
2309     RECT Rect;
2310     ::ScreenToClient(m_hWnd, &Point);
2311     ::GetClientRect(m_hWnd, &Rect);
2312 
2313     if (!::PtInRect(&Rect, Point))
2314     {
2315         V_VT(pvarID) = VT_EMPTY;
2316         return S_OK;
2317     }
2318 
2319     V_VT(pvarID) = VT_I4;
2320     V_I4(pvarID) = 0;
2321 
2322     for (size_t iItem = 1; iItem < m_AccItems.size(); ++iItem)
2323     {
2324         CTipbarAccItem *pItem = m_AccItems[iItem];
2325         if (pItem)
2326         {
2327             pItem->GetAccLocation(&Rect);
2328             if (::PtInRect(&Rect, Point))
2329             {
2330                 V_I4(pvarID) = iItem;
2331                 break;
2332             }
2333         }
2334     }
2335 
2336     return S_OK;
2337 }
2338 
2339 STDMETHODIMP CTipbarAccessible::accDoDefaultAction(VARIANT varID)
2340 {
2341     if (V_VT(&varID) != VT_I4)
2342         return E_INVALIDARG;
2343     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2344     if (!pItem)
2345         return DISP_E_MEMBERNOTFOUND;
2346     return (pItem->DoAccDefaultAction() ? S_OK : S_FALSE);
2347 }
2348 
2349 STDMETHODIMP CTipbarAccessible::put_accName(VARIANT varID, BSTR name)
2350 {
2351     return S_FALSE;
2352 }
2353 
2354 STDMETHODIMP CTipbarAccessible::put_accValue(VARIANT varID, BSTR value)
2355 {
2356     return S_FALSE;
2357 }
2358 
2359 /***********************************************************************
2360  * CUTBMenuWnd
2361  */
2362 
2363 CUTBMenuWnd::CUTBMenuWnd(HINSTANCE hInst, DWORD style, DWORD dwUnknown14)
2364     : CUIFMenu(hInst, style, dwUnknown14)
2365 {
2366 }
2367 
2368 BOOL CUTBMenuWnd::StartDoAccDefaultActionTimer(CUTBMenuItem *pTarget)
2369 {
2370     if (!m_pAccessible)
2371         return FALSE;
2372 
2373     m_nMenuWndID = m_pAccessible->GetIDOfItem(pTarget);
2374     if (!m_nMenuWndID || m_nMenuWndID == (UINT)-1)
2375         return FALSE;
2376 
2377     if (::IsWindow(m_hWnd))
2378     {
2379         ::KillTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION);
2380         ::SetTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION, g_uTimerElapseDOACCDEFAULTACTION, NULL);
2381     }
2382 
2383     return TRUE;
2384 }
2385 
2386 STDMETHODIMP_(BSTR) CUTBMenuWnd::GetAccName()
2387 {
2388     WCHAR szText[64];
2389     LoadStringW(g_hInst, IDS_MENUWND, szText, _countof(szText));
2390     return ::SysAllocString(szText);
2391 }
2392 
2393 STDMETHODIMP_(INT) CUTBMenuWnd::GetAccRole()
2394 {
2395     return 9;
2396 }
2397 
2398 STDMETHODIMP_(BOOL) CUTBMenuWnd::Initialize()
2399 {
2400     CTipbarAccessible *pAccessible = new(cicNoThrow) CTipbarAccessible(GetAccItem());
2401     if (pAccessible)
2402         m_pAccessible = pAccessible;
2403 
2404     return CUIFObject::Initialize();
2405 }
2406 
2407 STDMETHODIMP_(void) CUTBMenuWnd::OnCreate(HWND hWnd)
2408 {
2409     if (m_pAccessible)
2410         m_pAccessible->SetWindow(hWnd);
2411 }
2412 
2413 STDMETHODIMP_(void) CUTBMenuWnd::OnDestroy(HWND hWnd)
2414 {
2415     if (m_pAccessible)
2416     {
2417         m_pAccessible->NotifyWinEvent(EVENT_OBJECT_DESTROY, GetAccItem());
2418         m_pAccessible->ClearAccItems();
2419         m_pAccessible->Release();
2420         m_pAccessible = NULL;
2421     }
2422     m_coInit.CoUninit();
2423 }
2424 
2425 STDMETHODIMP_(HRESULT)
2426 CUTBMenuWnd::OnGetObject(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2427 {
2428     if (lParam != -4)
2429         return S_OK;
2430 
2431     if (!m_pAccessible)
2432         return E_OUTOFMEMORY;
2433 
2434     if (m_pAccessible->m_bInitialized)
2435         return m_pAccessible->CreateRefToAccObj(wParam);
2436 
2437     if (SUCCEEDED(m_coInit.EnsureCoInit()))
2438     {
2439         HRESULT hr = m_pAccessible->Initialize();
2440         if (FAILED(hr))
2441         {
2442             m_pAccessible->Release();
2443             m_pAccessible = NULL;
2444             return hr;
2445         }
2446 
2447         m_pAccessible->NotifyWinEvent(EVENT_OBJECT_CREATE, GetAccItem());
2448         return m_pAccessible->CreateRefToAccObj(wParam);
2449     }
2450 
2451     return S_OK;
2452 }
2453 
2454 STDMETHODIMP_(LRESULT)
2455 CUTBMenuWnd::OnShowWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2456 {
2457     if (m_pAccessible)
2458     {
2459         if (wParam)
2460         {
2461             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_SHOW, GetAccItem());
2462             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_FOCUS, GetAccItem());
2463         }
2464         else
2465         {
2466             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_HIDE, GetAccItem());
2467         }
2468     }
2469 
2470     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
2471 }
2472 
2473 STDMETHODIMP_(void) CUTBMenuWnd::OnTimer(WPARAM wParam)
2474 {
2475     if (wParam == TIMER_ID_DOACCDEFAULTACTION)
2476     {
2477         ::KillTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION);
2478         if (m_pAccessible && m_nMenuWndID)
2479         {
2480             m_pAccessible->DoDefaultActionReal(m_nMenuWndID);
2481             m_nMenuWndID = 0;
2482         }
2483     }
2484 }
2485 
2486 /***********************************************************************
2487  * CUTBMenuItem
2488  */
2489 
2490 CUTBMenuItem::CUTBMenuItem(CUTBMenuWnd *pMenuUI)
2491     : CUIFMenuItem(pMenuUI ? pMenuUI->GetMenu() : NULL)
2492 {
2493     m_pMenuUI = pMenuUI;
2494 }
2495 
2496 CUTBMenuItem::~CUTBMenuItem()
2497 {
2498     if (m_hbmColor)
2499     {
2500         ::DeleteObject(m_hbmColor);
2501         m_hbmColor = NULL;
2502     }
2503     if (m_hbmMask)
2504     {
2505         ::DeleteObject(m_hbmMask);
2506         m_hbmMask = NULL;
2507     }
2508 }
2509 
2510 STDMETHODIMP_(BOOL) CUTBMenuItem::DoAccDefaultAction()
2511 {
2512     if (!m_pMenuUI)
2513         return FALSE;
2514 
2515     m_pMenuUI->StartDoAccDefaultActionTimer(this);
2516     return TRUE;
2517 }
2518 
2519 STDMETHODIMP_(BOOL) CUTBMenuItem::DoAccDefaultActionReal()
2520 {
2521     if (!m_pSubMenu)
2522         OnLButtonUp(0, 0);
2523     else
2524         ShowSubPopup();
2525     return TRUE;
2526 }
2527 
2528 STDMETHODIMP_(BSTR) CUTBMenuItem::GetAccDefaultAction()
2529 {
2530     WCHAR szText[64];
2531     ::LoadStringW(g_hInst, IDS_LEFTCLICK, szText, _countof(szText));
2532     return ::SysAllocString(szText);
2533 }
2534 
2535 STDMETHODIMP_(void) CUTBMenuItem::GetAccLocation(LPRECT lprc)
2536 {
2537     GetRect(lprc);
2538     ::ClientToScreen(m_pMenuUI->m_hWnd, (LPPOINT)lprc);
2539     ::ClientToScreen(m_pMenuUI->m_hWnd, (LPPOINT)&lprc->right);
2540 }
2541 
2542 STDMETHODIMP_(BSTR) CUTBMenuItem::GetAccName()
2543 {
2544     return ::SysAllocString(m_pszMenuItemLeft);
2545 }
2546 
2547 /// @unimplemented
2548 STDMETHODIMP_(INT) CUTBMenuItem::GetAccRole()
2549 {
2550     if (FALSE) //FIXME
2551         return 21;
2552     return 12;
2553 }
2554 
2555 /***********************************************************************
2556  * CModalMenu
2557  */
2558 
2559 CUTBMenuItem *
2560 CModalMenu::InsertItem(CUTBMenuWnd *pMenuUI, INT nCommandId, INT nStringID)
2561 {
2562     CUTBMenuItem *pMenuItem = new(cicNoThrow) CUTBMenuItem(pMenuUI);
2563     if (!pMenuItem)
2564         return NULL;
2565 
2566     WCHAR szText[256];
2567     ::LoadStringW(g_hInst, nStringID, szText, _countof(szText));
2568 
2569     if (pMenuItem->Initialize() &&
2570         pMenuItem->Init(nCommandId, szText) &&
2571         pMenuUI->InsertItem(pMenuItem))
2572     {
2573         return pMenuItem;
2574     }
2575 
2576     delete pMenuItem;
2577     return NULL;
2578 }
2579 
2580 void CModalMenu::PostKey(BOOL bUp, WPARAM wParam, LPARAM lParam)
2581 {
2582     m_pMenuUI->PostKey(bUp, wParam, lParam);
2583 }
2584 
2585 void CModalMenu::CancelMenu()
2586 {
2587     if (m_pMenuUI)
2588         m_pMenuUI->CancelMenu();
2589 }
2590 
2591 /***********************************************************************
2592  * CUTBContextMenu
2593  */
2594 
2595 CUTBContextMenu::CUTBContextMenu(CTipbarWnd *pTipbarWnd)
2596 {
2597     m_pTipbarWnd = pTipbarWnd;
2598 }
2599 
2600 /// @unimplemented
2601 BOOL CUTBContextMenu::Init()
2602 {
2603     m_pTipbarThread = m_pTipbarWnd->m_pFocusThread;
2604     return !!m_pTipbarThread;
2605 }
2606 
2607 /// @unimplemented
2608 CUTBMenuWnd *CUTBContextMenu::CreateMenuUI(BOOL bFlag)
2609 {
2610     DWORD dwStatus = 0;
2611 
2612     if (FAILED(m_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus)))
2613         return NULL;
2614 
2615     CUTBMenuWnd *pMenuUI = new (cicNoThrow) CUTBMenuWnd(g_hInst, g_dwMenuStyle, 0);
2616     if (!pMenuUI)
2617         return NULL;
2618 
2619     pMenuUI->Initialize();
2620 
2621     if (dwStatus & (TF_SFT_DESKBAND | TF_SFT_MINIMIZED))
2622     {
2623         CUTBMenuItem *pRestoreLangBar = InsertItem(pMenuUI, ID_RESTORELANGBAR, IDS_RESTORELANGBAR2);
2624         if (pRestoreLangBar && !m_pTipbarWnd->m_dwUnknown20)
2625             pRestoreLangBar->Gray(TRUE);
2626     }
2627     else
2628     {
2629         InsertItem(pMenuUI, ID_DESKBAND, IDS_MINIMIZE);
2630 
2631         if (bFlag)
2632         {
2633             if (IsTransparecyAvailable())
2634             {
2635                 if (dwStatus & TF_LBI_BALLOON)
2636                 {
2637                     InsertItem(pMenuUI, ID_TRANS, IDS_TRANSPARENCY);
2638                 }
2639                 else
2640                 {
2641                     CUTBMenuItem *pTransparency = InsertItem(pMenuUI, ID_NOTRANS, IDS_TRANSPARENCY);
2642                     if (pTransparency)
2643                         pTransparency->Check(TRUE);
2644                 }
2645             }
2646 
2647             if (!(dwStatus & TF_SFT_LABELS))
2648             {
2649                 InsertItem(pMenuUI, ID_LABELS, IDS_TEXTLABELS);
2650             }
2651             else
2652             {
2653                 CUTBMenuItem *pTextLabels = InsertItem(pMenuUI, ID_NOLABELS, IDS_TEXTLABELS);
2654                 if (pTextLabels)
2655                     pTextLabels->Check(TRUE);
2656             }
2657 
2658             CUTBMenuItem *pVertical = InsertItem(pMenuUI, ID_VERTICAL, IDS_VERTICAL);
2659             if (pVertical)
2660                 pVertical->Check(!!(m_pTipbarWnd->m_dwTipbarWndFlags & 0x800000));
2661         }
2662     }
2663 
2664     if (bFlag)
2665     {
2666         CUTBMenuItem *pExtraIcons = NULL;
2667 
2668         if (dwStatus & TF_SFT_EXTRAICONSONMINIMIZED)
2669         {
2670             pExtraIcons = InsertItem(pMenuUI, ID_NOEXTRAICONS, IDS_EXTRAICONS);
2671             if (pExtraIcons)
2672                 pExtraIcons->Check(TRUE);
2673         }
2674         else
2675         {
2676             pExtraIcons = CModalMenu::InsertItem(pMenuUI, ID_EXTRAICONS, IDS_EXTRAICONS);
2677         }
2678 
2679         if (pExtraIcons)
2680         {
2681             if (::GetKeyboardLayoutList(0, NULL) == 1)
2682             {
2683                 pExtraIcons->Check(TRUE);
2684                 pExtraIcons->Gray(TRUE);
2685             }
2686             else
2687             {
2688                 pExtraIcons->Gray(FALSE);
2689             }
2690         }
2691 
2692         if (dwStatus & TF_SFT_DESKBAND)
2693             InsertItem(pMenuUI, ID_ADJUSTDESKBAND, IDS_ADJUSTLANGBAND);
2694 
2695         InsertItem(pMenuUI, ID_SETTINGS, IDS_SETTINGS);
2696 
2697         if (CheckCloseMenuAvailable())
2698             InsertItem(pMenuUI, ID_CLOSELANGBAR, IDS_CLOSELANGBAR);
2699     }
2700 
2701     return pMenuUI;
2702 }
2703 
2704 UINT
2705 CUTBContextMenu::ShowPopup(
2706     CUIFWindow *pWindow,
2707     POINT pt,
2708     LPCRECT prc,
2709     BOOL bFlag)
2710 {
2711     if (g_bWinLogon)
2712         return 0;
2713 
2714     if (m_pMenuUI)
2715         return -1;
2716 
2717     m_pMenuUI = CreateMenuUI(bFlag);
2718     if (!m_pMenuUI)
2719         return 0;
2720 
2721     UINT nCommandId = m_pMenuUI->ShowModalPopup(pWindow, prc, TRUE);
2722 
2723     if (m_pMenuUI)
2724     {
2725         delete m_pMenuUI;
2726         m_pMenuUI = NULL;
2727     }
2728 
2729     return nCommandId;
2730 }
2731 
2732 /// @unimplemented
2733 BOOL CUTBContextMenu::SelectMenuItem(UINT nCommandId)
2734 {
2735     switch (nCommandId)
2736     {
2737         case ID_TRANS:
2738             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_LOWTRANSPARENCY);
2739             break;
2740 
2741         case ID_NOTRANS:
2742             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOTRANSPARENCY);
2743             break;
2744 
2745         case ID_LABELS:
2746             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_LABELS);
2747             break;
2748 
2749         case ID_NOLABELS:
2750             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOLABELS);
2751             break;
2752 
2753         case ID_DESKBAND:
2754         {
2755             DWORD dwStatus;
2756             m_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus);
2757 
2758             if (dwStatus & TF_SFT_DESKBAND)
2759                 break;
2760 
2761             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND);
2762 
2763             CUTBMinimizeLangBarDlg *pDialog = new(cicNoThrow) CUTBMinimizeLangBarDlg();
2764             if (pDialog)
2765             {
2766                 pDialog->DoModal(*m_pTipbarWnd->GetWindow());
2767                 pDialog->_Release();
2768             }
2769             break;
2770         }
2771 
2772         case ID_CLOSELANGBAR:
2773         {
2774             CUTBCloseLangBarDlg *pDialog = new(cicNoThrow) CUTBCloseLangBarDlg();
2775             if (pDialog)
2776             {
2777                 BOOL bOK = pDialog->DoModal(*m_pTipbarWnd->GetWindow());
2778                 pDialog->_Release();
2779                 if (!bOK)
2780                     DoCloseLangbar();
2781             }
2782             break;
2783         }
2784 
2785         case ID_EXTRAICONS:
2786             m_pTipbarWnd->m_dwTipbarWndFlags &= ~0x4000;
2787             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_EXTRAICONSONMINIMIZED);
2788             break;
2789 
2790         case ID_NOEXTRAICONS:
2791             m_pTipbarWnd->m_dwTipbarWndFlags &= ~0x4000;
2792             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOEXTRAICONSONMINIMIZED);
2793             break;
2794 
2795         case ID_RESTORELANGBAR:
2796             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_LBI_ICON);
2797             break;
2798 
2799         case ID_VERTICAL:
2800             m_pTipbarWnd->SetVertical((m_pTipbarWnd->m_dwTipbarWndFlags & 0x4) ? TRUE : FALSE);
2801             break;
2802 
2803         case ID_ADJUSTDESKBAND:
2804             m_pTipbarWnd->AdjustDeskBandSize(TRUE);
2805             break;
2806 
2807         case ID_SETTINGS:
2808             TF_RunInputCPL();
2809             break;
2810 
2811         default:
2812             break;
2813     }
2814 
2815     return TRUE;
2816 }
2817 
2818 /***********************************************************************
2819  * CTrayIconItem
2820  */
2821 
2822 CTrayIconItem::CTrayIconItem(CTrayIconWnd *pTrayIconWnd)
2823 {
2824     m_dwIconAddOrModify = NIM_ADD;
2825     m_pTrayIconWnd = pTrayIconWnd;
2826 }
2827 
2828 BOOL
2829 CTrayIconItem::_Init(
2830     HWND hWnd,
2831     UINT uCallbackMessage,
2832     UINT uNotifyIconID,
2833     const GUID& rguid)
2834 {
2835     m_hWnd = hWnd;
2836     m_uCallbackMessage = uCallbackMessage;
2837     m_uNotifyIconID = uNotifyIconID;
2838     m_guid = rguid;
2839     return TRUE;
2840 }
2841 
2842 BOOL CTrayIconItem::RemoveIcon()
2843 {
2844     if (m_dwIconAddOrModify == NIM_MODIFY)
2845     {
2846         NOTIFYICONDATAW NotifyIcon = { sizeof(NotifyIcon), m_hWnd, m_uNotifyIconID };
2847         NotifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
2848         NotifyIcon.uCallbackMessage = m_uCallbackMessage;
2849         ::Shell_NotifyIconW(NIM_DELETE, &NotifyIcon);
2850     }
2851 
2852     m_dwIconAddOrModify = NIM_ADD;
2853     m_bIconAdded = TRUE;
2854     return TRUE;
2855 }
2856 
2857 BOOL CTrayIconItem::SetIcon(HICON hIcon, LPCWSTR pszTip)
2858 {
2859     if (!hIcon)
2860         return FALSE;
2861 
2862     NOTIFYICONDATAW NotifyIcon = { sizeof(NotifyIcon), m_hWnd, m_uNotifyIconID };
2863     NotifyIcon.uFlags = NIF_ICON | NIF_MESSAGE;
2864     NotifyIcon.uCallbackMessage = m_uCallbackMessage;
2865     NotifyIcon.hIcon = hIcon;
2866     if (pszTip)
2867     {
2868         NotifyIcon.uFlags |= NIF_TIP;
2869         StringCchCopyW(NotifyIcon.szTip, _countof(NotifyIcon.szTip), pszTip);
2870     }
2871 
2872     ::Shell_NotifyIconW(m_dwIconAddOrModify, &NotifyIcon);
2873 
2874     m_dwIconAddOrModify = NIM_MODIFY;
2875     m_bIconAdded = NIM_MODIFY;
2876     return TRUE;
2877 }
2878 
2879 BOOL CTrayIconItem::UpdateMenuRectPoint()
2880 {
2881     HWND hNotifyWnd = m_pTrayIconWnd->GetNotifyWnd();
2882     ::GetClientRect(hNotifyWnd, &m_rcMenu);
2883     ::ClientToScreen(hNotifyWnd, (LPPOINT)&m_rcMenu);
2884     ::ClientToScreen(hNotifyWnd, (LPPOINT)&m_rcMenu.right);
2885     ::GetCursorPos(&m_ptCursor);
2886     return TRUE;
2887 }
2888 
2889 /***********************************************************************
2890  * CButtonIconItem
2891  */
2892 
2893 CButtonIconItem::CButtonIconItem(CTrayIconWnd *pWnd, DWORD dwUnknown24)
2894     : CTrayIconItem(pWnd)
2895 {
2896     m_dwUnknown24 = dwUnknown24;
2897 }
2898 
2899 /// @unimplemented
2900 STDMETHODIMP_(BOOL) CButtonIconItem::OnMsg(WPARAM wParam, LPARAM lParam)
2901 {
2902     switch (lParam)
2903     {
2904         case WM_LBUTTONDOWN:
2905         case WM_RBUTTONDOWN:
2906         case WM_LBUTTONDBLCLK:
2907         case WM_RBUTTONDBLCLK:
2908             break;
2909         default:
2910             return TRUE;
2911     }
2912 
2913     //FIXME
2914     return TRUE;
2915 }
2916 
2917 /// @unimplemented
2918 STDMETHODIMP_(BOOL) CButtonIconItem::OnDelayMsg(UINT uMsg)
2919 {
2920     //FIXME
2921     return FALSE;
2922 }
2923 
2924 /***********************************************************************
2925  * CMainIconItem
2926  */
2927 
2928 CMainIconItem::CMainIconItem(CTrayIconWnd *pWnd)
2929     : CButtonIconItem(pWnd, 1)
2930 {
2931 }
2932 
2933 BOOL CMainIconItem::Init(HWND hWnd)
2934 {
2935     return CTrayIconItem::_Init(hWnd, WM_USER, 0, GUID_LBI_TRAYMAIN);
2936 }
2937 
2938 /// @unimplemented
2939 STDMETHODIMP_(BOOL) CMainIconItem::OnDelayMsg(UINT uMsg)
2940 {
2941     if (!CButtonIconItem::OnDelayMsg(uMsg))
2942         return 0;
2943 
2944     if (uMsg == WM_LBUTTONDBLCLK)
2945     {
2946         //FIXME
2947         //if (g_pTipbarWnd->m_dwUnknown20)
2948         //    g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_SHOWNORMAL);
2949     }
2950     else if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN)
2951     {
2952         //FIXME
2953         //g_pTipbarWnd->ShowContextMenu(m_ptCursor, &m_rcClient, uMsg == WM_RBUTTONDOWN);
2954     }
2955     return TRUE;
2956 }
2957 
2958 /***********************************************************************
2959  * CTrayIconWnd
2960  */
2961 
2962 CTrayIconWnd::CTrayIconWnd()
2963 {
2964     m_uCallbackMsg = WM_USER + 0x1000;
2965     m_uNotifyIconID = 0x1000;
2966 }
2967 
2968 CTrayIconWnd::~CTrayIconWnd()
2969 {
2970     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
2971     {
2972         auto& pItem = m_Items[iItem];
2973         if (pItem)
2974         {
2975             delete pItem;
2976             pItem = NULL;
2977         }
2978     }
2979 }
2980 
2981 void CTrayIconWnd::CallOnDelayMsg()
2982 {
2983     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
2984     {
2985         auto pItem = m_Items[iItem];
2986         if (pItem && m_uCallbackMessage == pItem->m_uCallbackMessage)
2987         {
2988             pItem->OnDelayMsg(m_uMsg);
2989             break;
2990         }
2991     }
2992 }
2993 
2994 HWND CTrayIconWnd::CreateWnd()
2995 {
2996     m_hWnd = ::CreateWindowEx(0, TEXT("CTrayIconWndClass"), NULL, WS_DISABLED,
2997                               0, 0, 0, 0, NULL, NULL, g_hInst, this);
2998     FindTrayEtc();
2999 
3000     m_pMainIconItem = new(cicNoThrow) CMainIconItem(this);
3001     if (m_pMainIconItem)
3002     {
3003         m_pMainIconItem->Init(m_hWnd);
3004         m_Items.Add(m_pMainIconItem);
3005     }
3006 
3007     return m_hWnd;
3008 }
3009 
3010 void CTrayIconWnd::DestroyWnd()
3011 {
3012     ::DestroyWindow(m_hWnd);
3013     m_hWnd = NULL;
3014 }
3015 
3016 BOOL CALLBACK CTrayIconWnd::EnumChildWndProc(HWND hWnd, LPARAM lParam)
3017 {
3018     CTrayIconWnd *pWnd = (CTrayIconWnd *)lParam;
3019 
3020     TCHAR ClassName[60];
3021     ::GetClassName(hWnd, ClassName, _countof(ClassName));
3022     if (lstrcmp(ClassName, TEXT("TrayNotifyWnd")) != 0)
3023         return TRUE;
3024 
3025     pWnd->m_hNotifyWnd = hWnd;
3026     return FALSE;
3027 }
3028 
3029 CButtonIconItem *CTrayIconWnd::FindIconItem(REFGUID rguid)
3030 {
3031     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3032     {
3033         auto pItem = m_Items[iItem];
3034         if (IsEqualGUID(rguid, pItem->m_guid))
3035             return pItem;
3036     }
3037     return NULL;
3038 }
3039 
3040 BOOL CTrayIconWnd::FindTrayEtc()
3041 {
3042     m_hTrayWnd = ::FindWindow(TEXT("Shell_TrayWnd"), NULL);
3043     if (!m_hTrayWnd)
3044         return FALSE;
3045 
3046     ::EnumChildWindows(m_hTrayWnd, EnumChildWndProc, (LPARAM)this);
3047     if (!m_hNotifyWnd)
3048         return FALSE;
3049     m_dwTrayWndThreadId = ::GetWindowThreadProcessId(m_hTrayWnd, NULL);
3050     m_hwndProgman = FindWindow(TEXT("Progman"), NULL);
3051     m_dwProgmanThreadId = ::GetWindowThreadProcessId(m_hwndProgman, NULL);
3052     return TRUE;
3053 }
3054 
3055 HWND CTrayIconWnd::GetNotifyWnd()
3056 {
3057     if (!::IsWindow(m_hNotifyWnd))
3058         FindTrayEtc();
3059     return m_hNotifyWnd;
3060 }
3061 
3062 /// @unimplemented
3063 BOOL CTrayIconWnd::OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
3064 {
3065     //FIXME
3066     //if (g_pTipbarWnd)
3067     //    g_pTipbarWnd->AttachFocusThread();
3068 
3069     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3070     {
3071         auto pItem = m_Items[iItem];
3072         if (pItem)
3073         {
3074             if (uMsg == pItem->m_uCallbackMessage)
3075             {
3076                 pItem->OnMsg(wParam, lParam);
3077                 return TRUE;
3078             }
3079         }
3080     }
3081     return FALSE;
3082 }
3083 
3084 BOOL CTrayIconWnd::RegisterClass()
3085 {
3086     WNDCLASSEX wc = { sizeof(wc) };
3087     wc.style = CS_HREDRAW | CS_VREDRAW;
3088     wc.hInstance = g_hInst;
3089     wc.hCursor = ::LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
3090     wc.lpfnWndProc = CTrayIconWnd::_WndProc;
3091     wc.lpszClassName = TEXT("CTrayIconWndClass");
3092     ::RegisterClassEx(&wc);
3093     return TRUE;
3094 }
3095 
3096 void CTrayIconWnd::RemoveAllIcon(DWORD dwFlags)
3097 {
3098     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3099     {
3100         auto pItem = m_Items[iItem];
3101         if (dwFlags & 0x1)
3102         {
3103             if (IsEqualGUID(pItem->m_guid, GUID_LBI_INATITEM) ||
3104                 IsEqualGUID(pItem->m_guid, GUID_LBI_CTRL))
3105             {
3106                 continue;
3107             }
3108         }
3109 
3110         if (dwFlags & 0x2)
3111         {
3112             if (IsEqualGUID(pItem->m_guid, GUID_TFCAT_TIP_KEYBOARD))
3113                 continue;
3114         }
3115 
3116         if (pItem->m_uNotifyIconID < 0x1000)
3117             continue;
3118 
3119         pItem->RemoveIcon();
3120     }
3121 }
3122 
3123 /// @unimplemented
3124 void CTrayIconWnd::RemoveUnusedIcons(int unknown)
3125 {
3126     //FIXME
3127 }
3128 
3129 BOOL CTrayIconWnd::SetIcon(REFGUID rguid, DWORD dwUnknown24, HICON hIcon, LPCWSTR psz)
3130 {
3131     CButtonIconItem *pItem = FindIconItem(rguid);
3132     if (!pItem)
3133     {
3134         if (!hIcon)
3135             return FALSE;
3136         pItem = new(cicNoThrow) CButtonIconItem(this, dwUnknown24);
3137         if (!pItem)
3138             return FALSE;
3139 
3140         pItem->_Init(m_hWnd, m_uCallbackMsg, m_uNotifyIconID, rguid);
3141         m_uCallbackMsg += 2;
3142         ++m_uNotifyIconID;
3143         m_Items.Add(pItem);
3144     }
3145 
3146     if (!hIcon)
3147         return pItem->RemoveIcon();
3148 
3149     return pItem->SetIcon(hIcon, psz);
3150 }
3151 
3152 BOOL CTrayIconWnd::SetMainIcon(HKL hKL)
3153 {
3154     if (!hKL)
3155     {
3156         m_pMainIconItem->RemoveIcon();
3157         m_pMainIconItem->m_hKL = NULL;
3158         return TRUE;
3159     }
3160 
3161     if (hKL != m_pMainIconItem->m_hKL)
3162     {
3163         WCHAR szText[64];
3164         HICON hIcon = TF_GetLangIcon(LOWORD(hKL), szText, _countof(szText));
3165         if (hIcon)
3166         {
3167             m_pMainIconItem->SetIcon(hIcon, szText);
3168             ::DestroyIcon(hIcon);
3169         }
3170         else
3171         {
3172             ::LoadStringW(g_hInst, IDS_RESTORELANGBAR, szText, _countof(szText));
3173             hIcon = ::LoadIconW(g_hInst, MAKEINTRESOURCEW(IDI_MAINICON));
3174             m_pMainIconItem->SetIcon(hIcon, szText);
3175         }
3176 
3177         m_pMainIconItem->m_hKL = hKL;
3178     }
3179 
3180     return TRUE;
3181 }
3182 
3183 CTrayIconWnd *CTrayIconWnd::GetThis(HWND hWnd)
3184 {
3185     return (CTrayIconWnd *)::GetWindowLongPtr(hWnd, GWL_USERDATA);
3186 }
3187 
3188 void CTrayIconWnd::SetThis(HWND hWnd, LPCREATESTRUCT pCS)
3189 {
3190     if (pCS)
3191         ::SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)pCS->lpCreateParams);
3192     else
3193         ::SetWindowLongPtr(hWnd, GWL_USERDATA, 0);
3194 }
3195 
3196 LRESULT CALLBACK
3197 CTrayIconWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3198 {
3199     CTrayIconWnd *pThis;
3200     switch (uMsg)
3201     {
3202         case WM_CREATE:
3203             CTrayIconWnd::SetThis(hWnd, (LPCREATESTRUCT)lParam);
3204             break;
3205         case WM_DESTROY:
3206             ::SetWindowLongPtr(hWnd, GWL_USERDATA, 0);
3207             break;
3208         case WM_TIMER:
3209             if (wParam == 100)
3210             {
3211                 ::KillTimer(hWnd, 100);
3212                 pThis = CTrayIconWnd::GetThis(hWnd);
3213                 if (pThis)
3214                     pThis->CallOnDelayMsg();
3215             }
3216             break;
3217         default:
3218         {
3219             if (uMsg < WM_USER)
3220                 return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
3221             pThis = CTrayIconWnd::GetThis(hWnd);
3222             if (pThis && pThis->OnIconMessage(uMsg, wParam, lParam))
3223                 break;
3224             return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
3225         }
3226     }
3227     return 0;
3228 }
3229 
3230 /***********************************************************************
3231  * CLBarItemBase
3232  */
3233 
3234 CLBarItemBase::CLBarItemBase()
3235 {
3236     m_dwItemStatus = 0;
3237     m_szToolTipText[0] = 0;
3238     m_cRefs = 1;
3239     m_pLangBarItemSink = NULL;
3240 }
3241 
3242 CLBarItemBase::~CLBarItemBase()
3243 {
3244     if (m_pLangBarItemSink)
3245         m_pLangBarItemSink->Release();
3246 }
3247 
3248 HRESULT
3249 CLBarItemBase::AdviseSink(
3250     REFIID riid,
3251     IUnknown *punk,
3252     DWORD *pdwCookie)
3253 {
3254     if (IsEqualIID(riid, IID_ITfLangBarItemSink) || m_pLangBarItemSink)
3255         return TF_E_NOOBJECT;
3256 
3257     HRESULT hr = punk->QueryInterface(IID_ITfLangBarItemSink, (void **)&m_pLangBarItemSink);
3258     if (SUCCEEDED(hr))
3259         *pdwCookie = 0x80000001;
3260     return hr;
3261 }
3262 
3263 HRESULT CLBarItemBase::UnadviseSink(DWORD dwCookie)
3264 {
3265     if (dwCookie != 0x80000001)
3266         return E_FAIL;
3267 
3268     if (!m_pLangBarItemSink)
3269         return E_UNEXPECTED;
3270 
3271     m_pLangBarItemSink->Release();
3272     m_pLangBarItemSink = NULL;
3273     return S_OK;
3274 }
3275 
3276 void
3277 CLBarItemBase::InitNuiInfo(
3278     REFIID clsidService,
3279     REFGUID guidItem,
3280     DWORD dwStyle,
3281     DWORD ulSort,
3282     LPCWSTR Source)
3283 {
3284     m_NewUIInfo.clsidService = clsidService;
3285     m_NewUIInfo.guidItem = guidItem;
3286     m_NewUIInfo.dwStyle = dwStyle;
3287     m_NewUIInfo.ulSort = ulSort;
3288     StringCchCopyW(m_NewUIInfo.szDescription, _countof(m_NewUIInfo.szDescription), Source);
3289 }
3290 
3291 HRESULT
3292 CLBarItemBase::ShowInternal(BOOL bShow, BOOL bUpdate)
3293 {
3294     DWORD dwOldStatus = m_dwItemStatus;
3295 
3296     if (bShow)
3297         m_dwItemStatus &= ~TF_LBI_STATUS_HIDDEN;
3298     else
3299         m_dwItemStatus |= TF_LBI_STATUS_HIDDEN;
3300 
3301     if (bUpdate && (dwOldStatus != m_dwItemStatus))
3302     {
3303         if (m_pLangBarItemSink)
3304             m_pLangBarItemSink->OnUpdate(TF_LBI_STATUS);
3305     }
3306 
3307     return S_OK;
3308 }
3309 
3310 HRESULT CLBarItemBase::GetInfo(TF_LANGBARITEMINFO *pInfo)
3311 {
3312     CopyMemory(pInfo, &m_NewUIInfo, sizeof(*pInfo));
3313     return S_OK;
3314 }
3315 
3316 HRESULT CLBarItemBase::GetStatus(DWORD *pdwStatus)
3317 {
3318     *pdwStatus = m_dwItemStatus;
3319     return S_OK;
3320 }
3321 
3322 HRESULT CLBarItemBase::Show(BOOL fShow)
3323 {
3324     return ShowInternal(fShow, TRUE);
3325 }
3326 
3327 HRESULT CLBarItemBase::GetTooltipString(BSTR *pbstrToolTip)
3328 {
3329     if (!pbstrToolTip)
3330         return E_INVALIDARG;
3331     BSTR bstr = ::SysAllocString(m_szToolTipText);
3332     *pbstrToolTip = bstr;
3333     return bstr ? S_OK : E_OUTOFMEMORY;
3334 }
3335 
3336 /***********************************************************************
3337  * CUTBLBarMenu
3338  */
3339 
3340 CUTBLBarMenu::CUTBLBarMenu(HINSTANCE hInst) : CCicLibMenu()
3341 {
3342     m_hInst = hInst;
3343 }
3344 
3345 CUTBLBarMenu::~CUTBLBarMenu()
3346 {
3347 }
3348 
3349 STDMETHODIMP_(CCicLibMenuItem*) CUTBLBarMenu::CreateMenuItem()
3350 {
3351     CUTBLBarMenuItem *pItem = new(cicNoThrow) CUTBLBarMenuItem();
3352     if (!pItem)
3353         return NULL;
3354     pItem->m_pLBarMenu = this;
3355     return pItem;
3356 }
3357 
3358 CUTBMenuWnd *CUTBLBarMenu::CreateMenuUI()
3359 {
3360     CUTBMenuWnd *pMenuUI = new(cicNoThrow) CUTBMenuWnd(m_hInst, g_dwMenuStyle, 0);
3361     if (!pMenuUI)
3362         return NULL;
3363 
3364     pMenuUI->Initialize();
3365     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
3366     {
3367         CUTBLBarMenuItem *pItem = (CUTBLBarMenuItem *)m_MenuItems[iItem];
3368         pItem->InsertToUI(pMenuUI);
3369     }
3370 
3371     return pMenuUI;
3372 }
3373 
3374 STDMETHODIMP_(CCicLibMenu*) CUTBLBarMenu::CreateSubMenu()
3375 {
3376     return new(cicNoThrow) CUTBLBarMenu(m_hInst);
3377 }
3378 
3379 INT CUTBLBarMenu::ShowPopup(CUIFWindow *pWindow, POINT pt, LPCRECT prcExclude)
3380 {
3381     if (m_pMenuUI)
3382         return 0;
3383 
3384     m_pMenuUI = CreateMenuUI();
3385     if (!m_pMenuUI)
3386         return -1;
3387 
3388     INT nCommandId = m_pMenuUI->ShowModalPopup(pWindow, prcExclude, TRUE);
3389 
3390     if (m_pMenuUI)
3391     {
3392         delete m_pMenuUI;
3393         m_pMenuUI = NULL;
3394     }
3395 
3396     return nCommandId;
3397 }
3398 
3399 /***********************************************************************
3400  * CUTBLBarMenuItem
3401  */
3402 
3403 /// @unimplemented
3404 BOOL CUTBLBarMenuItem::InsertToUI(CUTBMenuWnd *pMenuUI)
3405 {
3406     if ((m_dwFlags & 4) != 0)
3407     {
3408         pMenuUI->InsertSeparator();
3409         return TRUE;
3410     }
3411     if (m_dwFlags & 2)
3412     {
3413         //FIXME
3414     }
3415     else
3416     {
3417         //FIXME
3418     }
3419     return FALSE;
3420 }
3421 
3422 /***********************************************************************
3423  * CLBarItemButtonBase
3424  */
3425 
3426 CLBarItemButtonBase::~CLBarItemButtonBase()
3427 {
3428     if (m_hIcon)
3429     {
3430         ::DestroyIcon(m_hIcon);
3431         m_hIcon = NULL;
3432     }
3433 }
3434 
3435 STDMETHODIMP CLBarItemButtonBase::QueryInterface(REFIID riid, void **ppvObject)
3436 {
3437     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfLangBarItem))
3438     {
3439         *ppvObject = static_cast<ITfLangBarItem*>(this);
3440         AddRef();
3441         return S_OK;
3442     }
3443     if (IsEqualIID(riid, IID_ITfLangBarItemButton))
3444     {
3445         *ppvObject = static_cast<ITfLangBarItemButton*>(this);
3446         AddRef();
3447         return S_OK;
3448     }
3449     if (IsEqualIID(riid, IID_ITfSource))
3450     {
3451         *ppvObject = static_cast<ITfSource*>(this);
3452         AddRef();
3453         return S_OK;
3454     }
3455     return E_NOINTERFACE;
3456 }
3457 
3458 STDMETHODIMP_(ULONG) CLBarItemButtonBase::AddRef()
3459 {
3460     return ++m_cRefs;
3461 }
3462 
3463 STDMETHODIMP_(ULONG) CLBarItemButtonBase::Release()
3464 {
3465     if (--m_cRefs == 0)
3466     {
3467         delete this;
3468         return 0;
3469     }
3470     return m_cRefs;
3471 }
3472 
3473 /// @unimplemented
3474 STDMETHODIMP CLBarItemButtonBase::OnClick(TfLBIClick click, POINT pt, LPCRECT prc)
3475 {
3476     if (click == TF_LBI_CLK_RIGHT)
3477     {
3478         return E_NOTIMPL; //FIXME
3479     }
3480     if (click == TF_LBI_CLK_LEFT)
3481     {
3482         return E_NOTIMPL; //FIXME
3483     }
3484     return E_NOTIMPL;
3485 }
3486 
3487 STDMETHODIMP CLBarItemButtonBase::InitMenu(ITfMenu *pMenu)
3488 {
3489     return E_NOTIMPL;
3490 }
3491 
3492 STDMETHODIMP CLBarItemButtonBase::OnMenuSelect(UINT wID)
3493 {
3494     return E_NOTIMPL;
3495 }
3496 
3497 STDMETHODIMP CLBarItemButtonBase::GetIcon(HICON *phIcon)
3498 {
3499     return E_NOTIMPL;
3500 }
3501 
3502 STDMETHODIMP CLBarItemButtonBase::GetText(BSTR *pbstr)
3503 {
3504     if (!pbstr)
3505         return E_INVALIDARG;
3506     *pbstr = ::SysAllocString(m_NewUIInfo.szDescription);
3507     return (*pbstr ? S_OK : E_OUTOFMEMORY);
3508 }
3509 
3510 STDMETHODIMP CLBarItemButtonBase::GetInfo(TF_LANGBARITEMINFO *pInfo)
3511 {
3512     return CLBarItemBase::GetInfo(pInfo);
3513 }
3514 
3515 STDMETHODIMP CLBarItemButtonBase::GetStatus(DWORD *pdwStatus)
3516 {
3517     return CLBarItemBase::GetStatus(pdwStatus);
3518 }
3519 
3520 STDMETHODIMP CLBarItemButtonBase::Show(BOOL fShow)
3521 {
3522     return CLBarItemBase::Show(fShow);
3523 }
3524 
3525 STDMETHODIMP CLBarItemButtonBase::GetTooltipString(BSTR *pbstrToolTip)
3526 {
3527     return CLBarItemBase::GetTooltipString(pbstrToolTip);
3528 }
3529 
3530 STDMETHODIMP CLBarItemButtonBase::AdviseSink(
3531     REFIID riid,
3532     IUnknown *punk,
3533     DWORD *pdwCookie)
3534 {
3535     return CLBarItemBase::AdviseSink(riid, punk, pdwCookie);
3536 }
3537 
3538 STDMETHODIMP CLBarItemButtonBase::UnadviseSink(DWORD dwCookie)
3539 {
3540     return CLBarItemBase::UnadviseSink(dwCookie);
3541 }
3542 
3543 /***********************************************************************
3544  * CLBarInatItem
3545  */
3546 
3547 CLBarInatItem::CLBarInatItem(DWORD dwThreadId)
3548 {
3549     WCHAR szText[256];
3550     ::LoadStringW(g_hInst, IDS_LANGUAGE, szText, _countof(szText));
3551     InitNuiInfo(CLSID_SYSTEMLANGBARITEM, GUID_LBI_INATITEM, 0x20001, 0, szText);
3552 
3553     ::LoadStringW(g_hInst, IDS_LANGUAGEBUTTON, szText, _countof(szText));
3554     StringCchCopyW(m_szToolTipText, _countof(m_szToolTipText), szText);
3555     m_dwThreadId = dwThreadId;
3556     m_hKL = ::GetKeyboardLayout(m_dwThreadId);
3557 
3558     TF_InitMlngInfo();
3559     ShowInternal(TF_MlngInfoCount() > 1, 0);
3560 }
3561 
3562 STDMETHODIMP CLBarInatItem::GetIcon(HICON *phIcon)
3563 {
3564     HICON hIcon = NULL;
3565     INT iIndex = GetIconIndexFromhKL(m_hKL);
3566     if (iIndex != -1)
3567         hIcon = TF_InatExtractIcon(iIndex);
3568     *phIcon = hIcon;
3569     return S_OK;
3570 }
3571 
3572 STDMETHODIMP CLBarInatItem::GetText(BSTR *pbstr)
3573 {
3574     if (!pbstr)
3575         return E_INVALIDARG;
3576 
3577     WCHAR szText[256];
3578     if (!GethKLDesc(m_hKL, szText, _countof(szText)))
3579         return GetText(pbstr);
3580 
3581     *pbstr = ::SysAllocString(szText);
3582     return S_OK;
3583 }
3584 
3585 STDMETHODIMP CLBarInatItem::InitMenu(ITfMenu *pMenu)
3586 {
3587     TF_InitMlngInfo();
3588 
3589     INT iKL, cKLs = TF_MlngInfoCount();
3590     for (iKL = 0; iKL < cKLs; ++iKL)
3591     {
3592         HKL hKL;
3593         WCHAR szDesc[128];
3594         if (TF_GetMlngHKL(iKL, &hKL, szDesc, _countof(szDesc)))
3595         {
3596             HICON hIcon = NULL;
3597             INT iIndex = GetIconIndexFromhKL(hKL);
3598             if (iIndex != -1)
3599                 hIcon = TF_InatExtractIcon(iIndex);
3600 
3601             LangBarInsertMenu(pMenu, iKL, szDesc, (hKL == m_hKL), hIcon);
3602         }
3603     }
3604 
3605 #if 0 // FIXME: g_pTipbarWnd
3606     DWORD dwStatus;
3607     if (g_pTipbarWnd &&
3608         g_pTipbarWnd->m_pLangBarMgr &&
3609         SUCCEEDED(g_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus)) &&
3610         (dwStatus & (TF_SFT_DESKBAND | TF_SFT_MINIMIZED)))
3611     {
3612         LangBarInsertSeparator(pMenu);
3613 
3614         WCHAR szText[256];
3615         ::LoadStringW(g_hInst, IDS_RESTORELANGBAR2, szText, _countof(szText));
3616         LangBarInsertMenu(pMenu, 2000, szText, FALSE, NULL);
3617     }
3618 #endif
3619 
3620     return S_OK;
3621 }
3622 
3623 STDMETHODIMP CLBarInatItem::OnMenuSelect(INT nCommandId)
3624 {
3625     HKL hKL;
3626 
3627     if (nCommandId == 2000)
3628     {
3629         if (g_pTipbarWnd)
3630         {
3631 #if 0 // FIXME: g_pTipbarWnd
3632             ITfLangBarMgr *pLangBarMgr = g_pTipbarWnd->m_pLangBarMgr;
3633             if (pLangBarMgr)
3634                 pLangBarMgr->ShowFloating(TF_SFT_SHOWNORMAL);
3635 #endif
3636         }
3637     }
3638     else if (TF_GetMlngHKL(nCommandId, &hKL, NULL, 0))
3639     {
3640 #if 0 // FIXME: g_pTipbarWnd
3641         g_pTipbarWnd->RestoreLastFocus(0, (g_pTipbarWnd->m_dwTipbarWndFlags & 2) != 0);
3642 #endif
3643         HWND hwndFore = ::GetForegroundWindow();
3644         if (m_dwThreadId == ::GetWindowThreadProcessId(hwndFore, NULL))
3645         {
3646             BOOL FontSig = GetFontSig(hwndFore, hKL);
3647             ::PostMessage(hwndFore, WM_INPUTLANGCHANGEREQUEST, FontSig, (LPARAM)hKL);
3648         }
3649     }
3650 
3651     return S_OK;
3652 }
3653 
3654 /***********************************************************************
3655  * CTipbarGripper
3656  */
3657 
3658 CTipbarGripper::CTipbarGripper(CTipbarWnd *pTipbarWnd, LPCRECT prc, DWORD style)
3659     : CUIFGripper((pTipbarWnd ? pTipbarWnd->GetWindow() : NULL), prc, style)
3660 {
3661     m_bInDebugMenu = FALSE;
3662     m_pTipbarWnd = pTipbarWnd;
3663 }
3664 
3665 /// @unimplemented
3666 STDMETHODIMP_(void) CTipbarGripper::OnLButtonUp(LONG x, LONG y)
3667 {
3668     m_pTipbarWnd->RestoreFromStub();
3669 
3670     APPBARDATA AppBar = { sizeof(AppBar) };
3671     AppBar.hWnd = ::FindWindowW(L"Shell_TrayWnd", NULL);
3672     if (::SHAppBarMessage(ABM_GETTASKBARPOS, &AppBar))
3673     {
3674         RECT rc = AppBar.rc;
3675         POINT pt;
3676         ::GetCursorPos(&pt);
3677         if (g_pTipbarWnd && ::PtInRect(&rc, pt))
3678             g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND | TF_SFT_EXTRAICONSONMINIMIZED);
3679     }
3680 
3681     CUIFGripper::OnLButtonUp(x, y);
3682     m_pTipbarWnd->UpdatePosFlags();
3683 }
3684 
3685 /// @unimplemented
3686 STDMETHODIMP_(void) CTipbarGripper::OnRButtonUp(LONG x, LONG y)
3687 {
3688     if (g_bShowDebugMenu)
3689     {
3690         // FIXME: Debugging feature
3691     }
3692 }
3693 
3694 STDMETHODIMP_(BOOL) CTipbarGripper::OnSetCursor(UINT uMsg, LONG x, LONG y)
3695 {
3696     if (m_bInDebugMenu)
3697         return FALSE;
3698 
3699     return CUIFGripper::OnSetCursor(uMsg, x, y);
3700 }
3701 
3702 /***********************************************************************
3703  * CTipbarWnd
3704  */
3705 
3706 /// @unimplemented
3707 CTipbarWnd::CTipbarWnd(DWORD style)
3708     : CUIFWindow(g_hInst, style)
3709 {
3710     m_dwUnknown23_1[4] = 0;
3711     m_dwUnknown23_1[5] = 0;
3712     m_dwUnknown23_1[6] = 0;
3713     m_dwUnknown23_1[7] = 0;
3714 
3715     RECT rc;
3716     cicGetScreenRect(g_ptTipbar, &rc);
3717 
3718     //FIXME: Fix g_ptTipbar
3719 
3720     Move(g_ptTipbar.x, g_ptTipbar.y, 100, 24);
3721     UpdatePosFlags();
3722 
3723     m_hMarlettFont = ::CreateFontW(8, 8, 0, 0, FW_NORMAL, 0, 0, 0,
3724                                    SYMBOL_CHARSET, 0, 0, 0, 0, L"Marlett");
3725 
3726     ITfLangBarMgr *pLangBarMgr = NULL;
3727     if (SUCCEEDED(TF_CreateLangBarMgr(&pLangBarMgr)) && pLangBarMgr)
3728     {
3729         pLangBarMgr->QueryInterface(IID_ITfLangBarMgr_P, (void **)&m_pLangBarMgr);
3730         pLangBarMgr->Release();
3731     }
3732 
3733     if (style & UIF_WINDOW_ENABLETHEMED)
3734     {
3735         if (g_fTaskbarTheme)
3736         {
3737             m_iPartId = 1;
3738             m_iStateId = 1;
3739             m_pszClassList = L"TASKBAR";
3740         }
3741         else
3742         {
3743             m_iPartId = 0;
3744             m_iStateId = 1;
3745             m_pszClassList = L"REBAR";
3746         }
3747     }
3748 
3749     SetVertical(g_fVertical);
3750 
3751     m_cRefs = 1;
3752 }
3753 
3754 /// @unimplemented
3755 CTipbarWnd::~CTipbarWnd()
3756 {
3757     UnInit();
3758 
3759     if (m_hMarlettFont)
3760         ::DeleteObject(m_hMarlettFont);
3761     if (m_hTextFont)
3762         ::DeleteObject(m_hTextFont);
3763 
3764     //TFUninitLib_Thread(&g_libTLS); //FIXME
3765 }
3766 
3767 /// @unimplemented
3768 void CTipbarWnd::Init(BOOL bChild, CDeskBand *pDeskBand)
3769 {
3770 }
3771 
3772 void CTipbarWnd::InitHighContrast()
3773 {
3774     m_dwTipbarWndFlags &= ~0x10;
3775 
3776     HIGHCONTRAST HiCon = { sizeof(HiCon) };
3777     if (::SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HiCon), &HiCon, 0))
3778     {
3779         if (HiCon.dwFlags & HCF_HIGHCONTRASTON)
3780             m_dwTipbarWndFlags |= 0x10;
3781     }
3782 }
3783 
3784 void CTipbarWnd::InitMetrics()
3785 {
3786     m_cxSmallIcon = ::GetSystemMetrics(SM_CXSMICON);
3787     m_cySmallIcon = ::GetSystemMetrics(SM_CYSMICON);
3788 
3789     DWORD_PTR style = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
3790     if (style & WS_DLGFRAME)
3791     {
3792         m_cxDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CXDLGFRAME);
3793         m_cyDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CYDLGFRAME);
3794     }
3795     else if (style & WS_BORDER)
3796     {
3797         m_cxDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CXBORDER);
3798         m_cyDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CYBORDER);
3799     }
3800     else
3801     {
3802         m_cxDlgFrameX2 = m_cyDlgFrameX2 = 0;
3803     }
3804 }
3805 
3806 void CTipbarWnd::InitThemeMargins()
3807 {
3808     ZeroMemory(&m_Margins, sizeof(m_Margins));
3809 
3810     CUIFTheme theme;
3811     m_dwUnknown23_5[0] = 6;
3812     m_dwUnknown23_5[1] = 6;
3813     m_dwUnknown23_5[2] = 0;
3814     m_ButtonWidth = GetSystemMetrics(SM_CXSIZE);
3815 
3816     theme.m_iPartId = 1;
3817     theme.m_iStateId = 0;
3818     theme.m_pszClassList = L"TOOLBAR";
3819     if (SUCCEEDED(theme.InternalOpenThemeData(m_hWnd)))
3820     {
3821         ::GetThemeMargins(theme.m_hTheme, NULL, theme.m_iPartId, 1, 3602, NULL, &m_Margins);
3822         m_dwUnknown23_5[0] = 4;
3823         m_dwUnknown23_5[1] = 2;
3824         m_dwUnknown23_5[2] = 1;
3825     }
3826     theme.CloseThemeData();
3827 
3828     theme.m_iPartId = 18;
3829     theme.m_iStateId = 0;
3830     theme.m_pszClassList = L"WINDOW";
3831     if (SUCCEEDED(theme.InternalOpenThemeData(m_hWnd)))
3832     {
3833         SIZE partSize;
3834         ::GetThemePartSize(theme.m_hTheme, NULL, theme.m_iPartId, 1, 0, TS_TRUE, &partSize);
3835         INT size = ::GetThemeSysSize(theme.m_hTheme, 31);
3836         m_ButtonWidth = MulDiv(size, partSize.cx, partSize.cy);
3837     }
3838     theme.CloseThemeData();
3839 }
3840 
3841 /// @unimplemented
3842 void CTipbarWnd::UnInit()
3843 {
3844 }
3845 
3846 BOOL CTipbarWnd::IsFullScreenWindow(HWND hWnd)
3847 {
3848     if (g_fPolicyEnableLanguagebarInFullscreen)
3849         return FALSE;
3850 
3851     DWORD_PTR style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
3852     if (!(style & WS_VISIBLE) || (style & WS_CAPTION))
3853         return FALSE;
3854 
3855     DWORD_PTR exstyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
3856     if (exstyle & WS_EX_LAYERED)
3857         return FALSE;
3858 
3859     if ((exstyle & WS_EX_TOOLWINDOW) && (hWnd == m_ShellWndThread.GetWndProgman()))
3860         return FALSE;
3861 
3862     return !!cicIsFullScreenSize(hWnd);
3863 }
3864 
3865 BOOL CTipbarWnd::IsHKLToSkipRedrawOnNoItem()
3866 {
3867     HKL hKL = GetFocusKeyboardLayout();
3868     return IsSkipRedrawHKL(hKL);
3869 }
3870 
3871 /// @unimplemented
3872 BOOL CTipbarWnd::IsInItemChangeOrDirty(CTipbarThread *pTarget)
3873 {
3874     return FALSE;
3875 }
3876 
3877 void CTipbarWnd::AddThreadToThreadCreatingList(CTipbarThread *pThread)
3878 {
3879     m_ThreadCreatingList.Add(pThread);
3880 }
3881 
3882 void CTipbarWnd::RemoveThredFromThreadCreatingList(CTipbarThread *pTarget)
3883 {
3884     ssize_t iItem = m_ThreadCreatingList.Find(pTarget);
3885     if (iItem >= 0)
3886         m_ThreadCreatingList.Remove(iItem);
3887 }
3888 
3889 /// @unimplemented
3890 void CTipbarWnd::MoveToStub(BOOL bFlag)
3891 {
3892 }
3893 
3894 void CTipbarWnd::RestoreFromStub()
3895 {
3896     m_dwTipbarWndFlags &= 0x3F;
3897     KillTimer(1);
3898     KillTimer(2);
3899 }
3900 
3901 /// @unimplemented
3902 INT CTipbarWnd::GetCtrlButtonWidth()
3903 {
3904     return 0;
3905 }
3906 
3907 INT CTipbarWnd::GetGripperWidth()
3908 {
3909     if (m_dwTipbarWndFlags & 2)
3910         return 0;
3911 
3912     if (!m_pTipbarGripper || FAILED(m_pTipbarGripper->EnsureThemeData(m_hWnd)))
3913         return 5;
3914 
3915     INT width = -1;
3916     SIZE partSize;
3917     HDC hDC = ::GetDC(m_hWnd);
3918     if (SUCCEEDED(m_pTipbarGripper->GetThemePartSize(hDC, 1, 0, TS_TRUE, &partSize)))
3919     {
3920         INT cx = partSize.cx;
3921         if (m_dwTipbarWndFlags & 4)
3922             cx = partSize.cy;
3923         width = cx + 4;
3924     }
3925     ::ReleaseDC(m_hWnd, hDC);
3926 
3927     return ((width < 0) ? 5 : width);
3928 }
3929 
3930 INT CTipbarWnd::GetTipbarHeight()
3931 {
3932     SIZE size = { 0, 0 };
3933     if (m_pWndFrame)
3934         m_pWndFrame->GetFrameSize(&size);
3935     INT cy = m_Margins.cyBottomHeight + m_Margins.cyTopHeight + 2;
3936     if (cy < 6)
3937         cy = 6;
3938     return m_cySmallIcon + cy + (2 * size.cy);
3939 }
3940 
3941 /// @unimplemented
3942 BOOL CTipbarWnd::AutoAdjustDeskBandSize()
3943 {
3944     return FALSE;
3945 }
3946 
3947 /// @unimplemented
3948 INT CTipbarWnd::AdjustDeskBandSize(BOOL bFlag)
3949 {
3950     return 0;
3951 }
3952 
3953 /// @unimplemented
3954 void CTipbarWnd::LocateCtrlButtons()
3955 {
3956 }
3957 
3958 void CTipbarWnd::AdjustPosOnDisplayChange()
3959 {
3960     RECT rcWorkArea;
3961     RECT rc = { m_nLeft, m_nTop, m_nLeft + m_nWidth, m_nTop + m_nHeight };
3962     if (!GetWorkArea(&rc, &rcWorkArea))
3963         return;
3964 
3965     INT x = m_nLeft, y = m_nTop;
3966     if (m_dwTipbarWndFlags & 0x200000)
3967         x = rcWorkArea.left;
3968     if (m_dwTipbarWndFlags & 0x40000)
3969         y = rcWorkArea.top;
3970     if (m_dwTipbarWndFlags & 0x100000)
3971         x = rcWorkArea.right - m_nWidth;
3972     if (m_dwTipbarWndFlags & 0x80000)
3973         y = rcWorkArea.bottom - m_nHeight;
3974     if (x != m_nLeft || y != m_nTop)
3975         Move(x, y, m_nWidth, m_nHeight);
3976 }
3977 
3978 void CTipbarWnd::SetVertical(BOOL bVertical)
3979 {
3980     if (bVertical)
3981         m_dwTipbarWndFlags |= 0x4;
3982     else
3983         m_dwTipbarWndFlags &= ~0x4;
3984 
3985     if (m_pTipbarGripper)
3986     {
3987         DWORD style = m_pTipbarGripper->m_style;
3988         if (bVertical)
3989             style |= 0x1;
3990         else
3991             style &= 0x1;
3992         m_pTipbarGripper->SetStyle(style);
3993     }
3994 
3995     if (g_fTaskbarTheme)
3996         SetActiveTheme(L"TASKBAR", !!(m_dwTipbarWndFlags & 0x4), 1);
3997 
3998     if (!(m_dwTipbarWndFlags & 2))
3999     {
4000         if (m_dwTipbarWndFlags & 4)
4001         {
4002             Move(m_nLeft, m_nTop, GetTipbarHeight(), 0);
4003         }
4004         else
4005         {
4006             Move(m_nLeft, m_nTop, 0, GetTipbarHeight());
4007         }
4008     }
4009 
4010     if (m_hWnd)
4011     {
4012         KillTimer(7);
4013         SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4014     }
4015 }
4016 
4017 void CTipbarWnd::UpdatePosFlags()
4018 {
4019     if (m_dwTipbarWndFlags & 0x2)
4020         return;
4021 
4022     RECT rc = { m_nLeft, m_nTop, m_nLeft + m_nWidth, m_nTop + m_nHeight }, rcWorkArea;
4023     if (!GetWorkArea(&rc, &rcWorkArea))
4024         return;
4025 
4026     if (m_nLeft > rcWorkArea.left + 2)
4027         m_dwTipbarWndFlags &= ~0x200000;
4028     else
4029         m_dwTipbarWndFlags |= 0x200000;
4030 
4031     if ( m_nTop> rcWorkArea.top + 2 )
4032         m_dwTipbarWndFlags &= ~0x40000;
4033     else
4034         m_dwTipbarWndFlags |= 0x40000;
4035 
4036     if (m_nLeft + m_nWidth < rcWorkArea.right - 2)
4037         m_dwTipbarWndFlags &= ~0x100000;
4038     else
4039         m_dwTipbarWndFlags |= 0x100000;
4040 
4041     if (m_nTop + m_nHeight < rcWorkArea.bottom - 2)
4042         m_dwTipbarWndFlags &= ~0x80000;
4043     else
4044         m_dwTipbarWndFlags |= 0x80000;
4045 }
4046 
4047 /// @unimplemented
4048 void CTipbarWnd::CancelMenu()
4049 {
4050 }
4051 
4052 BOOL CTipbarWnd::CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT prc2)
4053 {
4054     return (prc1->top < prc2->top + 5) && (prc2->right <= prc1->right + (5 * m_ButtonWidth));
4055 }
4056 
4057 /// @unimplemented
4058 void CTipbarWnd::ClearLBItemList()
4059 {
4060 }
4061 
4062 HFONT CTipbarWnd::CreateVerticalFont()
4063 {
4064     if (!m_hWnd)
4065         return NULL;
4066 
4067     CUIFTheme theme;
4068     theme.m_iPartId = 1;
4069     theme.m_iStateId = 0;
4070     theme.m_pszClassList = L"TOOLBAR";
4071 
4072     LOGFONTW lf;
4073     if (FAILED(theme.InternalOpenThemeData(m_hWnd)) ||
4074         FAILED(::GetThemeFont(theme.m_hTheme, NULL, theme.m_iPartId, 0, 210, &lf)))
4075     {
4076         ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
4077     }
4078 
4079     lf.lfEscapement = lf.lfOrientation = 2700;
4080     lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4081 
4082     if (CheckEAFonts())
4083     {
4084         WCHAR szText[LF_FACESIZE];
4085         szText[0] = L'@';
4086         StringCchCopyW(&szText[1], _countof(szText) - 1, lf.lfFaceName);
4087         StringCchCopyW(lf.lfFaceName, _countof(lf.lfFaceName), szText);
4088     }
4089 
4090     return ::CreateFontIndirectW(&lf);
4091 }
4092 
4093 void CTipbarWnd::UpdateVerticalFont()
4094 {
4095     if (m_dwTipbarWndFlags & 4)
4096     {
4097         if (m_hTextFont)
4098         {
4099             ::DeleteObject(m_hTextFont);
4100             SetFontToThis(NULL);
4101             m_hTextFont = NULL;
4102         }
4103         m_hTextFont = CreateVerticalFont();
4104         SetFontToThis(m_hTextFont);
4105     }
4106     else
4107     {
4108         SetFontToThis(NULL);
4109     }
4110 }
4111 
4112 /// @unimplemented
4113 void CTipbarWnd::ShowOverScreenSizeBalloon()
4114 {
4115 }
4116 
4117 void CTipbarWnd::DestroyOverScreenSizeBalloon()
4118 {
4119     if (m_pBalloon)
4120     {
4121         if (::IsWindow(*m_pBalloon))
4122             ::DestroyWindow(*m_pBalloon);
4123         delete m_pBalloon;
4124         m_pBalloon = NULL;
4125     }
4126 }
4127 
4128 void CTipbarWnd::DestroyWnd()
4129 {
4130     if (::IsWindow(m_hWnd))
4131         ::DestroyWindow(m_hWnd);
4132 }
4133 
4134 /// @unimplemented
4135 HKL CTipbarWnd::GetFocusKeyboardLayout()
4136 {
4137     return NULL;
4138 }
4139 
4140 /// @unimplemented
4141 void CTipbarWnd::KillOnTheadItemChangeTimer()
4142 {
4143 }
4144 
4145 UINT_PTR CTipbarWnd::SetTimer(UINT_PTR nIDEvent, UINT uElapse)
4146 {
4147     if (::IsWindow(m_hWnd))
4148         return ::SetTimer(m_hWnd, nIDEvent, uElapse, NULL);
4149     return 0;
4150 }
4151 
4152 BOOL CTipbarWnd::KillTimer(UINT_PTR uIDEvent)
4153 {
4154     if (::IsWindow(m_hWnd))
4155         return ::KillTimer(m_hWnd, uIDEvent);
4156     return FALSE;
4157 }
4158 
4159 /// @unimplemented
4160 void CTipbarWnd::MoveToTray()
4161 {
4162 }
4163 
4164 void CTipbarWnd::MyClientToScreen(LPPOINT lpPoint, LPRECT prc)
4165 {
4166     if (lpPoint)
4167         ::ClientToScreen(m_hWnd, lpPoint);
4168 
4169     if (prc)
4170     {
4171         ::ClientToScreen(m_hWnd, (LPPOINT)prc);
4172         ::ClientToScreen(m_hWnd, (LPPOINT)&prc->right);
4173     }
4174 }
4175 
4176 void CTipbarWnd::SavePosition()
4177 {
4178     CicRegKey regKey;
4179     if (regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\")))
4180     {
4181         POINT pt = { 0, 0 };
4182         ::ClientToScreen(m_hWnd, &pt);
4183         regKey.SetDword(TEXT("Left"), pt.x);
4184         regKey.SetDword(TEXT("Top"), pt.y);
4185         regKey.SetDword(TEXT("Vertical"), !!(m_dwTipbarWndFlags & 4));
4186     }
4187 }
4188 
4189 /// @unimplemented
4190 void CTipbarWnd::SetAlpha(BYTE bAlpha, BOOL bFlag)
4191 {
4192 }
4193 
4194 BOOL CTipbarWnd::SetLangBand(BOOL bDeskBand, BOOL bFlag2)
4195 {
4196     if (bDeskBand == !!(m_dwShowType & TF_SFT_DESKBAND))
4197         return TRUE;
4198 
4199     BOOL ret = TRUE;
4200     HWND hwndTray = m_ShellWndThread.GetWndTray();
4201     if (bFlag2 && hwndTray)
4202     {
4203         DWORD_PTR dwResult;
4204         HWND hImeWnd = ::ImmGetDefaultIMEWnd(hwndTray);
4205         if (hImeWnd)
4206             ::SendMessageTimeout(hImeWnd, WM_IME_SYSTEM, 0x24 - bDeskBand, (LPARAM)hwndTray,
4207                                  (SMTO_BLOCK | SMTO_ABORTIFHUNG), 5000, &dwResult);
4208         else
4209             ::SendMessageTimeout(hwndTray, 0x505, 0, bDeskBand,
4210                                  (SMTO_BLOCK | SMTO_ABORTIFHUNG), 5000, &dwResult);
4211     }
4212     else
4213     {
4214         ret = FALSE;
4215     }
4216 
4217     if (!(m_dwTipbarWndFlags & 2))
4218     {
4219         if (bDeskBand)
4220         {
4221             KillTimer(7);
4222             SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4223         }
4224     }
4225 
4226     return ret;
4227 }
4228 
4229 void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight)
4230 {
4231     if (m_dwTipbarWndFlags & 0x2)
4232     {
4233         m_nWidth = nWidth;
4234         m_nHeight = nHeight;
4235         return;
4236     }
4237 
4238     ++m_bInCallOn;
4239 
4240     m_dwTipbarWndFlags |= 0x400;
4241 
4242     m_X = X;
4243     m_Y = Y;
4244     m_CX = nWidth;
4245     m_CY = nHeight;
4246 
4247     RECT rc;
4248     SIZE size = { 0, 0 };
4249     if (m_pWndFrame)
4250     {
4251         ::SetRect(&rc, 0, 0, nWidth - m_cxDlgFrameX2, nHeight - m_cyDlgFrameX2);
4252         m_pWndFrame->SetRect(&rc);
4253         m_pWndFrame->GetFrameSize(&size);
4254     }
4255 
4256     if (m_pTipbarGripper)
4257     {
4258         if (m_dwTipbarWndFlags & 4)
4259         {
4260             INT GripperWidth = GetGripperWidth();
4261             ::SetRect(&rc, size.cx, size.cy, nWidth - m_cxDlgFrameX2 - size.cx, size.cy + GripperWidth);
4262         }
4263         else
4264         {
4265             INT GripperWidth = GetGripperWidth();
4266             INT y1 = nHeight - m_cyDlgFrameX2 - size.cy;
4267             ::SetRect(&rc, size.cx, size.cy, size.cx + GripperWidth, y1);
4268         }
4269         m_pTipbarGripper->SetRect(&rc);
4270     }
4271 
4272     --m_bInCallOn;
4273 }
4274 
4275 /// @unimplemented
4276 void CTipbarWnd::SetShowText(BOOL bShow)
4277 {
4278 }
4279 
4280 void CTipbarWnd::SetShowTrayIcon(BOOL bShow)
4281 {
4282     if (m_dwTipbarWndFlags & 0x20)
4283         m_dwTipbarWndFlags &= ~0x20;
4284     else
4285         m_dwTipbarWndFlags |= 0x20;
4286 
4287     if ((m_dwTipbarWndFlags & 0x20) && m_pFocusThread)
4288     {
4289         KillTimer(10);
4290         SetTimer(10, g_uTimerElapseMOVETOTRAY);
4291     }
4292     else if (g_pTrayIconWnd)
4293     {
4294         g_pTrayIconWnd->SetMainIcon(NULL);
4295         g_pTrayIconWnd->RemoveAllIcon(0);
4296     }
4297 }
4298 
4299 /// @unimplemented
4300 void CTipbarWnd::ShowContextMenu(POINT pt, LPCRECT prc, BOOL bFlag)
4301 {
4302 }
4303 
4304 void CTipbarWnd::StartBackToAlphaTimer()
4305 {
4306     UINT uTime = ::GetDoubleClickTime();
4307     ::SetTimer(m_hWnd, 3, 3 * uTime, NULL);
4308 }
4309 
4310 /// @unimplemented
4311 BOOL CTipbarWnd::StartDoAccDefaultActionTimer(CTipbarItem *pTarget)
4312 {
4313     return FALSE;
4314 }
4315 
4316 void CTipbarWnd::StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId)
4317 {
4318     if (!m_pLangBarMgr)
4319         return;
4320 
4321     m_pLangBarMgr->SetModalInput(pSink, dwThreadId, 0);
4322     if (g_pTrayIconWnd)
4323         m_pLangBarMgr->SetModalInput(pSink, g_pTrayIconWnd->m_dwTrayWndThreadId, 0);
4324 
4325     DWORD dwCurThreadId = ::GetCurrentThreadId();
4326     m_pLangBarMgr->SetModalInput(pSink, dwCurThreadId, 1);
4327 }
4328 
4329 void CTipbarWnd::StopModalInput(DWORD dwThreadId)
4330 {
4331     if (!m_pLangBarMgr)
4332         return;
4333 
4334     m_pLangBarMgr->SetModalInput(NULL, dwThreadId, 0);
4335     if (g_pTrayIconWnd)
4336         m_pLangBarMgr->SetModalInput(NULL, g_pTrayIconWnd->m_dwTrayWndThreadId, 0);
4337 
4338     DWORD dwCurThreadId = ::GetCurrentThreadId();
4339     m_pLangBarMgr->SetModalInput(NULL, dwCurThreadId, 0);
4340 }
4341 
4342 /// @unimplemented
4343 CTipbarThread *CTipbarWnd::_CreateThread(DWORD dwThreadId)
4344 {
4345     return NULL;
4346 }
4347 
4348 /// @unimplemented
4349 CTipbarThread *CTipbarWnd::_FindThread(DWORD dwThreadId)
4350 {
4351     return NULL;
4352 }
4353 
4354 void CTipbarWnd::EnsureFocusThread()
4355 {
4356     if (m_pFocusThread)
4357         return;
4358 
4359     if (m_dwTipbarWndFlags & 0x12000)
4360         return;
4361 
4362     m_dwTipbarWndFlags |= 0x2000;
4363 
4364     HWND hwndFore = ::GetForegroundWindow();
4365     if (!hwndFore)
4366         return;
4367 
4368     DWORD dwThreadId = ::GetWindowThreadProcessId(hwndFore, NULL);
4369     if (dwThreadId)
4370         OnSetFocus(dwThreadId);
4371 
4372     m_dwTipbarWndFlags &= ~0x2000;
4373 }
4374 
4375 /// @unimplemented
4376 HRESULT CTipbarWnd::SetFocusThread(CTipbarThread *pFocusThread)
4377 {
4378     return E_NOTIMPL;
4379 }
4380 
4381 /// @unimplemented
4382 HRESULT CTipbarWnd::AttachFocusThread()
4383 {
4384     return E_NOTIMPL;
4385 }
4386 
4387 void CTipbarWnd::RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev)
4388 {
4389     if (m_pLangBarMgr)
4390         m_pLangBarMgr->RestoreLastFocus(pdwThreadId, fPrev);
4391 }
4392 
4393 void CTipbarWnd::CleanUpThreadPointer(CTipbarThread *pThread, BOOL bRemove)
4394 {
4395     if (bRemove)
4396     {
4397         ssize_t iItem = m_Threads.Find(pThread);
4398         if (iItem >= 0)
4399             m_Threads.Remove(iItem);
4400     }
4401 
4402     if (pThread == m_pFocusThread)
4403         SetFocusThread(NULL);
4404 
4405     if (pThread == m_pThread)
4406         m_pThread = NULL;
4407 
4408     if (pThread == m_pUnknownThread)
4409         m_pUnknownThread = NULL;
4410 }
4411 
4412 /// @unimplemented
4413 void CTipbarWnd::TerminateAllThreads(BOOL bFlag)
4414 {
4415 }
4416 
4417 STDMETHODIMP CTipbarWnd::QueryInterface(REFIID riid, void **ppvObj)
4418 {
4419     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfLangBarEventSink))
4420     {
4421         *ppvObj = this;
4422         AddRef();
4423         return S_OK;
4424     }
4425     if (IsEqualIID(riid, IID_ITfLangBarEventSink_P))
4426     {
4427         *ppvObj = static_cast<ITfLangBarEventSink_P*>(this);
4428         AddRef();
4429         return S_OK;
4430     }
4431     return E_NOINTERFACE;
4432 }
4433 
4434 STDMETHODIMP_(ULONG) CTipbarWnd::AddRef()
4435 {
4436     return ++m_cRefs;
4437 }
4438 
4439 STDMETHODIMP_(ULONG) CTipbarWnd::Release()
4440 {
4441     if (--m_cRefs == 0)
4442     {
4443         delete this;
4444         return 0;
4445     }
4446     return m_cRefs;
4447 }
4448 
4449 /// @unimplemented
4450 STDMETHODIMP CTipbarWnd::OnSetFocus(DWORD dwThreadId)
4451 {
4452     return E_NOTIMPL;
4453 }
4454 
4455 STDMETHODIMP CTipbarWnd::OnThreadTerminate(DWORD dwThreadId)
4456 {
4457     HRESULT hr;
4458     ++m_bInCallOn;
4459     AddRef();
4460     {
4461         hr = OnThreadTerminateInternal(dwThreadId);
4462         if (!m_pFocusThread)
4463             EnsureFocusThread();
4464     }
4465     --m_bInCallOn;
4466     Release();
4467     return hr;
4468 }
4469 
4470 /// @unimplemented
4471 HRESULT CTipbarWnd::OnThreadTerminateInternal(DWORD dwThreadId)
4472 {
4473     return E_NOTIMPL;
4474 }
4475 
4476 /// @unimplemented
4477 STDMETHODIMP CTipbarWnd::OnThreadItemChange(DWORD dwThreadId)
4478 {
4479     return E_NOTIMPL;
4480 }
4481 
4482 STDMETHODIMP CTipbarWnd::OnModalInput(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam)
4483 {
4484     switch (uMsg)
4485     {
4486         case WM_NCLBUTTONDOWN:
4487         case WM_NCRBUTTONDOWN:
4488         case WM_NCMBUTTONDOWN:
4489         case WM_LBUTTONUP:
4490         case WM_RBUTTONUP:
4491         case WM_MBUTTONUP:
4492             break;
4493 
4494         case WM_NCLBUTTONUP:
4495         case WM_NCRBUTTONUP:
4496         case WM_NCMBUTTONUP:
4497             if (m_pThread)
4498             {
4499                 CUTBMenuWnd *pMenuUI = m_pModalMenu->m_pMenuUI;
4500                 if (pMenuUI)
4501                 {
4502                     HWND hWnd = *pMenuUI;
4503                     if (hWnd)
4504                     {
4505                         POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) };
4506                         ::ScreenToClient(hWnd, &pt);
4507                         uMsg += WM_LBUTTONUP - WM_NCLBUTTONUP;
4508                         ::PostMessage(m_hWnd, uMsg, wParam, MAKELPARAM(pt.x, pt.y));
4509                     }
4510                 }
4511             }
4512             break;
4513 
4514         default:
4515         {
4516             if (uMsg == WM_KEYDOWN || uMsg == WM_KEYUP)
4517             {
4518                 if (m_pThread)
4519                     m_pModalMenu->PostKey(uMsg == WM_KEYUP, wParam, lParam);
4520             }
4521             else
4522             {
4523                 CancelMenu();
4524             }
4525             break;
4526         }
4527     }
4528 
4529     return 0;
4530 }
4531 
4532 /// @unimplemented
4533 STDMETHODIMP CTipbarWnd::ShowFloating(DWORD dwFlags)
4534 {
4535     return E_NOTIMPL;
4536 }
4537 
4538 /// @unimplemented
4539 STDMETHODIMP CTipbarWnd::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
4540 {
4541     return E_NOTIMPL;
4542 }
4543 
4544 /// @unimplemented
4545 STDMETHODIMP CTipbarWnd::OnLangBarUpdate(TfLBIClick click, BOOL bFlag)
4546 {
4547     return E_NOTIMPL;
4548 }
4549 
4550 STDMETHODIMP_(BSTR) CTipbarWnd::GetAccName()
4551 {
4552     WCHAR szText[256];
4553     ::LoadStringW(g_hInst, IDS_LANGUAGEBAR, szText, _countof(szText));
4554     return ::SysAllocString(szText);
4555 }
4556 
4557 STDMETHODIMP_(void) CTipbarWnd::GetAccLocation(LPRECT lprc)
4558 {
4559     GetRect(lprc);
4560 }
4561 
4562 /// @unimplemented
4563 STDMETHODIMP_(void) CTipbarWnd::PaintObject(HDC hDC, LPCRECT prc)
4564 {
4565 }
4566 
4567 STDMETHODIMP_(DWORD) CTipbarWnd::GetWndStyle()
4568 {
4569     return CUIFWindow::GetWndStyle() & ~WS_BORDER;
4570 }
4571 
4572 STDMETHODIMP_(void) CTipbarWnd::Move(INT x, INT y, INT nWidth, INT nHeight)
4573 {
4574     CUIFWindow::Move(x, y, nWidth, nHeight);
4575 }
4576 
4577 STDMETHODIMP_(void) CTipbarWnd::OnMouseOutFromWindow(LONG x, LONG y)
4578 {
4579     StartBackToAlphaTimer();
4580     if ((m_dwTipbarWndFlags & 0x40) && (m_dwTipbarWndFlags & 0x80))
4581         SetTimer(2, g_uTimerElapseSTUBEND);
4582 }
4583 
4584 /// @unimplemented
4585 STDMETHODIMP_(void) CTipbarWnd::OnCreate(HWND hWnd)
4586 {
4587 }
4588 
4589 STDMETHODIMP_(void) CTipbarWnd::OnDestroy(HWND hWnd)
4590 {
4591     CancelMenu();
4592 
4593     if (m_pTipbarAccessible)
4594         m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_DESTROY, GetAccItem());
4595 
4596     OnTerminateToolbar();
4597     if (m_pTipbarAccessible)
4598     {
4599         m_pTipbarAccessible->ClearAccItems();
4600         m_pTipbarAccessible->Release();
4601         m_pTipbarAccessible = NULL;
4602     }
4603 
4604     m_coInit.CoUninit();
4605 
4606     if (m_pLangBarMgr)
4607         m_pLangBarMgr->UnAdviseEventSink(m_dwSinkCookie);
4608 }
4609 
4610 /// @unimplemented
4611 STDMETHODIMP_(void) CTipbarWnd::OnTimer(WPARAM wParam)
4612 {
4613 }
4614 
4615 STDMETHODIMP_(void) CTipbarWnd::OnSysColorChange()
4616 {
4617     KillTimer(7);
4618     SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4619 }
4620 
4621 void CTipbarWnd::OnTerminateToolbar()
4622 {
4623     m_dwTipbarWndFlags |= 0x10000;
4624     DestroyOverScreenSizeBalloon();
4625     TerminateAllThreads(TRUE);
4626     if (!(m_dwTipbarWndFlags & 0x2))
4627         SavePosition();
4628 }
4629 
4630 STDMETHODIMP_(void) CTipbarWnd::OnEndSession(HWND hWnd, WPARAM wParam, LPARAM lParam)
4631 {
4632     if (!g_bWinLogon)
4633         OnTerminateToolbar();
4634 
4635     if (wParam) // End session?
4636     {
4637         if (lParam & ENDSESSION_LOGOFF)
4638         {
4639             KillTimer(9);
4640             Show(FALSE);
4641         }
4642         else
4643         {
4644             OnTerminateToolbar();
4645 
4646             AddRef();
4647             ::DestroyWindow(hWnd);
4648             Release();
4649         }
4650     }
4651 }
4652 
4653 STDMETHODIMP_(void) CTipbarWnd::OnUser(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4654 {
4655     if (uMsg == WM_USER + 1)
4656     {
4657         POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) };
4658         ::ClientToScreen(m_hWnd, &pt);
4659         ShowContextMenu(pt, NULL, TRUE);
4660     }
4661     else if (uMsg == g_wmTaskbarCreated)
4662     {
4663         m_ShellWndThread.clear();
4664     }
4665 }
4666 
4667 /// @unimplemented
4668 STDMETHODIMP_(LRESULT)
4669 CTipbarWnd::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4670 {
4671     return 0;
4672 }
4673 
4674 STDMETHODIMP_(LRESULT)
4675 CTipbarWnd::OnWindowPosChanging(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4676 {
4677     LPWINDOWPOS pWP = (LPWINDOWPOS)lParam;
4678     if (!(pWP->flags & SWP_NOZORDER))
4679     {
4680         if (!m_pThread && (!m_pToolTip || !m_pToolTip->m_bShowToolTip))
4681             pWP->hwndInsertAfter = NULL;
4682     }
4683     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
4684 }
4685 
4686 STDMETHODIMP_(LRESULT)
4687 CTipbarWnd::OnShowWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4688 {
4689     if (m_pTipbarAccessible)
4690     {
4691         if (wParam) // Show?
4692         {
4693             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_SHOW, GetAccItem());
4694             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_FOCUS, GetAccItem());
4695         }
4696         else
4697         {
4698             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_HIDE, GetAccItem());
4699         }
4700     }
4701     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
4702 }
4703 
4704 STDMETHODIMP_(LRESULT)
4705 CTipbarWnd::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4706 {
4707     if (!wParam || wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETHIGHCONTRAST)
4708     {
4709         KillTimer(7);
4710         SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4711     }
4712     return 0;
4713 }
4714 
4715 STDMETHODIMP_(LRESULT)
4716 CTipbarWnd::OnDisplayChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4717 {
4718     if (!(m_dwTipbarWndFlags & 2))
4719     {
4720         KillTimer(12);
4721         SetTimer(12, g_uTimerElapseDISPLAYCHANGE);
4722     }
4723     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
4724 }
4725 
4726 STDMETHODIMP_(HRESULT)
4727 CTipbarWnd::OnGetObject(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4728 {
4729     if (lParam != -4)
4730         return S_OK;
4731     if (!m_pTipbarAccessible)
4732         return E_OUTOFMEMORY;
4733 
4734     if (m_pTipbarAccessible->m_bInitialized)
4735         return m_pTipbarAccessible->CreateRefToAccObj(wParam);
4736 
4737     HRESULT hr = S_OK;
4738     if (SUCCEEDED(m_coInit.EnsureCoInit()))
4739     {
4740         hr = m_pTipbarAccessible->Initialize();
4741         if (FAILED(hr))
4742         {
4743             m_pTipbarAccessible->Release();
4744             m_pTipbarAccessible = NULL;
4745             return hr;
4746         }
4747 
4748         m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_CREATE, GetAccItem());
4749         return m_pTipbarAccessible->CreateRefToAccObj(wParam);
4750     }
4751 
4752     return hr;
4753 }
4754 
4755 STDMETHODIMP_(BOOL) CTipbarWnd::OnEraseBkGnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4756 {
4757     return TRUE;
4758 }
4759 
4760 STDMETHODIMP_(void) CTipbarWnd::OnThemeChanged(HWND hWnd, WPARAM wParam, LPARAM lParam)
4761 {
4762     CUIFWindow::OnThemeChanged(hWnd, wParam, lParam);
4763 }
4764 
4765 /// @unimplemented
4766 STDMETHODIMP_(void) CTipbarWnd::UpdateUI(LPCRECT prc)
4767 {
4768 }
4769 
4770 /// @unimplemented
4771 STDMETHODIMP_(void) CTipbarWnd::HandleMouseMsg(UINT uMsg, LONG x, LONG y)
4772 {
4773 }
4774 
4775 /***********************************************************************
4776  *              GetTipbarInternal
4777  */
4778 BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand *pDeskBand)
4779 {
4780     BOOL bParent = !!(dwFlags & 0x80000000);
4781     g_bWinLogon = !!(dwFlags & 0x1);
4782 
4783     InitFromReg();
4784 
4785     if (!g_bShowTipbar)
4786         return FALSE;
4787 
4788     if (bParent)
4789     {
4790         g_pTrayIconWnd = new(cicNoThrow) CTrayIconWnd();
4791         if (!g_pTrayIconWnd)
4792             return FALSE;
4793         g_pTrayIconWnd->CreateWnd();
4794     }
4795 
4796     g_pTipbarWnd = new(cicNoThrow) CTipbarWnd(bParent ? g_dwWndStyle : g_dwChildWndStyle);
4797     if (!g_pTipbarWnd || !g_pTipbarWnd->Initialize())
4798         return FALSE;
4799 
4800     g_pTipbarWnd->Init(!bParent, pDeskBand);
4801     g_pTipbarWnd->CreateWnd(hWnd);
4802 
4803     ::SetWindowText(*g_pTipbarWnd, TEXT("TF_FloatingLangBar_WndTitle"));
4804 
4805     DWORD dwOldStatus = 0;
4806     if (!bParent)
4807     {
4808         g_pTipbarWnd->m_pLangBarMgr->GetPrevShowFloatingStatus(&dwOldStatus);
4809         g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND);
4810     }
4811 
4812     DWORD dwStatus;
4813     g_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus);
4814     g_pTipbarWnd->ShowFloating(dwStatus);
4815 
4816     if (!bParent && (dwOldStatus & TF_SFT_DESKBAND))
4817         g_pTipbarWnd->m_dwTipbarWndFlags |= 0x4000;
4818 
4819     g_hwndParent = hWnd;
4820     return TRUE;
4821 }
4822 
4823 /***********************************************************************
4824  *              GetLibTls (MSUTB.@)
4825  *
4826  * @unimplemented
4827  */
4828 EXTERN_C LPVOID WINAPI
4829 GetLibTls(VOID)
4830 {
4831     FIXME("stub:()\n");
4832     return NULL;
4833 }
4834 
4835 /***********************************************************************
4836  *              GetPopupTipbar (MSUTB.@)
4837  *
4838  * @implemented
4839  */
4840 EXTERN_C BOOL WINAPI
4841 GetPopupTipbar(HWND hWnd, BOOL fWinLogon)
4842 {
4843     TRACE("(%p, %d)\n", hWnd, fWinLogon);
4844 
4845     if (!fWinLogon)
4846         TurnOffSpeechIfItsOn();
4847 
4848     return GetTipbarInternal(hWnd, fWinLogon | 0x80000000, NULL);
4849 }
4850 
4851 /***********************************************************************
4852  *              SetRegisterLangBand (MSUTB.@)
4853  *
4854  * @implemented
4855  */
4856 EXTERN_C HRESULT WINAPI
4857 SetRegisterLangBand(BOOL bRegister)
4858 {
4859     TRACE("(%d)\n", bRegister);
4860 
4861     if (!(g_dwOSInfo & CIC_OSINFO_XPPLUS)) // Desk band is for XP+
4862         return E_FAIL;
4863 
4864     BOOL bDeskBand = IsDeskBandFromReg();
4865     if (bDeskBand == bRegister)
4866         return S_OK;
4867 
4868     SetDeskBandToReg(bRegister);
4869 
4870     if (!RegisterComCat(CLSID_MSUTBDeskBand, CATID_DeskBand, bRegister))
4871         return TF_E_NOLOCK;
4872 
4873     return S_OK;
4874 }
4875 
4876 /***********************************************************************
4877  *              ClosePopupTipbar (MSUTB.@)
4878  *
4879  * @implemented
4880  */
4881 EXTERN_C VOID WINAPI
4882 ClosePopupTipbar(VOID)
4883 {
4884     TRACE("()\n");
4885 
4886     if (g_fInClosePopupTipbar)
4887         return;
4888 
4889     g_fInClosePopupTipbar = TRUE;
4890 
4891     if (g_pTipbarWnd)
4892     {
4893         g_pTipbarWnd->m_pDeskBand = NULL;
4894         g_pTipbarWnd->DestroyWnd();
4895         g_pTipbarWnd->Release();
4896         g_pTipbarWnd = NULL;
4897     }
4898 
4899     if (g_pTrayIconWnd)
4900     {
4901         g_pTrayIconWnd->DestroyWnd();
4902         delete g_pTrayIconWnd;
4903         g_pTrayIconWnd = NULL;
4904     }
4905 
4906     UninitSkipRedrawHKLArray();
4907 
4908     g_fInClosePopupTipbar = FALSE;
4909 }
4910 
4911 /***********************************************************************
4912  *              DllRegisterServer (MSUTB.@)
4913  *
4914  * @implemented
4915  */
4916 STDAPI DllRegisterServer(VOID)
4917 {
4918     TRACE("()\n");
4919     return gModule.DllRegisterServer(FALSE);
4920 }
4921 
4922 /***********************************************************************
4923  *              DllUnregisterServer (MSUTB.@)
4924  *
4925  * @implemented
4926  */
4927 STDAPI DllUnregisterServer(VOID)
4928 {
4929     TRACE("()\n");
4930     return gModule.DllUnregisterServer(FALSE);
4931 }
4932 
4933 /***********************************************************************
4934  *              DllCanUnloadNow (MSUTB.@)
4935  *
4936  * @implemented
4937  */
4938 STDAPI DllCanUnloadNow(VOID)
4939 {
4940     TRACE("()\n");
4941     return gModule.DllCanUnloadNow() && (g_DllRefCount == 0);
4942 }
4943 
4944 /***********************************************************************
4945  *              DllGetClassObject (MSUTB.@)
4946  *
4947  * @implemented
4948  */
4949 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4950 {
4951     TRACE("()\n");
4952     return gModule.DllGetClassObject(rclsid, riid, ppv);
4953 }
4954 
4955 /// @implemented
4956 HRESULT APIENTRY
4957 MsUtbCoCreateInstance(
4958     REFCLSID rclsid,
4959     LPUNKNOWN pUnkOuter,
4960     DWORD dwClsContext,
4961     REFIID iid,
4962     LPVOID *ppv)
4963 {
4964     if (IsEqualCLSID(rclsid, CLSID_TF_CategoryMgr))
4965         return TF_CreateCategoryMgr((ITfCategoryMgr**)ppv);
4966     if (IsEqualCLSID(rclsid, CLSID_TF_DisplayAttributeMgr))
4967         return TF_CreateDisplayAttributeMgr((ITfDisplayAttributeMgr **)ppv);
4968     return cicRealCoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
4969 }
4970 
4971 /// @implemented
4972 BOOL ProcessAttach(HINSTANCE hinstDLL)
4973 {
4974     ::InitializeCriticalSectionAndSpinCount(&g_cs, 0);
4975 
4976     g_hInst = hinstDLL;
4977 
4978     cicGetOSInfo(&g_uACP, &g_dwOSInfo);
4979 
4980     TFInitLib(MsUtbCoCreateInstance);
4981     cicInitUIFLib();
4982 
4983     CTrayIconWnd::RegisterClass();
4984 
4985     g_wmTaskbarCreated = RegisterWindowMessageW(L"TaskbarCreated");
4986 
4987     gModule.Init(ObjectMap, hinstDLL, NULL);
4988     ::DisableThreadLibraryCalls(hinstDLL);
4989 
4990     return TRUE;
4991 }
4992 
4993 /// @implemented
4994 VOID ProcessDetach(HINSTANCE hinstDLL)
4995 {
4996     cicDoneUIFLib();
4997     TFUninitLib();
4998     ::DeleteCriticalSection(&g_cs);
4999     gModule.Term();
5000 }
5001 
5002 /// @implemented
5003 EXTERN_C BOOL WINAPI
5004 DllMain(
5005     _In_ HINSTANCE hinstDLL,
5006     _In_ DWORD dwReason,
5007     _Inout_opt_ LPVOID lpvReserved)
5008 {
5009     switch (dwReason)
5010     {
5011         case DLL_PROCESS_ATTACH:
5012         {
5013             TRACE("(%p, %lu, %p)\n", hinstDLL, dwReason, lpvReserved);
5014             if (!ProcessAttach(hinstDLL))
5015             {
5016                 ProcessDetach(hinstDLL);
5017                 return FALSE;
5018             }
5019             break;
5020         }
5021         case DLL_PROCESS_DETACH:
5022         {
5023             ProcessDetach(hinstDLL);
5024             break;
5025         }
5026     }
5027     return TRUE;
5028 }
5029