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.

1050 lines
28 KiB

  1. #include "priv.h"
  2. #include "zaxxon.h"
  3. #include "guids.h"
  4. #include "shlwapip.h"
  5. #include "mmreg.h"
  6. #include "mmstream.h" // Multimedia stream interfaces
  7. #include "amstream.h" // DirectShow multimedia stream interfaces
  8. #include "ddstream.h" // DirectDraw multimedia stream interfaces
  9. #include "resource.h"
  10. #include "varutil.h"
  11. #include "runtask.h"
  12. #define COLOR3d (COLORREF)GetSysColor(COLOR_3DFACE)
  13. #define COLORMASK (COLORREF)RGB( 255, 0, 255 )
  14. #define PREV 0
  15. #define PLAY 1
  16. #define PAUSE 2
  17. #define STOP 3
  18. #define NEXT 4
  19. #define MENU 5
  20. void PlayMP3(LPTSTR pszFilename);
  21. const TCHAR* g_crgstrStrings = TEXT("Play\0Pause\0Stop\0Previous\0Next\0Menu\0\0");
  22. const TBBUTTON g_crgButtons[] =
  23. {
  24. {PLAY, PLAY, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
  25. {PREV, PREV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
  26. {NEXT, NEXT, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
  27. {MENU, MENU, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
  28. };
  29. #define WMP_CONTROLS_COUNT 6
  30. int GetButtonsWidth(HWND hwndTB)
  31. {
  32. LONG lButton = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0L);
  33. return HIWORD(lButton) * SendMessage(hwndTB, TB_BUTTONCOUNT, 0, 0) + 1;
  34. }
  35. void CenterOnTopOf(BOOL fToolbar, HWND hwnd, HWND hwndOn)
  36. {
  37. RECT rcParent;
  38. RECT rcSelf;
  39. HMONITOR hmon;
  40. GetWindowRect(hwnd, &rcSelf);
  41. GetWindowRect(hwndOn, &rcParent);
  42. if (fToolbar)
  43. rcParent.right = rcParent.left + GetButtonsWidth(hwndOn);
  44. int x = rcParent.left + (RECTWIDTH(rcParent) - RECTWIDTH(rcSelf))/2;
  45. int y = rcParent.top - RECTHEIGHT(rcSelf);
  46. hmon = MonitorFromWindow(hwndOn, MONITOR_DEFAULTTONEAREST);
  47. if (hmon)
  48. {
  49. MONITORINFO mi;
  50. mi.cbSize = sizeof(mi);
  51. if (GetMonitorInfo(hmon, &mi))
  52. {
  53. if (x < mi.rcMonitor.left)
  54. x = mi.rcMonitor.left;
  55. if (y < mi.rcMonitor.top)
  56. {
  57. // Go below
  58. y = rcParent.bottom;
  59. }
  60. if (y + RECTHEIGHT(rcSelf) > mi.rcMonitor.bottom)
  61. y = mi.rcMonitor.bottom - RECTHEIGHT(rcSelf);
  62. if (x + RECTWIDTH(rcSelf) > mi.rcMonitor.right)
  63. x = mi.rcMonitor.right - RECTWIDTH(rcSelf);
  64. }
  65. }
  66. SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSIZE);
  67. }
  68. void FillRectClr(HDC hdc, PRECT prc, COLORREF clr)
  69. {
  70. COLORREF clrSave = SetBkColor(hdc, clr);
  71. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
  72. SetBkColor(hdc, clrSave);
  73. }
  74. class CMusicExtractionTask : public CRunnableTask
  75. {
  76. public:
  77. CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile);
  78. STDMETHODIMP RunInitRT(void);
  79. private:
  80. virtual ~CMusicExtractionTask();
  81. TCHAR szFile[MAX_PATH];
  82. HWND _hwnd;
  83. CZaxxon* _pzaxxon;
  84. };
  85. CMusicExtractionTask::CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile)
  86. : CRunnableTask(RTF_DEFAULT), _hwnd(hwnd), _pzaxxon(pzaxxon)
  87. {
  88. StrCpyN(szFile, pszFile, ARRAYSIZE(szFile));
  89. }
  90. CMusicExtractionTask::~CMusicExtractionTask()
  91. {
  92. }
  93. STDMETHODIMP CMusicExtractionTask::RunInitRT()
  94. {
  95. BOOL fResetImage = TRUE;
  96. HRESULT hr = E_OUTOFMEMORY;
  97. PWSTR psz = StrDup(szFile);
  98. if (psz)
  99. {
  100. LPITEMIDLIST pidl = ILCreateFromPath(szFile);
  101. if (pidl)
  102. {
  103. LPCITEMIDLIST pidlChild;
  104. IShellFolder2* psf;
  105. hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder2, &psf), &pidlChild);
  106. if (SUCCEEDED(hr))
  107. {
  108. VARIANT v;
  109. hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Artist, &v);
  110. if (SUCCEEDED(hr))
  111. {
  112. TCHAR szValue[MAX_PATH];
  113. VariantToStr(&v, szValue, ARRAYSIZE(szValue));
  114. SendMessage(_hwnd, WM_SETARTIST, 0, (LPARAM)szValue);
  115. }
  116. hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Album, &v);
  117. if (SUCCEEDED(hr))
  118. {
  119. TCHAR szValue[MAX_PATH];
  120. VariantToStr(&v, szValue, ARRAYSIZE(szValue));
  121. SendMessage(_hwnd, WM_SETALBUM, 0, (LPARAM)szValue);
  122. }
  123. hr = psf->GetDetailsEx(pidlChild, &SCID_Title, &v);
  124. if (SUCCEEDED(hr))
  125. {
  126. TCHAR szValue[MAX_PATH];
  127. VariantToStr(&v, szValue, ARRAYSIZE(szValue));
  128. SendMessage(_hwnd, WM_SETSONG, 0, (LPARAM)szValue);
  129. }
  130. InvalidateRect(_hwnd, NULL, TRUE);
  131. psf->Release();
  132. }
  133. ILFree(pidl);
  134. }
  135. if (PathRemoveFileSpec(psz))
  136. {
  137. PathAppend(psz, TEXT("folder.gif"));
  138. if (!PathFileExists(psz))
  139. {
  140. PathRemoveFileSpec(psz);
  141. PathAppend(psz, TEXT("folder.jpg"));
  142. }
  143. if (PathFileExists(psz))
  144. {
  145. if (_pzaxxon->_pThumbnail)
  146. {
  147. _pzaxxon->_pThumbnail->Release();
  148. _pzaxxon->_pThumbnail = NULL;
  149. }
  150. hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&(_pzaxxon->_pThumbnail));
  151. if (SUCCEEDED(hr))
  152. {
  153. RECT rc;
  154. GetWindowRect(_hwnd, &rc);
  155. SIZE sz;
  156. sz.cy = (3 * RECTHEIGHT(rc)) / 4;
  157. sz.cx = sz.cy;
  158. _pzaxxon->_pThumbnail->Init(_hwnd, WM_SONGTHUMBDONE);
  159. _pzaxxon->_pThumbnail->GetBitmap(psz, 0, sz.cx, sz.cy);
  160. fResetImage = FALSE;
  161. }
  162. }
  163. }
  164. LocalFree(psz);
  165. }
  166. if (fResetImage)
  167. SendMessage(_hwnd, WM_SONGTHUMBDONE, 0, 0);;
  168. if (_pzaxxon->_bOpacity < 200)
  169. {
  170. _pzaxxon->_fHide = FALSE;
  171. SetTimer(_hwnd, 1, 30, NULL);
  172. }
  173. return hr;
  174. }
  175. void RenderTile(HWND hwnd, HDC hdc, CZaxxon* pzax)
  176. {
  177. BITMAP bm = {0};
  178. RECT rc;
  179. GetClientRect(hwnd, &rc);
  180. MARGINS m = {0};
  181. MARGINS s = {0};
  182. RECT rcFrame = {0};
  183. RECT rcText;
  184. int y = 10;
  185. if (pzax->_hbmpAlbumArt)
  186. {
  187. GetObject(pzax->_hbmpAlbumArt, sizeof (BITMAP), &bm);
  188. HDC hdcBitmap = CreateCompatibleDC(hdc);
  189. HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcBitmap, pzax->_hbmpAlbumArt);
  190. y = (RECTHEIGHT(rc) - bm.bmHeight) / 2;
  191. if (pzax->_hTheme)
  192. {
  193. GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_SIZINGMARGINS, NULL, &s);
  194. y = (RECTHEIGHT(rc) - bm.bmHeight - m.cyBottomHeight - m.cyTopHeight - s.cyBottomHeight - s.cyTopHeight) / 2;
  195. GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_CONTENTMARGINS, NULL, &m);
  196. rcFrame.left = 10;
  197. rcFrame.top = y;
  198. rcFrame.right = rcFrame.left + bm.bmWidth + m.cxLeftWidth + m.cxRightWidth;
  199. rcFrame.bottom = rcFrame.top + bm.bmHeight + m.cyBottomHeight + m.cyTopHeight;
  200. DrawThemeBackground(pzax->_hTheme, hdc, SPP_USERPICTURE, 0, &rcFrame, 0);
  201. }
  202. BitBlt(hdc, rcFrame.left+m.cxLeftWidth, y + m.cyTopHeight, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
  203. SelectObject(hdcBitmap, hbmpOld);
  204. DeleteDC(hdcBitmap);
  205. }
  206. SetBkMode(hdc, TRANSPARENT);
  207. SIZE sz;
  208. HFONT h = (HFONT)SelectObject(hdc, pzax->_hfont);
  209. int cch = lstrlen(pzax->_szArtist);
  210. GetTextExtentPoint32(hdc, pzax->_szArtist, cch, &sz);
  211. rcText.left = bm.bmWidth + 20 + m.cxLeftWidth + m.cxRightWidth;
  212. rcText.top = y + m.cyTopHeight;
  213. rcText.right = rcText.left + sz.cx;
  214. rcText.bottom = rcText.top + sz.cy;
  215. DrawShadowText(hdc, pzax->_szArtist, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP, GetSysColor(COLOR_CAPTIONTEXT), RGB(0,0,0), 2, 2);
  216. SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
  217. cch = lstrlen(pzax->_szAlbum);
  218. GetTextExtentPoint32(hdc, pzax->_szAlbum, cch, &sz);
  219. rcText.top = rcText.bottom;
  220. rcText.bottom = rcText.top + sz.cy;
  221. rcText.right = rcText.left + sz.cx;
  222. DrawText(hdc, pzax->_szAlbum, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
  223. cch = lstrlen(pzax->_szSong);
  224. GetTextExtentPoint32(hdc, pzax->_szSong, cch, &sz);
  225. rcText.top = rcText.bottom;
  226. rcText.bottom = rcText.top + sz.cy;
  227. rcText.right = rcText.left + sz.cx;
  228. DrawText(hdc, pzax->_szSong, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
  229. SelectObject(hdc, h);
  230. }
  231. LRESULT ZaxxonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  232. {
  233. CZaxxon* pzaxxon = (CZaxxon*)GetProp(hwnd, TEXT("Zaxxon"));
  234. if (!pzaxxon && uMsg != WM_CREATE)
  235. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  236. switch (uMsg)
  237. {
  238. case WM_CREATE:
  239. {
  240. pzaxxon = (CZaxxon*)((CREATESTRUCT*)lParam)->lpCreateParams;
  241. SetProp(hwnd, TEXT("Zaxxon"), (HANDLE)pzaxxon);
  242. pzaxxon->_hTheme = OpenThemeData(NULL, L"StartPanel");
  243. NONCLIENTMETRICS ncm;
  244. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  245. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  246. pzaxxon->_hfont = CreateFontIndirect(&ncm.lfCaptionFont);
  247. SIZE sz = {0};
  248. if (pzaxxon->_hTheme)
  249. GetThemePartSize(pzaxxon->_hTheme, NULL, SPP_USERPANE, 0, NULL, TS_TRUE, &sz);
  250. int cy = 3 * GetSystemMetrics(SM_CYCAPTION);
  251. if (sz.cy < cy)
  252. sz.cy = cy;
  253. if (sz.cx < 400)
  254. sz.cx = 400;
  255. SetWindowPos(hwnd, NULL, 0, 0, sz.cx, sz.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  256. }
  257. break;
  258. case WM_DESTROY:
  259. {
  260. if (pzaxxon->_hTheme)
  261. CloseThemeData(pzaxxon->_hTheme);
  262. }
  263. break;
  264. case WM_ERASEBKGND:
  265. if (pzaxxon->_hTheme)
  266. {
  267. RECT rc;
  268. HDC hdc = (HDC)wParam;
  269. GetClientRect(hwnd, &rc);
  270. FillRectClr(hdc, &rc, RGB(255,0,255));
  271. DrawThemeBackground(pzaxxon->_hTheme, hdc, SPP_USERPANE, 0, &rc, 0);
  272. RenderTile(hwnd, hdc, pzaxxon);
  273. return TRUE;
  274. }
  275. break;
  276. case WM_SETALBUM:
  277. StrCpy(pzaxxon->_szAlbum, (PTSTR)lParam);
  278. break;
  279. case WM_SETARTIST:
  280. StrCpy(pzaxxon->_szArtist, (PTSTR)lParam);
  281. break;
  282. case WM_SETSONG:
  283. StrCpy(pzaxxon->_szSong, (PTSTR)lParam);
  284. break;
  285. case WM_SONGTHUMBDONE:
  286. {
  287. if (pzaxxon->_hbmpAlbumArt)
  288. DeleteObject(pzaxxon->_hbmpAlbumArt);
  289. pzaxxon->_hbmpAlbumArt = (HBITMAP)lParam;
  290. InvalidateRect(hwnd, NULL, TRUE);
  291. if (pzaxxon->_pThumbnail)
  292. {
  293. pzaxxon->_pThumbnail->Release();
  294. pzaxxon->_pThumbnail = NULL;
  295. }
  296. }
  297. return TRUE;
  298. case WM_TIMER:
  299. if (wParam == 1)
  300. {
  301. BYTE bOld = pzaxxon->_bOpacity;
  302. if (pzaxxon->_fHide)
  303. {
  304. if (pzaxxon->_bOpacity < 20)
  305. {
  306. pzaxxon->_bOpacity = 0;
  307. ShowWindow(hwnd, SW_HIDE);
  308. KillTimer(hwnd, 1);
  309. }
  310. else
  311. pzaxxon->_bOpacity -= 20;
  312. }
  313. else
  314. {
  315. if (pzaxxon->_bOpacity > 200)
  316. {
  317. pzaxxon->_bOpacity = 200;
  318. KillTimer(hwnd, 1);
  319. if (pzaxxon->_fAllowFadeout)
  320. SetTimer(hwnd, 2, 1000, NULL);
  321. }
  322. else
  323. pzaxxon->_bOpacity += 10;
  324. }
  325. if (bOld != pzaxxon->_bOpacity)
  326. SetLayeredWindowAttributes(hwnd, RGB(255,0,255), pzaxxon->_bOpacity, LWA_COLORKEY | LWA_ALPHA);
  327. BOOL fToolbar = TRUE;
  328. HWND hwndToPutOnTopOf = pzaxxon->_hwnd;
  329. if (pzaxxon->_fEditorShown)
  330. {
  331. fToolbar = FALSE;
  332. hwndToPutOnTopOf = pzaxxon->_pEdit->_hwnd;
  333. }
  334. CenterOnTopOf(fToolbar, hwnd, hwndToPutOnTopOf);
  335. }
  336. else if (wParam == 2)
  337. {
  338. KillTimer(hwnd, 2);
  339. SetTimer(hwnd, 1, 30, NULL);
  340. pzaxxon->_fHide = TRUE;
  341. }
  342. return TRUE;
  343. case WM_SONGSTOP:
  344. {
  345. pzaxxon->SongStop();
  346. DeleteObject(pzaxxon->_hbmpAlbumArt);
  347. pzaxxon->_hbmpAlbumArt = NULL;
  348. pzaxxon->_szArtist[0] = 0;
  349. pzaxxon->_szSong[0] = 0;
  350. pzaxxon->_szAlbum[0] = 0;
  351. InvalidateRect(hwnd, NULL, TRUE);
  352. }
  353. return TRUE;
  354. case WM_SONGCHANGE:
  355. {
  356. if (pzaxxon->_pScheduler)
  357. {
  358. CMusicExtractionTask* pme = new CMusicExtractionTask(pzaxxon, hwnd, (PWSTR)wParam);
  359. pzaxxon->_pScheduler->AddTask(pme, CLSID_Zaxxon, 0, ITSAT_DEFAULT_PRIORITY);
  360. pme->Release();
  361. }
  362. }
  363. return TRUE;
  364. }
  365. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  366. }
  367. CZaxxon::CZaxxon()
  368. {
  369. CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler));
  370. CoCreateInstance(CLSID_ZaxxonPlayer, NULL, CLSCTX_INPROC_SERVER, IID_IZaxxonPlayer, (void**)&_pzax);
  371. _dwViewMode = NULL;
  372. _himlHot = NULL;
  373. _himlDef = NULL;
  374. _hmenuOpenFolder = NULL;
  375. _pThumbnail = NULL;
  376. _bOpacity = 0;
  377. _fHide = FALSE;
  378. _fAllowFadeout = TRUE;
  379. _fPlaying = FALSE;
  380. _hbr = NULL;
  381. _szArtist[0] = 0;
  382. _szSong[0] = 0;
  383. _szAlbum[0] = 0;
  384. _hbmpAlbumArt = NULL;
  385. }
  386. CZaxxon::~CZaxxon()
  387. {
  388. if (_himlHot)
  389. ImageList_Destroy(_himlHot);
  390. if (_himlDef)
  391. ImageList_Destroy(_himlDef);
  392. if (_pzax)
  393. _pzax->Release();
  394. if (_pThumbnail)
  395. _pThumbnail->Release();
  396. if (_pScheduler)
  397. _pScheduler->Release();
  398. if (_hbr)
  399. DeleteObject(_hbr);
  400. if (_hmenuOpenFolder)
  401. DestroyMenu(_hmenuOpenFolder);
  402. }
  403. HWND CZaxxon::_CreateWindow(HWND hwndParent)
  404. {
  405. if (_hwnd)
  406. return _hwnd;
  407. WNDCLASS wc = {0};
  408. wc.style = CS_HREDRAW | CS_VREDRAW;
  409. wc.lpszClassName = TEXT("ZaxxonSongTile");
  410. wc.lpfnWndProc = ZaxxonWndProc;
  411. wc.hInstance = HINST_THISDLL;
  412. wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  413. RegisterClass(&wc);
  414. _hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
  415. WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  416. WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  417. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  418. CCS_NORESIZE | TBSTYLE_REGISTERDROP,
  419. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  420. if (_hwnd)
  421. {
  422. // Set the format to ANSI or UNICODE as appropriate.
  423. ToolBar_SetUnicodeFormat(_hwnd, TRUE);
  424. SetWindowTheme(_hwnd, L"TaskBar", NULL);
  425. SendMessage(_hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0);
  426. SendMessage(_hwnd, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  427. // SendMessage(_hwnd, TB_ADDSTRING, NULL, (LPARAM)&g_crgstrStrings);
  428. SendMessage(_hwnd, TB_ADDBUTTONS, ARRAYSIZE(g_crgButtons), (LPARAM)&g_crgButtons);
  429. ToolBar_SetExtendedStyle(_hwnd, TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_DOUBLEBUFFER);
  430. _himlHot = ImageList_LoadImage(HINST_THISDLL,
  431. MAKEINTRESOURCE(IDB_ZAXXONHOT), 16, 0, COLORMASK,
  432. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  433. SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, (LPARAM)_himlHot);
  434. _himlDef = ImageList_LoadImage(HINST_THISDLL,
  435. MAKEINTRESOURCE(IDB_ZAXXONDEF), 16, 0, COLORMASK,
  436. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  437. SendMessage(_hwnd, TB_SETIMAGELIST, 0, (LPARAM)_himlDef);
  438. _hwndSongTile = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT, TEXT("ZaxxonSongTile"), NULL,
  439. WS_POPUP, 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, this);
  440. _pEdit = new CZaxxonEditor(this);
  441. _pEdit->Initialize();
  442. _pzax->Register(_hwndSongTile);
  443. }
  444. return _hwnd;
  445. }
  446. void CZaxxon::SongStop()
  447. {
  448. _fPlaying = FALSE;
  449. TBBUTTONINFO bi = {0};
  450. bi.cbSize = sizeof(bi);
  451. bi.dwMask = TBIF_IMAGE;
  452. bi.iImage = PLAY;
  453. ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
  454. }
  455. LRESULT CZaxxon::_OnCommand(WORD wNotifyCode, WORD wID, HWND hwnd)
  456. {
  457. if (!_pzax)
  458. return 0;
  459. switch (wNotifyCode)
  460. {
  461. case BN_CLICKED:
  462. switch (wID)
  463. {
  464. case PLAY:
  465. {
  466. TBBUTTONINFO bi = {0};
  467. bi.cbSize = sizeof(bi);
  468. bi.dwMask = TBIF_IMAGE;
  469. if (_fPlaying)
  470. {
  471. _pzax->Pause();
  472. _fPlaying = FALSE;
  473. bi.iImage = PLAY;
  474. }
  475. else
  476. {
  477. _pzax->Play();
  478. _fPlaying = TRUE;
  479. bi.iImage = PAUSE;
  480. }
  481. ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
  482. }
  483. break;
  484. case PAUSE:
  485. _pzax->Pause();
  486. break;
  487. case STOP:
  488. _pzax->Stop();
  489. _fPlaying = FALSE;
  490. break;
  491. case NEXT:
  492. _pzax->NextSong();
  493. break;
  494. case PREV:
  495. _pzax->PrevSong();
  496. break;
  497. case MENU:
  498. {
  499. _fEditorShown = !_fEditorShown;
  500. BOOL fToolbar = TRUE;
  501. HWND hwndToPutOnTopOf = _hwnd;
  502. if (_fEditorShown)
  503. {
  504. fToolbar = FALSE;
  505. hwndToPutOnTopOf = _pEdit->_hwnd;
  506. }
  507. _pEdit->Show(_fEditorShown);
  508. CenterOnTopOf(fToolbar, _hwndSongTile, hwndToPutOnTopOf);
  509. }
  510. break;
  511. }
  512. }
  513. return 1;
  514. }
  515. HRESULT CZaxxon::RecurseAddFile(IShellFolder* psf)
  516. {
  517. LPITEMIDLIST pidlItem;
  518. IEnumIDList* penum;
  519. if (SUCCEEDED(psf->EnumObjects(NULL, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &penum)))
  520. {
  521. ULONG l;
  522. while(S_OK == penum->Next(1, &pidlItem, &l))
  523. {
  524. if ((SHGetAttributes(psf, pidlItem, SFGAO_FOLDER) & SFGAO_FOLDER))
  525. {
  526. IShellFolder* psfNext;
  527. if (SUCCEEDED(SHBindToObjectEx(psf, pidlItem, NULL, IID_PPV_ARG(IShellFolder, &psfNext))))
  528. {
  529. RecurseAddFile(psfNext);
  530. psfNext->Release();
  531. }
  532. }
  533. else
  534. {
  535. TCHAR sz[MAX_PATH];
  536. DisplayNameOf(psf, pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
  537. PTSTR pszExtension = PathFindExtension(sz);
  538. if (StrCmpI(pszExtension, TEXT(".mp3")) == 0 ||
  539. StrCmpI(pszExtension, TEXT(".wma")) == 0)
  540. {
  541. _pzax->AddSong(sz);
  542. }
  543. }
  544. ILFree(pidlItem);
  545. }
  546. }
  547. return S_OK;
  548. }
  549. HRESULT CZaxxon::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  550. {
  551. HRESULT hr = S_FALSE;
  552. switch (uMsg)
  553. {
  554. case SMC_EXEC:
  555. {
  556. if (psmd->uId == 1)
  557. {
  558. IShellMenu* psm;
  559. if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
  560. {
  561. DWORD dwFlags;
  562. IShellFolder* psf;
  563. LPITEMIDLIST pidl;
  564. if (SUCCEEDED(psm->GetShellFolder(&dwFlags, &pidl, IID_PPV_ARG(IShellFolder, &psf))))
  565. {
  566. RecurseAddFile(psf);
  567. hr = S_OK;
  568. psf->Release();
  569. ILFree(pidl);
  570. }
  571. psm->Release();
  572. }
  573. }
  574. else if (psmd->uId == 2)
  575. {
  576. _pzax->ClearPlaylist();
  577. }
  578. }
  579. break;
  580. case SMC_SFEXEC:
  581. {
  582. TCHAR sz[MAX_PATH];
  583. DisplayNameOf(psmd->psf, psmd->pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
  584. PTSTR pszExtension = PathFindExtension(sz);
  585. if (StrCmpI(pszExtension, TEXT(".mp3")) == 0)
  586. {
  587. _pzax->AddSong(sz);
  588. }
  589. hr = S_OK;
  590. }
  591. break;
  592. case SMC_INITMENU:
  593. {
  594. IShellMenu* psm;
  595. if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
  596. {
  597. HMENU hmenu;
  598. DWORD dwFlags = SMSET_BOTTOM;
  599. if (psmd->uIdParent == 100)
  600. {
  601. hmenu = CreateMenu();
  602. AppendMenu(hmenu, MF_SEPARATOR, -1, NULL);
  603. AppendMenu(hmenu, MF_STRING, 2, TEXT("Clear Playlist"));
  604. AppendMenu(hmenu, MF_STRING, 1, TEXT("Play Folder"));
  605. }
  606. else
  607. {
  608. if (_hmenuOpenFolder == NULL)
  609. {
  610. _hmenuOpenFolder = CreateMenu();
  611. AppendMenu(_hmenuOpenFolder, MF_SEPARATOR, -1, NULL);
  612. AppendMenu(_hmenuOpenFolder, MF_STRING, 1, TEXT("Play Folder"));
  613. }
  614. dwFlags |= SMSET_DONTOWN;
  615. hmenu = _hmenuOpenFolder;
  616. }
  617. psm->SetMenu(hmenu, NULL, dwFlags);
  618. psm->Release();
  619. }
  620. return S_OK;
  621. }
  622. break;
  623. }
  624. return hr;
  625. }
  626. void CZaxxon::_DoMenu()
  627. {
  628. HRESULT hr;
  629. LPITEMIDLIST pidl = NULL;
  630. if (FAILED(SHGetSpecialFolderLocation(_hwnd, CSIDL_MYMUSIC, &pidl)))
  631. SHGetSpecialFolderLocation(_hwnd, CSIDL_MYDOCUMENTS, &pidl);
  632. if (pidl)
  633. {
  634. IShellFolder* psf;
  635. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf));
  636. if (SUCCEEDED(hr))
  637. {
  638. ITrackShellMenu* ptsm;
  639. hr = CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER, IID_ITrackShellMenu, (void**)&ptsm);
  640. if (SUCCEEDED(hr))
  641. {
  642. RECT rc;
  643. POINTL pt;
  644. ptsm->Initialize(this, 100, ANCESTORDEFAULT, SMINIT_TOPLEVEL | SMINIT_NOSETSITE | SMINIT_VERTICAL);
  645. ptsm->SetShellFolder(psf, pidl, NULL, SMSET_TOP | SMSET_USEBKICONEXTRACTION);
  646. ToolBar_GetRect(_hwnd, MENU, &rc);
  647. MapWindowPoints(_hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  648. pt.x = rc.left;
  649. pt.y = rc.top;
  650. ptsm->Popup(_hwnd, &pt, (RECTL*)&rc, MPPF_TOP);
  651. ptsm->Release();
  652. }
  653. psf->Release();
  654. }
  655. ILFree(pidl);
  656. }
  657. }
  658. LRESULT CZaxxon::_OnNotify(LPNMHDR pnm)
  659. {
  660. LRESULT lres = 0;
  661. switch(pnm->code)
  662. {
  663. case TBN_GETOBJECT:
  664. {
  665. NMOBJECTNOTIFY*pon = (NMOBJECTNOTIFY*)pnm;
  666. pon->hResult = QueryInterface(*pon->piid, &pon->pObject);
  667. lres = 1;
  668. }
  669. break;
  670. case TBN_HOTITEMCHANGE:
  671. {
  672. NMTBHOTITEM* phi = (NMTBHOTITEM*)pnm;
  673. if (phi->dwFlags & HICF_ENTERING)
  674. {
  675. _fAllowFadeout = FALSE;
  676. _fHide = FALSE;
  677. if (_fPlaying)
  678. {
  679. ShowWindow(_hwndSongTile, SW_SHOW);
  680. SetTimer(_hwndSongTile, 1, 30, NULL);
  681. KillTimer(_hwndSongTile, 2);
  682. }
  683. }
  684. else if (phi->dwFlags & HICF_LEAVING)
  685. {
  686. _fAllowFadeout = TRUE;
  687. _fHide = TRUE;
  688. SetTimer(_hwndSongTile, 1, 30, NULL);
  689. KillTimer(_hwndSongTile, 2);
  690. }
  691. }
  692. break;
  693. }
  694. return lres;
  695. }
  696. STDMETHODIMP CZaxxon::QueryInterface(REFIID riid, LPVOID * ppvObj)
  697. {
  698. static const QITAB qit[] = {
  699. QITABENT(CZaxxon, IWinEventHandler),
  700. QITABENT(CZaxxon, IDropTarget),
  701. { 0 },
  702. };
  703. HRESULT hres = QISearch(this, qit, riid, ppvObj);
  704. if (FAILED(hres))
  705. hres = CToolBand::QueryInterface(riid, ppvObj);
  706. return hres;
  707. }
  708. STDMETHODIMP CZaxxon::GetWindow(HWND * phwnd)
  709. {
  710. *phwnd = _CreateWindow(_hwndParent);
  711. return *phwnd? S_OK : E_FAIL;
  712. }
  713. STDMETHODIMP CZaxxon::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  714. DESKBANDINFO* pdbi)
  715. {
  716. LONG lButton = SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0L);
  717. UINT ucy;
  718. UINT ucx;
  719. if (fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL))
  720. {
  721. ucy = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
  722. ucx = LOWORD(lButton);
  723. }
  724. else
  725. {
  726. ucx = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
  727. ucy = LOWORD(lButton);
  728. }
  729. _dwBandID = dwBandID;
  730. _dwViewMode = fViewMode;
  731. pdbi->ptMinSize.x = LOWORD(lButton) * 1;
  732. pdbi->ptMinSize.y = ucy;
  733. pdbi->ptMaxSize.y = ucy;
  734. pdbi->ptMaxSize.x = ucx;
  735. pdbi->ptActual.y = ucy;
  736. pdbi->ptActual.x = ucx;
  737. pdbi->ptIntegral.y = 1;
  738. pdbi->ptIntegral.x = 1;
  739. if (pdbi->dwMask & DBIM_TITLE)
  740. {
  741. StrCpy(pdbi->wszTitle, TEXT("Zaxxon"));
  742. }
  743. return S_OK;
  744. }
  745. STDMETHODIMP CZaxxon::ShowDW(BOOL fShow)
  746. {
  747. return CToolBand::ShowDW(fShow);
  748. }
  749. STDMETHODIMP CZaxxon::CloseDW(DWORD dw)
  750. {
  751. SendMessage(_hwnd, TB_SETIMAGELIST, 0, NULL);
  752. SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, NULL);
  753. return CToolBand::CloseDW(dw);
  754. }
  755. STDMETHODIMP CZaxxon::TranslateAcceleratorIO(LPMSG lpMsg)
  756. {
  757. return E_NOTIMPL;
  758. }
  759. STDMETHODIMP CZaxxon::HasFocusIO()
  760. {
  761. return E_NOTIMPL;
  762. }
  763. STDMETHODIMP CZaxxon::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  764. {
  765. return S_OK;
  766. }
  767. STDMETHODIMP CZaxxon::IsWindowOwner(HWND hwnd)
  768. {
  769. return (hwnd == _hwnd)? S_OK : S_FALSE;
  770. }
  771. STDMETHODIMP CZaxxon::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  772. {
  773. HRESULT hres = S_FALSE;
  774. switch (dwMsg)
  775. {
  776. case WM_COMMAND:
  777. *plres = _OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
  778. hres = S_OK;
  779. break;
  780. case WM_NOTIFY:
  781. *plres = _OnNotify((LPNMHDR)lParam);
  782. hres = S_OK;
  783. break;
  784. case WM_ENDSESSION:
  785. _pzax->Stop();
  786. hres = S_OK;
  787. break;
  788. }
  789. return hres;
  790. }
  791. STDMETHODIMP CZaxxon::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  792. {
  793. *pdwEffect = DROPEFFECT_MOVE;
  794. return S_OK;
  795. }
  796. STDMETHODIMP CZaxxon::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  797. {
  798. return S_OK;
  799. }
  800. STDMETHODIMP CZaxxon::DragLeave(void)
  801. {
  802. return S_OK; // Yea so?
  803. }
  804. STDMETHODIMP CZaxxon::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  805. {
  806. STGMEDIUM medium;
  807. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  808. if (SUCCEEDED(pdtobj->GetData(&fmte, &medium)))
  809. {
  810. HDROP hdrop = (HDROP)medium.hGlobal;
  811. if (hdrop)
  812. {
  813. int c = DragQueryFile(hdrop, -1, NULL, 0);
  814. if (c > 0)
  815. {
  816. for (int i=0; i < c;i++)
  817. {
  818. TCHAR szPath[MAX_PATH];
  819. DragQueryFile(hdrop, i, szPath, ARRAYSIZE(szPath));
  820. _pzax->AddSong(szPath);
  821. }
  822. }
  823. }
  824. }
  825. return S_OK;
  826. }
  827. HRESULT CZaxxon_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
  828. {
  829. HRESULT hr;
  830. CZaxxon *pzax = new CZaxxon;
  831. if (pzax)
  832. {
  833. hr = pzax->QueryInterface(riid, ppv);
  834. pzax->Release();
  835. }
  836. else
  837. {
  838. hr = E_OUTOFMEMORY;
  839. *ppv = NULL;
  840. }
  841. return hr;
  842. }
  843. STDMETHODIMP CZaxxon::GetClassID(CLSID *pClassID)
  844. {
  845. *pClassID = CLSID_Zaxxon;
  846. return S_OK;
  847. }
  848. STDMETHODIMP CZaxxon::Load(IStream *pStm)
  849. {
  850. return S_OK;
  851. }
  852. STDMETHODIMP CZaxxon::Save(IStream *pStm, BOOL fClearDirty)
  853. {
  854. return S_OK;
  855. }