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