dwm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #include "main.h"
  2. #include "config.h"
  3. #include "wintheme.h"
  4. #include <shobjidl.h>
  5. #include <tataki/canvas/bltcanvas.h>
  6. #include <tataki/bitmap/bitmap.h>
  7. #include "../Agave/Language/api_language.h"
  8. typedef HRESULT(WINAPI *DWMREGISTERTHUMBNAIL)(HWND hwndDestination, HWND hwndSource, void **phThumbnailId);
  9. typedef HRESULT(WINAPI *DWMUPATETHUMBNAILPROPERTIES)(void* hThumbnailId, void* ptnProperties);
  10. typedef HRESULT(WINAPI *DWMUNREGISTERTHUMBNAIL)(void *hThumbnailId);
  11. typedef HRESULT(WINAPI *DWMSETWINDOWATTRIBUTE)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
  12. typedef HRESULT (WINAPI *DWMENABLEMMCSS)(BOOL fEnableMMCSS);
  13. typedef HRESULT (WINAPI *DWMSETICONICTHUMBNAIL)(HWND hwnd, HBITMAP hbmp, DWORD dwSITFlags);
  14. typedef HRESULT (WINAPI *DWMINVALIDATEICONICBITMAPS)( HWND hwnd);
  15. typedef HRESULT (WINAPI *DWMSETICONICLIVEPREVIEWBITMAP )(HWND hwnd, HBITMAP hbmp, POINT *pptClient, DWORD dwSITFlags);
  16. static HMODULE dwmapi;
  17. static void *thumbnail;
  18. static DWMREGISTERTHUMBNAIL regThumbnail;
  19. static DWMUPATETHUMBNAILPROPERTIES updateProp;
  20. static DWMUNREGISTERTHUMBNAIL unregThumbnail;
  21. static DWMSETWINDOWATTRIBUTE setWindowAttribute;
  22. static DWMENABLEMMCSS dwmEnableMMCSS;
  23. static DWMSETICONICTHUMBNAIL dwmSetIconicThumbnail;
  24. static DWMINVALIDATEICONICBITMAPS dwmInvalidateIconicBitmaps;
  25. static DWMSETICONICLIVEPREVIEWBITMAP dwmSetIconicLivePreviewBitmap;
  26. HIMAGELIST toolbarIcons = NULL;
  27. BOOL atti_present=false;
  28. static bool triedLoad=false;
  29. static bool LoadDWMApi()
  30. {
  31. if (!triedLoad)
  32. {
  33. wchar_t gen_win7shell_path[MAX_PATH] = {0};
  34. PathCombineW(gen_win7shell_path, PLUGINDIR, L"gen_win7shell.dll");
  35. HMODULE gen_win7shell = LoadLibraryW(gen_win7shell_path);
  36. if (gen_win7shell)
  37. {
  38. atti_present=true;
  39. FreeLibrary(gen_win7shell);
  40. }
  41. dwmapi = LoadLibraryA("dwmapi.dll");
  42. regThumbnail = (DWMREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmRegisterThumbnail");
  43. updateProp = (DWMUPATETHUMBNAILPROPERTIES)GetProcAddress(dwmapi, "DwmUpdateThumbnailProperties");
  44. unregThumbnail = (DWMUNREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmUnregisterThumbnail");
  45. setWindowAttribute = (DWMSETWINDOWATTRIBUTE)GetProcAddress(dwmapi, "DwmSetWindowAttribute");
  46. dwmEnableMMCSS = (DWMENABLEMMCSS)GetProcAddress(dwmapi, "DwmEnableMMCSS");
  47. dwmSetIconicThumbnail = (DWMSETICONICTHUMBNAIL)GetProcAddress(dwmapi, "DwmSetIconicThumbnail");
  48. dwmInvalidateIconicBitmaps = (DWMINVALIDATEICONICBITMAPS)GetProcAddress(dwmapi, "DwmInvalidateIconicBitmaps");
  49. dwmSetIconicLivePreviewBitmap = (DWMSETICONICLIVEPREVIEWBITMAP)GetProcAddress(dwmapi, "DwmSetIconicLivePreviewBitmap");
  50. triedLoad = true;
  51. }
  52. return dwmapi && regThumbnail && updateProp && unregThumbnail && setWindowAttribute && dwmEnableMMCSS;
  53. }
  54. bool LoadToolbarIcons()
  55. {
  56. //toolbarIcons already loaded
  57. if (toolbarIcons != NULL)
  58. {
  59. return true;
  60. }
  61. //load toolbarIcons
  62. toolbarIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 5, 0);
  63. if (toolbarIcons == NULL)
  64. return false;
  65. for (int i = 0; i < 5; i++)
  66. {
  67. HICON hIcon = LoadIconW(hMainInstance, MAKEINTRESOURCE(IDI_TBICON1+i));
  68. if (hIcon != NULL)
  69. ImageList_AddIcon(toolbarIcons, hIcon);
  70. // no need to call DestroyIcon(..) if using LoadIcon(..)
  71. // as the OS will free things anyway - might be cause of
  72. // the random button disappearing issue...?
  73. //DestroyIcon(hIcon);
  74. }
  75. return true;
  76. }
  77. static BOOL taskbar_inited = FALSE;
  78. void OnTaskbarButtonCreated(BOOL force)
  79. {
  80. if (pTaskbar3 || (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
  81. IID_PPV_ARGS(&pTaskbar3))) && pTaskbar3))
  82. {
  83. if (force)
  84. {
  85. taskbar_inited = TRUE;
  86. pTaskbar3->HrInit();
  87. }
  88. if (taskbar_inited)
  89. {
  90. RegisterThumbnailTab(IsWindow(g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow);
  91. }
  92. }
  93. }
  94. void UnregisterThumbnailTab(HWND hWnd)
  95. {
  96. if (LoadDWMApi() && !atti_present)
  97. {
  98. if (!IsVistaOrLower() && IsWindow(hWnd) && pTaskbar3 != NULL)
  99. {
  100. if (taskbar_inited)
  101. pTaskbar3->UnregisterTab(hWnd);
  102. }
  103. }
  104. }
  105. static void addToolbarButtons(HWND hWnd, BOOL update)
  106. {
  107. THUMBBUTTON thbButtons[5];
  108. DWORD dwMask = THB_BITMAP | THB_TOOLTIP;
  109. thbButtons[0].dwMask = (THUMBBUTTONMASK)dwMask;
  110. thbButtons[0].iId = 0;
  111. thbButtons[0].iBitmap = 0;
  112. StringCbCopyW(thbButtons[0].szTip, sizeof(thbButtons[0].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PREVIOUS, NULL, 0));
  113. thbButtons[1].dwMask = (THUMBBUTTONMASK)dwMask;
  114. thbButtons[1].iId = 1;
  115. thbButtons[1].iBitmap = 1;
  116. StringCbCopyW(thbButtons[1].szTip, sizeof(thbButtons[1].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PLAY, NULL, 0));
  117. thbButtons[2].dwMask = (THUMBBUTTONMASK)dwMask;
  118. thbButtons[2].iId = 2;
  119. thbButtons[2].iBitmap = 2;
  120. StringCbCopyW(thbButtons[2].szTip, sizeof(thbButtons[2].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PAUSE, NULL, 0));
  121. thbButtons[3].dwMask = (THUMBBUTTONMASK)dwMask;
  122. thbButtons[3].iId = 3;
  123. thbButtons[3].iBitmap = 3;
  124. StringCbCopyW(thbButtons[3].szTip, sizeof(thbButtons[3].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_STOP, NULL, 0));
  125. thbButtons[4].dwMask = (THUMBBUTTONMASK)dwMask;
  126. thbButtons[4].iId = 4;
  127. thbButtons[4].iBitmap = 4;
  128. StringCbCopyW(thbButtons[4].szTip, sizeof(thbButtons[4].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_NEXT, NULL, 0));
  129. if (update)
  130. pTaskbar3->ThumbBarUpdateButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
  131. else
  132. pTaskbar3->ThumbBarAddButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
  133. }
  134. void RegisterThumbnailTab(HWND hWnd)
  135. {
  136. if (LoadDWMApi() && !atti_present)
  137. {
  138. if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
  139. dwmInvalidateIconicBitmaps(hMainWindow);
  140. if (!IsWindow(hWnd))
  141. {
  142. hWnd = hMainWindow;
  143. }
  144. if (hWnd != hMainWindow)
  145. {
  146. wchar_t title[512] = {0};
  147. GetWindowTextW(hMainWindow, title, sizeof(title));
  148. SetWindowTextW(hWnd, title);
  149. #ifdef WIN64
  150. HICON hIcon = (HICON)GetClassLongPtr(hMainWindow, GCLP_HICONSM);
  151. #else
  152. HICON hIcon = (HICON)GetClassLong(hMainWindow, GCL_HICONSM);
  153. #endif
  154. SendMessageW(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
  155. }
  156. if (IsWindow(hWnd) && IsWindow(hMainWindow))
  157. {
  158. BOOL dwm_setting = FALSE;
  159. setWindowAttribute(hWnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
  160. setWindowAttribute(hWnd, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
  161. if (!IsVistaOrLower() && pTaskbar3 != NULL)
  162. {
  163. // shouldn't fail, but there's a case on loading where it can due to timing quirks
  164. // so for that we then allow the regsistation to still happen (hence the dup code)
  165. HRESULT hr = pTaskbar3->RegisterTab(hWnd, hMainWindow);
  166. if (SUCCEEDED(hr))
  167. {
  168. if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
  169. {
  170. pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
  171. if (LoadToolbarIcons())
  172. {
  173. HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
  174. if (SUCCEEDED(hr))
  175. {
  176. addToolbarButtons(hWnd, false);
  177. }
  178. }
  179. }
  180. }
  181. else
  182. {
  183. if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
  184. {
  185. pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
  186. if (LoadToolbarIcons())
  187. {
  188. HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
  189. if (SUCCEEDED(hr))
  190. {
  191. addToolbarButtons(hWnd, false);
  192. }
  193. }
  194. }
  195. }
  196. }
  197. if (hWnd != hMainWindow)
  198. {
  199. dwm_setting = TRUE;
  200. setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
  201. setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
  202. }
  203. }
  204. }
  205. }
  206. void DisableVistaPreview()
  207. {
  208. if (LoadDWMApi())
  209. {
  210. BOOL blah=TRUE;
  211. setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &blah, sizeof(blah));
  212. setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &blah, sizeof(blah));
  213. }
  214. }
  215. static bool done_the_dance=false;
  216. void DoTheVistaVideoDance()
  217. {
  218. if (!done_the_dance && LoadDWMApi())
  219. {
  220. dwmEnableMMCSS(TRUE); // the magic "make my program not suck" function
  221. /* TODO:
  222. DWM_PRESENT_PARAMETERS dpp;
  223. memset(&dpp, 0, sizeof(dpp));
  224. dpp.cbSize = sizeof(dpp);
  225. dpp.fQueue = true;
  226. dpp.cBuffer = 8;
  227. dpp.fUseSourceRate = false;
  228. dpp.cRefreshesPerFrame = 1;
  229. dpp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
  230. HRESULT hr = DwmSetPresentParameters(hWnd, &dpp);
  231. */
  232. // TODO also, unrelated, but check out AvSetMmThreadCharacteristics sometime.
  233. }
  234. done_the_dance = true;
  235. }
  236. static void Adjust(int bmpw, int bmph, RECT &r)
  237. {
  238. // maintain 'square' stretching
  239. int w = r.right - r.left;
  240. int h = r.bottom - r.top;
  241. double aspX = (double)(w)/(double)bmpw;
  242. double aspY = (double)(h)/(double)bmph;
  243. double asp = min(aspX, aspY);
  244. int newW = (int)(bmpw*asp);
  245. int newH = (int)(bmph*asp);
  246. r.left = (w - newW)/2;
  247. r.top = (h - newH)/2;
  248. r.right = r.left + newW;
  249. r.bottom = r.top + newH;
  250. }
  251. void RefreshIconicThumbnail()
  252. {
  253. if (LoadDWMApi() && !atti_present)
  254. {
  255. if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
  256. dwmInvalidateIconicBitmaps(hMainWindow);
  257. }
  258. }
  259. void OnIconicThumbnail(int width, int height)
  260. {
  261. static BltCanvas *iconic_thumbnail_bitmap=0;
  262. HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
  263. RECT client_size;
  264. GetClientRect(hWnd, &client_size);
  265. if (!iconic_thumbnail_bitmap)
  266. {
  267. iconic_thumbnail_bitmap = new BltCanvas(client_size.right, client_size.bottom, hMainWindow);
  268. }
  269. else
  270. {
  271. iconic_thumbnail_bitmap->DestructiveResize(client_size.right, client_size.bottom);
  272. }
  273. SendMessageW(hWnd, WM_PRINTCLIENT, (WPARAM) iconic_thumbnail_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | /*PRF_ERASEBKGND |*/ PRF_NONCLIENT /*| PRF_OWNED*/);
  274. void *bits=0;
  275. BITMAPINFO bmi = {0};
  276. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  277. bmi.bmiHeader.biWidth = width;
  278. bmi.bmiHeader.biHeight = -height;
  279. bmi.bmiHeader.biPlanes = 1;
  280. bmi.bmiHeader.biBitCount = 32;
  281. bmi.bmiHeader.biCompression = BI_RGB;
  282. HBITMAP hbmp = CreateDIBSection(iconic_thumbnail_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
  283. if (hbmp)
  284. {
  285. BltCanvas resizedBitmap(hbmp);
  286. int x=0, y=0;
  287. RECT dest;
  288. dest.left = x;
  289. dest.top = y;
  290. dest.right = width;
  291. dest.bottom = height;
  292. resizedBitmap.drawRect(&dest, 1, 0);
  293. Adjust(client_size.right, client_size.bottom, dest);
  294. iconic_thumbnail_bitmap->stretchToRectAlpha(&resizedBitmap, &client_size, &dest);
  295. dwmSetIconicThumbnail(hMainWindow, hbmp, 0);
  296. }
  297. }
  298. void OnThumbnailPreview()
  299. {
  300. static BltCanvas *thumbnail_preview_bitmap=0;
  301. HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
  302. RECT client_size;
  303. GetClientRect(hWnd, &client_size);
  304. if (!thumbnail_preview_bitmap)
  305. {
  306. thumbnail_preview_bitmap = new BltCanvas(client_size.right, client_size.bottom, hWnd);
  307. }
  308. else
  309. {
  310. thumbnail_preview_bitmap->DestructiveResize(client_size.right, client_size.bottom);
  311. }
  312. SendMessageW(hWnd, WM_PRINT, (WPARAM) thumbnail_preview_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT /*| PRF_OWNED*/);
  313. void *bits=0;
  314. BITMAPINFO bmi = {0};
  315. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  316. bmi.bmiHeader.biWidth = client_size.right - client_size.left;
  317. bmi.bmiHeader.biHeight = client_size.top - client_size.bottom;
  318. bmi.bmiHeader.biPlanes = 1;
  319. bmi.bmiHeader.biBitCount = 32;
  320. bmi.bmiHeader.biCompression = BI_RGB;
  321. HBITMAP hbmp = CreateDIBSection(thumbnail_preview_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
  322. if (hbmp)
  323. {
  324. POINT offset;
  325. offset.x = client_size.left;
  326. offset.y = client_size.top;
  327. if (dwmSetIconicLivePreviewBitmap(hWnd, hbmp, &offset, 1) == S_OK)
  328. {
  329. MessageBoxA(NULL, "winamp/live", "winamp/live", MB_OK);
  330. }
  331. else
  332. {
  333. MessageBoxA(NULL, "winamp/no live", "winamp/no live", MB_OK);
  334. }
  335. }
  336. }