Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

565 lines
16 KiB

  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // SHELLICO.CPP
  4. //
  5. // Shell tray icon handler
  6. //
  7. // Copyright (c) Microsoft Corporation 1998
  8. //
  9. // 3/15/98 David Stewart / dstewart
  10. //
  11. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  12. #include <windows.h>
  13. #include <tchar.h>
  14. #include <shellapi.h>
  15. #include "shellico.h"
  16. #include "mmenu.h"
  17. #include "resource.h"
  18. #define IDM_HOMEMENU_BASE (LAST_SEARCH_MENU_ID + 1)
  19. #define IDM_NETMENU_BASE (LAST_SEARCH_MENU_ID + 100)
  20. #define IDM_DISCLIST_BASE 20000
  21. #define SHELLTIMERID 1500
  22. //file-global variables
  23. PCOMPNODE g_pNode = NULL;
  24. IMMComponentAutomation* g_pAuto = NULL;
  25. HWND g_hwnd = NULL;
  26. HINSTANCE g_hInst = NULL;
  27. BOOL g_fShellIconCreated = FALSE;
  28. //icon
  29. HICON hIconPlay = NULL;
  30. HICON hIconPause = NULL;
  31. HICON hIconNoDisc = NULL;
  32. extern fOptionsDlgUp;
  33. extern nCDMode;
  34. extern BOOL fPlaying;
  35. extern BOOL IsDownloading();
  36. extern CustomMenu* g_pMenu;
  37. extern "C" void NormalizeNameForMenuDisplay(TCHAR* szInput, TCHAR* szOutput, DWORD cbLen);
  38. void CheckDiscState()
  39. {
  40. if (g_fShellIconCreated)
  41. {
  42. MMMEDIAID mmMedia;
  43. mmMedia.nDrive = -1;
  44. g_pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia);
  45. if (mmMedia.dwMediaID != 0)
  46. {
  47. ShellIconSetState(fPlaying ? PAUSE_ICON : PLAY_ICON);
  48. }
  49. else
  50. {
  51. ShellIconSetState(NODISC_ICON);
  52. }
  53. }
  54. }
  55. BOOL CreateShellIcon(HINSTANCE hInst, HWND hwndOwner, PCOMPNODE pNode, TCHAR* sztip)
  56. {
  57. BOOL retval = FALSE;
  58. g_hInst = hInst;
  59. HRESULT hr = pNode->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&g_pAuto);
  60. if (SUCCEEDED(hr))
  61. {
  62. g_pNode = pNode;
  63. //load all of the icon images
  64. hIconPlay = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_SHELL_PLAY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  65. hIconPause = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_SHELL_PAUSE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  66. hIconNoDisc = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_SHELL_NODISC), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  67. //now, create the tray icon
  68. g_hwnd = hwndOwner;
  69. NOTIFYICONDATA nData;
  70. nData.cbSize = sizeof(nData);
  71. nData.hWnd = hwndOwner;
  72. nData.uID = SHELLMESSAGE_CDICON;
  73. nData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  74. nData.uCallbackMessage = SHELLMESSAGE_CDICON;
  75. nData.hIcon = hIconPlay;
  76. _tcscpy(nData.szTip,sztip);
  77. retval = Shell_NotifyIcon(NIM_ADD,&nData);
  78. if (!retval)
  79. {
  80. g_pAuto->Release();
  81. g_pAuto = NULL;
  82. }
  83. else
  84. {
  85. g_fShellIconCreated = TRUE;
  86. CheckDiscState();
  87. }
  88. }
  89. return (retval);
  90. }
  91. void DestroyShellIcon()
  92. {
  93. g_fShellIconCreated = FALSE;
  94. if (g_pAuto)
  95. {
  96. //g_pAuto was addref'ed when we qi'ed for it.
  97. g_pAuto->Release();
  98. }
  99. NOTIFYICONDATA nData;
  100. nData.cbSize = sizeof(nData);
  101. nData.uID = SHELLMESSAGE_CDICON;
  102. nData.hWnd = g_hwnd;
  103. Shell_NotifyIcon(NIM_DELETE,&nData);
  104. //kill the icons
  105. DestroyIcon(hIconPlay);
  106. DestroyIcon(hIconPause);
  107. DestroyIcon(hIconNoDisc);
  108. hIconPlay = NULL;
  109. hIconPause = NULL;
  110. hIconNoDisc = NULL;
  111. }
  112. //works around bug in all Windows versions
  113. //where ampersands are stripped from tooltips on shell icon
  114. void EscapeTooltip(TCHAR* szInput, TCHAR* szOutput, DWORD cbLen)
  115. {
  116. ZeroMemory(szOutput,cbLen);
  117. WORD index1 = 0;
  118. WORD index2 = 0;
  119. for (; ((index1 < _tcslen(szInput)) && (index2 < ((cbLen/sizeof(TCHAR))-1))); index1++)
  120. {
  121. szOutput[index2] = szInput[index1];
  122. if (szOutput[index2] == TEXT('&'))
  123. {
  124. szOutput[++index2] = TEXT('&');
  125. szOutput[++index2] = TEXT('&');
  126. }
  127. index2++;
  128. }
  129. }
  130. void ShellIconSetTooltip()
  131. {
  132. if (g_fShellIconCreated)
  133. {
  134. NOTIFYICONDATA nData;
  135. nData.cbSize = sizeof(nData);
  136. nData.hWnd = g_hwnd;
  137. nData.uID = SHELLMESSAGE_CDICON;
  138. nData.uFlags = NIF_TIP;
  139. MMMEDIAID mmMedia;
  140. mmMedia.nDrive = -1;
  141. mmMedia.szTrack[0] = TEXT('\0');
  142. g_pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia);
  143. TCHAR szTempTip[MAX_PATH+sizeof(TCHAR)];
  144. TCHAR szEscapeTip[MAX_PATH+sizeof(TCHAR)];
  145. if ((mmMedia.dwMediaID != 0) || (_tcslen(mmMedia.szTrack)!=0))
  146. {
  147. //128 + 128 + 4 = 260 ... that's max_path
  148. wsprintf(szTempTip,TEXT("%s (%s)"),mmMedia.szTitle,mmMedia.szTrack);
  149. }
  150. else
  151. {
  152. _tcscpy(szTempTip,mmMedia.szTitle);
  153. }
  154. //escape out & symbols if they are in the string
  155. if (_tcschr(szTempTip,TEXT('&')))
  156. {
  157. EscapeTooltip(szTempTip,szEscapeTip,sizeof(szEscapeTip));
  158. _tcscpy(szTempTip,szEscapeTip);
  159. }
  160. //truncate long tip to size of tooltip
  161. szTempTip[(sizeof(nData.szTip)/sizeof(TCHAR))-1] = TEXT('\0');
  162. _tcscpy(nData.szTip,szTempTip);
  163. Shell_NotifyIcon(NIM_MODIFY,&nData);
  164. //bit of a hack, but if we're getting a new tool tip, then we might be need to turn
  165. //on or off the "nodisc" state
  166. CheckDiscState();
  167. }
  168. }
  169. void CreateTransportMenu(CustomMenu* pMenu, CustomMenu* pTransMenu)
  170. {
  171. //play or pause
  172. if (fPlaying)
  173. {
  174. pTransMenu->AppendMenu(IDB_PLAY,g_hInst,IDS_SH_PAUSE);
  175. }
  176. else
  177. {
  178. pTransMenu->AppendMenu(IDB_PLAY,g_hInst,IDS_SH_PLAY);
  179. }
  180. //stop
  181. pTransMenu->AppendMenu(IDB_STOP,g_hInst,IDS_SH_STOP);
  182. //eject
  183. pTransMenu->AppendMenu(IDB_EJECT,g_hInst,IDS_SH_EJECT);
  184. //previous track
  185. pTransMenu->AppendMenu(IDB_PREVTRACK,g_hInst,IDS_SH_PREVTRACK);
  186. //next track
  187. pTransMenu->AppendMenu(IDB_NEXTTRACK,g_hInst,IDS_SH_NEXTTRACK);
  188. pMenu->AppendMenu(g_hInst,IDS_SH_TRANS,pTransMenu);
  189. }
  190. void CreateOptionsMenu(CustomMenu* pMenu, CustomMenu* pOptionsMenu)
  191. {
  192. pOptionsMenu->AppendMenu(IDM_OPTIONS,g_hInst,IDM_OPTIONS);
  193. pOptionsMenu->AppendMenu(IDM_PLAYLIST,g_hInst,IDM_PLAYLIST);
  194. pOptionsMenu->AppendSeparator();
  195. //do not bother graying out the playlist menu, it causes too much delay in odbc load
  196. /*
  197. LPCDDATA pData = GetCDData();
  198. if (pData)
  199. {
  200. if (FAILED(pData->CheckDatabase(g_hwnd)))
  201. {
  202. EnableMenuItem(pOptionsMenu->GetMenuHandle(),
  203. IDM_PLAYLIST,
  204. MF_BYCOMMAND | MF_GRAYED);
  205. }
  206. }
  207. */
  208. pOptionsMenu->AppendMenu(IDM_HELP,g_hInst,IDM_HELP);
  209. pMenu->AppendMenu(g_hInst,IDS_SH_OPTIONS,pOptionsMenu);
  210. }
  211. void CreateModeMenu(CustomMenu* pMenu, CustomMenu* pModeMenu)
  212. {
  213. pModeMenu->AppendMenu(IDM_MODE_NORMAL,g_hInst,IDI_MODE_NORMAL,IDM_MODE_NORMAL);
  214. pModeMenu->AppendMenu(IDM_MODE_RANDOM,g_hInst,IDI_MODE_RANDOM,IDM_MODE_RANDOM);
  215. pModeMenu->AppendMenu(IDM_MODE_REPEATONE,g_hInst,IDI_MODE_REPEATONE,IDM_MODE_REPEATONE);
  216. pModeMenu->AppendMenu(IDM_MODE_REPEATALL,g_hInst,IDI_MODE_REPEATALL,IDM_MODE_REPEATALL);
  217. pModeMenu->AppendMenu(IDM_MODE_INTRO,g_hInst,IDI_MODE_INTRO,IDM_MODE_INTRO);
  218. pModeMenu->SetMenuDefaultItem(nCDMode,FALSE);
  219. pMenu->AppendMenu(g_hInst,IDS_SH_MODE,pModeMenu);
  220. }
  221. void CreateNetMenu(CustomMenu* pMenu, CustomMenu* pNetMenu, CustomMenu* pSearchSubMenu, CustomMenu* pProviderSubMenu)
  222. {
  223. MMMEDIAID mmMedia;
  224. mmMedia.nDrive = -1;
  225. g_pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia);
  226. BOOL fContinue = TRUE;
  227. //append static menu choices
  228. if (IsDownloading())
  229. {
  230. pNetMenu->AppendMenu(IDM_NET_CANCEL,g_hInst,IDM_NET_CANCEL);
  231. }
  232. else
  233. {
  234. pNetMenu->AppendMenu(IDM_NET_UPDATE,g_hInst,IDM_NET_UPDATE);
  235. if (mmMedia.dwMediaID == 0)
  236. {
  237. //need to gray out menu
  238. MENUITEMINFO mmi;
  239. mmi.cbSize = sizeof(mmi);
  240. mmi.fMask = MIIM_STATE;
  241. mmi.fState = MFS_GRAYED;
  242. HMENU hMenu = pNetMenu->GetMenuHandle();
  243. SetMenuItemInfo(hMenu,IDM_NET_UPDATE,FALSE,&mmi);
  244. }
  245. }
  246. //if networking is not allowed, gray it out ...
  247. //don't worry about cancel case, it won't be there
  248. LPCDDATA pData = GetCDData();
  249. if (mmMedia.dwMediaID != 0)
  250. {
  251. //don't allow searching if title isn't available
  252. if (pData)
  253. {
  254. if (pData->QueryTitle(mmMedia.dwMediaID))
  255. {
  256. pSearchSubMenu->AppendMenu(IDM_NET_BAND,g_hInst,IDM_NET_BAND);
  257. pSearchSubMenu->AppendMenu(IDM_NET_CD,g_hInst,IDM_NET_CD);
  258. pSearchSubMenu->AppendMenu(IDM_NET_ROLLINGSTONE_ARTIST,g_hInst,IDM_NET_ROLLINGSTONE_ARTIST);
  259. pSearchSubMenu->AppendMenu(IDM_NET_BILLBOARD_ARTIST,g_hInst,IDM_NET_BILLBOARD_ARTIST);
  260. pSearchSubMenu->AppendMenu(IDM_NET_BILLBOARD_ALBUM,g_hInst,IDM_NET_BILLBOARD_ALBUM);
  261. pNetMenu->AppendMenu(g_hInst,IDM_NET_SEARCH_HEADING,pSearchSubMenu);
  262. }
  263. } //end if pdata
  264. }
  265. //display any provider home pages
  266. DWORD i = 0;
  267. LPCDOPT pOpt = GetCDOpt();
  268. if( pOpt )
  269. {
  270. LPCDOPTIONS pCDOpts = pOpt->GetCDOpts();
  271. LPCDPROVIDER pProviderList = pCDOpts->pProviderList;
  272. while (pProviderList!=NULL)
  273. {
  274. TCHAR szProviderMenu[MAX_PATH];
  275. TCHAR szHomePageFormat[MAX_PATH/2];
  276. LoadString(g_hInst,IDS_HOMEPAGEFORMAT,szHomePageFormat,sizeof(szHomePageFormat)/sizeof(TCHAR));
  277. wsprintf(szProviderMenu,szHomePageFormat,pProviderList->szProviderName);
  278. pProviderSubMenu->AppendMenu(IDM_HOMEMENU_BASE+i,szProviderMenu);
  279. pProviderList = pProviderList->pNext;
  280. i++;
  281. } //end while
  282. pNetMenu->AppendMenu(g_hInst,IDM_NET_PROVIDER_HEADING,pProviderSubMenu);
  283. } //end home pages
  284. //display internet-loaded disc menus
  285. if (mmMedia.dwMediaID != 0)
  286. {
  287. if (pData)
  288. {
  289. if (pData->QueryTitle(mmMedia.dwMediaID))
  290. {
  291. LPCDTITLE pCDTitle = NULL;
  292. HRESULT hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
  293. if (SUCCEEDED(hr))
  294. {
  295. for (i = 0; i < pCDTitle->dwNumMenus; i++)
  296. {
  297. if (i==0)
  298. {
  299. pNetMenu->AppendSeparator();
  300. }
  301. TCHAR szDisplayNet[MAX_PATH];
  302. NormalizeNameForMenuDisplay(pCDTitle->pMenuTable[i].szMenuText,szDisplayNet,sizeof(szDisplayNet));
  303. pNetMenu->AppendMenu(i + IDM_NETMENU_BASE,szDisplayNet);
  304. }
  305. pData->UnlockTitle(pCDTitle,FALSE);
  306. }
  307. } //end if query title
  308. }
  309. }
  310. pMenu->AppendMenu(g_hInst,IDS_SH_NET,pNetMenu);
  311. }
  312. void CreateTrackMenu(CustomMenu* pMenu, CustomMenu* pTrackMenu)
  313. {
  314. int i = 0;
  315. HRESULT hr = S_OK;
  316. while (SUCCEEDED(hr))
  317. {
  318. MMTRACKORDISC mmTrack;
  319. mmTrack.nNumber = i++;
  320. hr = g_pAuto->OnAction(MMACTION_GETTRACKINFO,&mmTrack);
  321. if (SUCCEEDED(hr))
  322. {
  323. pTrackMenu->AppendMenu(mmTrack.nID + IDM_TRACKLIST_SHELL_BASE, mmTrack.szName);
  324. if (mmTrack.fCurrent)
  325. {
  326. pTrackMenu->SetMenuDefaultItem(mmTrack.nID + IDM_TRACKLIST_SHELL_BASE,FALSE);
  327. } //end if current
  328. } //end if ok
  329. } //end while
  330. pMenu->AppendMenu(g_hInst,IDS_SH_TRACK,pTrackMenu);
  331. }
  332. void CreateDiscMenu(CustomMenu* pMenu, CustomMenu* pDiscMenu)
  333. {
  334. int i = 0;
  335. HRESULT hr = S_OK;
  336. while (SUCCEEDED(hr))
  337. {
  338. MMTRACKORDISC mmDisc;
  339. mmDisc.nNumber = i++;
  340. hr = g_pAuto->OnAction(MMACTION_GETDISCINFO,&mmDisc);
  341. if (SUCCEEDED(hr))
  342. {
  343. pDiscMenu->AppendMenu(mmDisc.nID + IDM_DISCLIST_BASE, mmDisc.szName);
  344. if (mmDisc.fCurrent)
  345. {
  346. pDiscMenu->SetMenuDefaultItem(mmDisc.nID + IDM_DISCLIST_BASE,FALSE);
  347. } //end if current
  348. }
  349. }
  350. pMenu->AppendMenu(g_hInst,IDS_SH_DISC,pDiscMenu);
  351. }
  352. void CALLBACK lButtonTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  353. {
  354. KillTimer(hwnd,idEvent);
  355. if (fPlaying)
  356. {
  357. g_pAuto->OnAction(MMACTION_PAUSE,NULL);
  358. //ShellIconSetState(PLAY_ICON);
  359. }
  360. else
  361. {
  362. g_pAuto->OnAction(MMACTION_PLAY,NULL);
  363. //ShellIconSetState(PAUSE_ICON);
  364. }
  365. }
  366. LRESULT ShellIconHandeMessage(LPARAM lParam)
  367. {
  368. switch (lParam)
  369. {
  370. case (WM_LBUTTONDOWN) :
  371. {
  372. SetTimer(g_hwnd,SHELLTIMERID,GetDoubleClickTime()+100,(TIMERPROC)lButtonTimerProc);
  373. }
  374. break;
  375. case (WM_LBUTTONDBLCLK) :
  376. {
  377. KillTimer(g_hwnd,SHELLTIMERID);
  378. if ((IsWindowVisible(g_hwnd)) && (!IsIconic(g_hwnd)))
  379. {
  380. ShowWindow(g_hwnd,SW_HIDE);
  381. }
  382. else
  383. {
  384. if (IsIconic(g_hwnd))
  385. {
  386. ShowWindow(g_hwnd,SW_RESTORE);
  387. }
  388. ShowWindow(g_hwnd,SW_SHOW);
  389. BringWindowToTop(g_hwnd);
  390. SetForegroundWindow(g_hwnd);
  391. }
  392. }
  393. break;
  394. case (WM_RBUTTONUP) :
  395. {
  396. if (!fOptionsDlgUp)
  397. {
  398. CustomMenu* pTrackMenu = NULL;
  399. CustomMenu* pDiscMenu = NULL;
  400. CustomMenu* pOptionsMenu = NULL;
  401. CustomMenu* pNetMenu = NULL;
  402. CustomMenu* pSearchSubMenu = NULL;
  403. CustomMenu* pProviderSubMenu = NULL;
  404. CustomMenu* pModeMenu = NULL;
  405. CustomMenu* pTransMenu = NULL;
  406. AllocCustomMenu(&g_pMenu);
  407. AllocCustomMenu(&pTrackMenu);
  408. AllocCustomMenu(&pDiscMenu);
  409. AllocCustomMenu(&pOptionsMenu);
  410. AllocCustomMenu(&pNetMenu);
  411. AllocCustomMenu(&pSearchSubMenu);
  412. AllocCustomMenu(&pProviderSubMenu);
  413. AllocCustomMenu(&pModeMenu);
  414. AllocCustomMenu(&pTransMenu);
  415. if (g_pMenu)
  416. {
  417. g_pMenu->AppendMenu(IDM_ABOUT,g_hInst,IDM_ABOUT);
  418. g_pMenu->AppendSeparator();
  419. CreateTransportMenu(g_pMenu,pTransMenu);
  420. CreateOptionsMenu(g_pMenu,pOptionsMenu);
  421. CreateNetMenu(g_pMenu,pNetMenu,pSearchSubMenu,pProviderSubMenu);
  422. CreateModeMenu(g_pMenu,pModeMenu);
  423. CreateDiscMenu(g_pMenu,pDiscMenu);
  424. CreateTrackMenu(g_pMenu,pTrackMenu);
  425. g_pMenu->AppendSeparator();
  426. g_pMenu->AppendMenu(IDM_EXIT_SHELL,g_hInst,IDM_EXIT);
  427. POINT mouse;
  428. GetCursorPos(&mouse);
  429. RECT rect;
  430. SetRect(&rect,0,0,0,0);
  431. SetForegroundWindow(g_hwnd);
  432. g_pMenu->TrackPopupMenu(0,mouse.x,mouse.y,g_hwnd,&rect);
  433. pTrackMenu->Destroy();
  434. pDiscMenu->Destroy();
  435. pOptionsMenu->Destroy();
  436. pNetMenu->Destroy();
  437. pSearchSubMenu->Destroy();
  438. pProviderSubMenu->Destroy();
  439. pModeMenu->Destroy();
  440. pTransMenu->Destroy();
  441. }
  442. if (g_pMenu)
  443. {
  444. g_pMenu->Destroy();
  445. g_pMenu = NULL;
  446. }
  447. } //end if ok to do
  448. else
  449. {
  450. MessageBeep(0);
  451. }
  452. } //end right-button up
  453. break;
  454. }
  455. return 0;
  456. }
  457. void ShellIconSetState(int nIconType)
  458. {
  459. if (g_fShellIconCreated)
  460. {
  461. int iID = IDI_SHELL_PLAY;
  462. HICON hIcon = hIconPlay;
  463. switch(nIconType)
  464. {
  465. case PAUSE_ICON :
  466. {
  467. iID = IDI_SHELL_PAUSE;
  468. hIcon = hIconPause;
  469. }
  470. break;
  471. case NODISC_ICON :
  472. {
  473. iID = IDI_SHELL_NODISC;
  474. hIcon = hIconNoDisc;
  475. }
  476. break;
  477. }
  478. NOTIFYICONDATA nData;
  479. nData.cbSize = sizeof(nData);
  480. nData.hWnd = g_hwnd;
  481. nData.uID = SHELLMESSAGE_CDICON;
  482. nData.uFlags = NIF_ICON;
  483. nData.hIcon = hIcon;
  484. Shell_NotifyIcon(NIM_MODIFY,&nData);
  485. }
  486. }