dxcontext.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. /*
  2. LICENSE
  3. -------
  4. Copyright 2005-2013 Nullsoft, Inc.
  5. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without modification,
  7. are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright notice,
  9. this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. * Neither the name of Nullsoft nor the names of its contributors may be used to
  14. endorse or promote products derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  16. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  21. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  22. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "api__vis_milk2.h"
  25. #include "DXContext.h"
  26. #include "utility.h"
  27. #include "shell_defines.h"
  28. #include "resource.h"
  29. #define COMPILE_MULTIMON_STUBS 1
  30. #include <multimon.h>
  31. #include <strsafe.h>
  32. // note: added WS_EX_CONTROLPARENT and WS_TABSTOP for embedwnd so window frame will pass on KB commands to us, if it has focus & receives them.
  33. // however, it is still not working. Maksim says he needs to use GetNextDlgTabItem() and then it will work.
  34. // aha- had to remove WS_EX_CONTROLPARENT and WS_OVERLAPPED. Should now work with winamp 5.5 build 1620.
  35. #define MY_EXT_WINDOW_STYLE (m_current_mode.m_skin ? 0/*WS_EX_CONTROLPARENT*/ : ((m_current_mode.screenmode==DESKTOP) ? (WS_EX_TOOLWINDOW) : 0)) // note: changed from TOOLWINDOW to APPWINDOW b/c we wanted the plugin to appear in the taskbar.
  36. #define SKINNED_WS (WS_VISIBLE|WS_CHILDWINDOW/*|WS_OVERLAPPED*/|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TABSTOP)
  37. #define MY_WINDOW_STYLE (m_current_mode.m_skin ? SKINNED_WS : ((m_current_mode.screenmode==FAKE_FULLSCREEN || m_current_mode.screenmode==DESKTOP) ? WS_POPUP : WS_OVERLAPPEDWINDOW)) // note: WS_POPUP (by itself) removes all borders, captions, etc.
  38. #include "vis.h"
  39. extern winampVisModule mod1;
  40. DXContext::DXContext(HWND hWndWinamp,HINSTANCE hInstance,LPCWSTR szClassName,LPCSTR szWindowCaption,WNDPROC pProc,LONG_PTR uWindowLong, int minimize_winamp, wchar_t* szIniFile)
  41. {
  42. m_classAtom = 0;
  43. m_szWindowCaption[0] = 0;
  44. m_hwnd = NULL;
  45. m_lpD3D = NULL;
  46. m_lpDevice = NULL;
  47. m_hmod_d3d9 = NULL;
  48. m_hmod_d3dx9 = NULL;
  49. m_zFormat = D3DFMT_UNKNOWN;
  50. for (int i=0; i<MAX_DXC_ADAPTERS; i++)
  51. m_orig_windowed_mode_format[i] = D3DFMT_UNKNOWN;
  52. m_ordinal_adapter = D3DADAPTER_DEFAULT;
  53. m_ignore_wm_destroy = 0;
  54. m_hwnd_winamp = hWndWinamp;
  55. m_minimize_winamp = minimize_winamp;
  56. m_winamp_minimized = 0;
  57. m_truly_exiting = 0;
  58. m_bpp = 0;
  59. m_frame_delay = 0;
  60. StringCbCopyW(m_szIniFile, sizeof(m_szIniFile), szIniFile);
  61. memset(&myWindowState,0,sizeof(myWindowState));
  62. m_szDriver[0] = 0;
  63. m_szDesc[0] = 0;
  64. WNDCLASSW wc = {0};
  65. // clear the error register
  66. m_lastErr = S_OK;
  67. // clear the active flag
  68. m_ready=FALSE;
  69. // Set up and register window class
  70. wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode...
  71. wc.lpfnWndProc = (WNDPROC) pProc;
  72. wc.cbWndExtra = sizeof(DWORD);
  73. wc.hInstance = hInstance;
  74. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PLUGIN_ICON));//NULL;
  75. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  76. wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  77. wc.lpszMenuName = NULL;
  78. wc.lpszClassName = szClassName;
  79. m_classAtom = RegisterClassW(&wc);
  80. if (!m_classAtom)
  81. {
  82. wchar_t title[64];
  83. int y = GetLastError();
  84. m_lastErr = DXC_ERR_REGWIN;
  85. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_REGISTER_WINDOW_CLASS),
  86. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  87. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  88. Internal_CleanUp();
  89. return;
  90. }
  91. StringCbCopy(m_szWindowCaption, sizeof(m_szWindowCaption), szWindowCaption);
  92. m_hInstance = hInstance;
  93. m_uWindowLong = uWindowLong;
  94. }
  95. DXContext::~DXContext()
  96. {
  97. Internal_CleanUp();
  98. }
  99. void DXContext::Internal_CleanUp()
  100. {
  101. // clear active flag
  102. m_ready=FALSE;
  103. // release 3D interfaces
  104. SafeRelease(m_lpDevice);
  105. SafeRelease(m_lpD3D);
  106. // destroy the window
  107. if (m_truly_exiting)
  108. {
  109. // somebody else will destroy the window for us!
  110. m_hwnd = NULL;
  111. if (m_hmod_d3d9)
  112. {
  113. FreeLibrary(m_hmod_d3d9);
  114. m_hmod_d3d9 = NULL;
  115. }
  116. if (m_hmod_d3dx9)
  117. {
  118. m_hmod_d3dx9 = NULL;
  119. }
  120. }
  121. if (myWindowState.me)
  122. {
  123. DestroyWindow(myWindowState.me);
  124. myWindowState.me = NULL;
  125. m_hwnd = NULL;
  126. }
  127. else if (m_hwnd)
  128. {
  129. DestroyWindow(m_hwnd);
  130. m_hwnd = NULL;
  131. }
  132. // unregister window class. note: only works if window is already destroyed!
  133. if (m_classAtom)
  134. {
  135. UnregisterClass(MAKEINTATOM(m_classAtom), m_hInstance);
  136. m_classAtom = 0;
  137. }
  138. RestoreWinamp();
  139. }
  140. void DXContext::GetSnappedClientSize()
  141. {
  142. // Call this whenever you set m_REAL_client_width/height while in windowed mode,
  143. // to compute an appropriate (oversized) internal canvas size. At the end of each
  144. // frame, for display, the canvas will be centered & cropped.
  145. m_client_width = m_REAL_client_width;
  146. m_client_height = m_REAL_client_height;
  147. #if (SNAP_WINDOWED_MODE_BLOCKSIZE >= 1)
  148. if (m_current_mode.screenmode == WINDOWED)
  149. {
  150. // oversize it - then we'll just crop - so onscreen text has no stretching :)
  151. m_client_width = max(1, (m_REAL_client_width + 31)/32)*32;
  152. m_client_height = max(1, (m_REAL_client_height + 31)/32)*32;
  153. }
  154. #endif
  155. }
  156. BOOL DXContext::TestFormat(int ordinal_adapter, D3DFORMAT fmt)
  157. {
  158. if (D3D_OK==m_lpD3D->CheckDeviceType(ordinal_adapter,D3DDEVTYPE_HAL,fmt,fmt,FALSE))
  159. return TRUE;
  160. return FALSE;
  161. }
  162. BOOL DXContext::TestDepth(int ordinal_adapter, D3DFORMAT fmt)
  163. {
  164. if (D3D_OK!=m_lpD3D->CheckDeviceFormat(ordinal_adapter,D3DDEVTYPE_HAL,m_current_mode.display_mode.Format,
  165. D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,fmt))
  166. return FALSE;
  167. if (D3D_OK!=m_lpD3D->CheckDepthStencilMatch(ordinal_adapter,D3DDEVTYPE_HAL,
  168. m_current_mode.display_mode.Format,m_current_mode.display_mode.Format,fmt))
  169. return FALSE;
  170. return TRUE;
  171. }
  172. int DXContext::CheckAndCorrectFullscreenDispMode(int ordinal_adapter, D3DDISPLAYMODE *pdm)
  173. {
  174. // given the user's choice of fullscreen display mode,
  175. // go through all the display modes available to the currently-selected adapter
  176. // and find the best match.
  177. // returns 1 if it altered pdm to the best match,
  178. // or 0 if it was able to find a perfect match.
  179. // if it returns 1, you might want to notify the user.
  180. #define MAX_DISPLAY_MODES 4096
  181. D3DDISPLAYMODE list[MAX_DISPLAY_MODES];
  182. int nCount = min(m_lpD3D->GetAdapterModeCount(ordinal_adapter, D3DFMT_A8R8G8B8), MAX_DISPLAY_MODES);
  183. int nValid = 0;
  184. for (int i=0; i<nCount; i++)
  185. if (m_lpD3D->EnumAdapterModes(ordinal_adapter, D3DFMT_A8R8G8B8, i, &list[nValid]) == D3D_OK)
  186. nValid++;
  187. // do many passes through the set until we find a match,
  188. // each time relaxing more constraints.
  189. // outline of the passes:
  190. int bpp_desired = 0;
  191. switch (pdm->Format)
  192. {
  193. case D3DFMT_R8G8B8 : bpp_desired = 32; break;
  194. case D3DFMT_A8R8G8B8: bpp_desired = 32; break;
  195. case D3DFMT_X8R8G8B8: bpp_desired = 32; break;
  196. case D3DFMT_R5G6B5 : bpp_desired = 16; break;
  197. case D3DFMT_X1R5G5B5: bpp_desired = 16; break;
  198. case D3DFMT_A1R5G5B5: bpp_desired = 16; break;
  199. case D3DFMT_A4R4G4B4: bpp_desired = 16; break;
  200. case D3DFMT_R3G3B2 : bpp_desired = 8; break;
  201. case D3DFMT_A8R3G3B2: bpp_desired = 16; break;
  202. case D3DFMT_X4R4G4B4: bpp_desired = 16; break;
  203. }
  204. // rep MATCH:
  205. // 0. w,h,r,f
  206. // 1. w,h,-,f
  207. // 2. w,h,r,- pass:
  208. // 3. w,h,-,- -on pass 0, for 'f', match exact format
  209. // 4. 8,6,r,f -on pass 1, for 'f', just match # of bits per pixel
  210. // 5. 8,6,-,f (more relaxed match)
  211. // 6. 8,6,r,-
  212. // 7. 8,6,-,-
  213. // 8. -,-,r,f
  214. // 9. -,-,-,f
  215. // 10. -,-,r,-
  216. // 11. -,-,-,-
  217. int found = 0;
  218. for (int rep=0; rep<12 && !found; rep++)
  219. {
  220. for (int pass=0; pass<2 && !found; pass++)
  221. {
  222. for (int i=0; i<nValid && !found; i++)
  223. {
  224. bool bMatch = true;
  225. int bpp_this_mode = 0;
  226. switch (list[i].Format)
  227. {
  228. case D3DFMT_R8G8B8 : bpp_this_mode = 32; break;
  229. case D3DFMT_A8R8G8B8: bpp_this_mode = 32; break;
  230. case D3DFMT_X8R8G8B8: bpp_this_mode = 32; break;
  231. case D3DFMT_R5G6B5 : bpp_this_mode = 16; break;
  232. case D3DFMT_X1R5G5B5: bpp_this_mode = 16; break;
  233. case D3DFMT_A1R5G5B5: bpp_this_mode = 16; break;
  234. case D3DFMT_A4R4G4B4: bpp_this_mode = 16; break;
  235. case D3DFMT_R3G3B2 : bpp_this_mode = 8; break;
  236. case D3DFMT_A8R3G3B2: bpp_this_mode = 16; break;
  237. case D3DFMT_X4R4G4B4: bpp_this_mode = 16; break;
  238. }
  239. if (rep < 4)
  240. {
  241. if (pdm->Width != list[i].Width)
  242. bMatch = false;
  243. if (pdm->Height != list[i].Height)
  244. bMatch = false;
  245. }
  246. else if (rep < 8)
  247. {
  248. if (DEFAULT_FULLSCREEN_WIDTH != list[i].Width)
  249. bMatch = false;
  250. if (DEFAULT_FULLSCREEN_HEIGHT != list[i].Height)
  251. bMatch = false;
  252. }
  253. if (((rep/2)%2)==0)
  254. {
  255. if (pass==0 && pdm->Format != list[i].Format)
  256. bMatch = false;
  257. else if (pass==1 && bpp_desired != bpp_this_mode)
  258. bMatch = false;
  259. }
  260. if (((rep%2)==0) && pdm->RefreshRate != list[i].RefreshRate)
  261. {
  262. bMatch = false;
  263. }
  264. if (bMatch)
  265. {
  266. memcpy(pdm, &list[i], sizeof(D3DDISPLAYMODE));
  267. found = 1;
  268. if (rep != 0 || pass != 0)
  269. {
  270. return 1;
  271. }
  272. }
  273. }
  274. }
  275. }
  276. return 0;
  277. }
  278. BOOL CALLBACK MyMonitorEnumProc(
  279. HMONITOR hMonitor, // handle to display monitor
  280. HDC hdcMonitor, // handle to monitor DC
  281. LPRECT lprcMonitor, // monitor intersection rectangle
  282. LPARAM dwData // data
  283. )
  284. {
  285. RECT* p = (RECT*)dwData;
  286. if (hMonitor)
  287. {
  288. MONITORINFO mi;
  289. mi.cbSize = sizeof(mi);
  290. if (GetMonitorInfo(hMonitor, &mi))
  291. {
  292. p->top = min(p->top , mi.rcMonitor.top);
  293. p->left = min(p->left , mi.rcMonitor.left);
  294. p->right = max(p->right , mi.rcMonitor.right);
  295. p->bottom = max(p->bottom, mi.rcMonitor.bottom);
  296. }
  297. }
  298. return TRUE;
  299. }
  300. int DXContext::GetWindowedModeAutoSize(int iteration)
  301. {
  302. // note: requires 'm_monitor_rect' has been set!
  303. // generically determine size of window, for windowed mode:
  304. int x = m_monitor_rect.right-m_monitor_rect.left;
  305. int y = m_monitor_rect.bottom-m_monitor_rect.top;
  306. // if running in horz/vert-span multi-display mode, base the window size on
  307. // an actual display size, not the giant double-sized monitor. Also, position
  308. // the window on the same monitor that Winamp is on.
  309. if (x >= y*2)
  310. {
  311. x /= 2;
  312. // move window to same display that Winamp is on:
  313. WINDOWPLACEMENT wp;
  314. wp.length = sizeof(wp);
  315. if (GetWindowPlacement(m_hwnd_winamp, &wp))
  316. {
  317. int winamp_center_x = (wp.rcNormalPosition.right + wp.rcNormalPosition.left)/2;
  318. if (winamp_center_x > x)
  319. {
  320. m_monitor_rect.left += x;
  321. m_monitor_rect.right += x;
  322. }
  323. }
  324. }
  325. else if (y > x*4/3)
  326. {
  327. y /= 2;
  328. // move window to same display that Winamp is on:
  329. WINDOWPLACEMENT wp;
  330. wp.length = sizeof(wp);
  331. if (GetWindowPlacement(m_hwnd_winamp, &wp))
  332. {
  333. int winamp_center_y = (wp.rcNormalPosition.top + wp.rcNormalPosition.bottom)/2;
  334. if (winamp_center_y > y)
  335. {
  336. m_monitor_rect.top += y;
  337. m_monitor_rect.bottom += y;
  338. }
  339. }
  340. }
  341. int size = min(x, y);
  342. size = (int)(size*DEFAULT_WINDOW_SIZE);
  343. size = (size/64 - iteration)*64;
  344. if (size < 64)
  345. size = 64;
  346. return size;
  347. }
  348. void DXContext::WriteSafeWindowPos()
  349. {
  350. if (m_current_mode.screenmode == WINDOWED)
  351. {
  352. WritePrivateProfileIntW(64, L"nMainWndTop", m_szIniFile, L"settings");
  353. WritePrivateProfileIntW(64, L"nMainWndLeft", m_szIniFile, L"settings");
  354. WritePrivateProfileIntW(64+256, L"nMainWndRight", m_szIniFile, L"settings");
  355. WritePrivateProfileIntW(64+256, L"nMainWndBottom", m_szIniFile, L"settings");
  356. WritePrivateProfileIntW(64, L"avs_wx",m_szIniFile,L"settings");
  357. WritePrivateProfileIntW(64, L"avs_wy",m_szIniFile,L"settings");
  358. WritePrivateProfileIntW(256, L"avs_ww",m_szIniFile,L"settings");
  359. WritePrivateProfileIntW(256, L"avs_wh",m_szIniFile,L"settings");
  360. }
  361. }
  362. // {0000000A-000C-0010-FF7B-01014263450C}
  363. const GUID avs_guid =
  364. { 10, 12, 16, { 255, 123, 1, 1, 66, 99, 69, 12 } };
  365. BOOL DXContext::Internal_Init(DXCONTEXT_PARAMS *pParams, BOOL bFirstInit)
  366. {
  367. memcpy(&m_current_mode, pParams, sizeof(DXCONTEXT_PARAMS));
  368. memset(&myWindowState,0,sizeof(myWindowState));
  369. // various checks
  370. if (m_current_mode.screenmode != WINDOWED)
  371. m_current_mode.m_skin = 0;
  372. // 1. destroy old window
  373. if (m_hwnd)
  374. {
  375. m_ignore_wm_destroy = 1;
  376. DestroyWindow(m_hwnd);
  377. m_ignore_wm_destroy = 0;
  378. m_hwnd = NULL;
  379. }
  380. // 2. CHECK TO MAKE SURE DIRECTX/DDRAW IS INSTALLED
  381. if (bFirstInit)
  382. {
  383. // Test for DirectX 9 + start it
  384. // note: if you don't call LoadLibrary here, and you're on a system
  385. // where DX9 is missing, Direct3DCreate8() might crash; so call it.
  386. int d3d9_already_loaded = (GetModuleHandle("d3d9.dll") != NULL) ? 1 : 0;
  387. if (!d3d9_already_loaded)
  388. m_hmod_d3d9 = LoadLibrary("d3d9.dll");
  389. if ((!d3d9_already_loaded && !m_hmod_d3d9) ||
  390. !(m_lpD3D = Direct3DCreate9(D3D_SDK_VERSION))
  391. )
  392. {
  393. MissingDirectX(NULL);
  394. m_lastErr = DXC_ERR_CREATE3D;
  395. return FALSE;
  396. }
  397. if (!m_hmod_d3dx9)
  398. m_hmod_d3dx9 = FindD3DX9(m_hwnd_winamp);
  399. if ((!m_hmod_d3dx9))
  400. {
  401. MissingDirectX(NULL);
  402. m_lastErr = DXC_ERR_CREATE3D;
  403. return FALSE;
  404. }
  405. }
  406. // 3. get the smallest single rectangle that encloses ALL the monitors on the desktop:
  407. SetRect(&m_all_monitors_rect, 0, 0, 0, 0);
  408. EnumDisplayMonitors(NULL, NULL, MyMonitorEnumProc, (LPARAM)&m_all_monitors_rect);
  409. // 4. some DirectX- / DDraw-specific stuff. Also determine hPluginMonitor.
  410. HMONITOR hPluginMonitor = NULL;
  411. {
  412. D3DADAPTER_IDENTIFIER9 temp;
  413. // find the ordinal # of the adapter whose GUID matches what the user picked from the config panel,
  414. // and whose DeviceName matches as well.
  415. // if no match found, use D3DADAPTER_DEFAULT.
  416. m_ordinal_adapter = D3DADAPTER_DEFAULT;
  417. int nAdapters = m_lpD3D->GetAdapterCount();
  418. {
  419. for (int i=0; i<nAdapters; i++)
  420. {
  421. if ((m_lpD3D->GetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) &&
  422. (memcmp(&temp.DeviceIdentifier, &m_current_mode.adapter_guid, sizeof(GUID))==0) &&
  423. !strcmp(temp.DeviceName, m_current_mode.adapter_devicename)
  424. )
  425. {
  426. m_ordinal_adapter = i;
  427. break;
  428. }
  429. }
  430. }
  431. if (m_lpD3D->GetAdapterIdentifier(m_ordinal_adapter, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK)
  432. {
  433. StringCbCopy(m_szDriver, sizeof(m_szDriver), temp.Driver);
  434. StringCbCopy(m_szDesc, sizeof(m_szDesc), temp.Description);
  435. }
  436. int caps_ok = 0;
  437. int caps_tries = 0;
  438. int changed_fs_disp_mode;
  439. // try to get the device caps for the adapter selected from the config panel.
  440. // if GetDeviceCaps() fails, it's probably because the adapter has been
  441. // removed from the system (or disabled), so we try again with other adapter(s).
  442. do
  443. {
  444. changed_fs_disp_mode = 0;
  445. SetRect(&m_monitor_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  446. // get bounding rect of the monitor attached to the adapter (to assist w/window positioning)
  447. // note: in vert/horz span setups (psuedo-multimon),
  448. // this will be 2048x768 or 1024x1536 or something like that.
  449. hPluginMonitor = m_lpD3D->GetAdapterMonitor(m_ordinal_adapter);
  450. /*if (hPluginMonitor)
  451. {
  452. MONITORINFO mi;
  453. mi.cbSize = sizeof(mi);
  454. if (GetMonitorInfo(hPluginMonitor, &mi))
  455. {
  456. memcpy(&m_monitor_rect, &mi.rcMonitor, sizeof(RECT));
  457. memcpy(&m_monitor_work_rect, &mi.rcWork, sizeof(RECT));
  458. }
  459. }*/
  460. if (bFirstInit)
  461. {
  462. for (int i=0; i<min(nAdapters, MAX_DXC_ADAPTERS); i++)
  463. {
  464. // if this is the first call to Init, get the display mode's original color format,
  465. // before we go changing it:
  466. D3DDISPLAYMODE d3ddm;
  467. if (FAILED(m_lpD3D->GetAdapterDisplayMode(i, &d3ddm)))
  468. {
  469. d3ddm.Format = D3DFMT_UNKNOWN;
  470. }
  471. m_orig_windowed_mode_format[i] = d3ddm.Format;
  472. }
  473. }
  474. // figure out pixel (color) format for back buffer: (m_current_mode.display_mode.Format)
  475. if (m_current_mode.screenmode!=FULLSCREEN && m_ordinal_adapter < MAX_DXC_ADAPTERS)
  476. m_current_mode.display_mode.Format = m_orig_windowed_mode_format[m_ordinal_adapter];
  477. // else
  478. // for fullscreen, use what they gave us
  479. if (m_current_mode.display_mode.Format == D3DFMT_UNKNOWN ||
  480. !TestFormat(m_ordinal_adapter, m_current_mode.display_mode.Format))
  481. {
  482. // if they try to run the plugin without ever running the config panel
  483. // first (& pressing OK), then the fullscreen pixelformat hasn't been
  484. // chosen... so we try all the possilibities until one works:
  485. if (TestFormat(m_ordinal_adapter,D3DFMT_A8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_A8R8G8B8;
  486. else if (TestFormat(m_ordinal_adapter,D3DFMT_X8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_X8R8G8B8;
  487. else if (TestFormat(m_ordinal_adapter,D3DFMT_R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_R8G8B8 ;
  488. else if (TestFormat(m_ordinal_adapter,D3DFMT_R5G6B5)) m_current_mode.display_mode.Format = D3DFMT_R5G6B5 ;
  489. else if (TestFormat(m_ordinal_adapter,D3DFMT_X1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_X1R5G5B5;
  490. else if (TestFormat(m_ordinal_adapter,D3DFMT_A1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_A1R5G5B5;
  491. else if (TestFormat(m_ordinal_adapter,D3DFMT_A4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_A4R4G4B4;
  492. else if (TestFormat(m_ordinal_adapter,D3DFMT_X4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_X4R4G4B4;
  493. }
  494. if (m_current_mode.display_mode.Format==D3DFMT_UNKNOWN)
  495. {
  496. wchar_t title[64];
  497. m_lastErr = DXC_ERR_FORMAT;
  498. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED),
  499. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  500. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  501. return FALSE;
  502. }
  503. if (m_current_mode.screenmode == FULLSCREEN)
  504. changed_fs_disp_mode = CheckAndCorrectFullscreenDispMode(m_ordinal_adapter, &m_current_mode.display_mode);
  505. // figure out pixel format of the z-buffer: (m_zFormat)
  506. m_zFormat = D3DFMT_UNKNOWN;
  507. /*
  508. if (TestDepth(m_ordinal_adapter,D3DFMT_D32 )) m_zFormat=D3DFMT_D32;
  509. else if (TestDepth(m_ordinal_adapter,D3DFMT_D24S8 )) m_zFormat=D3DFMT_D24S8;
  510. else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X4S4 )) m_zFormat=D3DFMT_D24X4S4;
  511. else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X8 )) m_zFormat=D3DFMT_D24X8;
  512. else if (TestDepth(m_ordinal_adapter,D3DFMT_D16 )) m_zFormat=D3DFMT_D16;
  513. else if (TestDepth(m_ordinal_adapter,D3DFMT_D15S1 )) m_zFormat=D3DFMT_D15S1;
  514. else if (TestDepth(m_ordinal_adapter,D3DFMT_D16_LOCKABLE)) m_zFormat=D3DFMT_D16_LOCKABLE;
  515. */
  516. // get device caps:
  517. memset(&m_caps, 0, sizeof(m_caps));
  518. if (FAILED(m_lpD3D->GetDeviceCaps(m_ordinal_adapter, D3DDEVTYPE_HAL, &m_caps)))
  519. {
  520. // that adapter was found in the system, but it might be disabled
  521. // (i.e. 'extend my Windows desktop onto this monitor') is unchecked)
  522. // so, try other adapters (try all sequentially).
  523. if (caps_tries < nAdapters)
  524. {
  525. // try again, this time using the default adapter:
  526. m_ordinal_adapter = caps_tries;
  527. caps_tries++;
  528. }
  529. else
  530. {
  531. wchar_t title[64];
  532. m_lastErr = DXC_ERR_CAPSFAIL;
  533. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DXC_ERR_CAPSFAIL),
  534. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  535. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  536. return FALSE;
  537. }
  538. }
  539. else
  540. {
  541. caps_ok = 1;
  542. }
  543. }
  544. while (!caps_ok);
  545. if (changed_fs_disp_mode)
  546. {
  547. wchar_t title[64];
  548. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_FS_DISPLAY_MODE_SELECTED_IS_INVALID),
  549. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64),
  550. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  551. }
  552. switch (m_current_mode.display_mode.Format)
  553. {
  554. case D3DFMT_R8G8B8 : m_bpp = 32; break;
  555. case D3DFMT_A8R8G8B8: m_bpp = 32; break;
  556. case D3DFMT_X8R8G8B8: m_bpp = 32; break;
  557. case D3DFMT_R5G6B5 : m_bpp = 16; break;
  558. case D3DFMT_X1R5G5B5: m_bpp = 16; break;
  559. case D3DFMT_A1R5G5B5: m_bpp = 16; break;
  560. case D3DFMT_A8R3G3B2: m_bpp = 16; break;
  561. case D3DFMT_A4R4G4B4: m_bpp = 16; break;
  562. case D3DFMT_X4R4G4B4: m_bpp = 16; break;
  563. case D3DFMT_R3G3B2 : m_bpp = 8; break; // misleading? implies a palette...
  564. }
  565. }
  566. // 5. set m_monitor_rect and m_monitor_work_rect.
  567. if (hPluginMonitor)
  568. {
  569. MONITORINFO mi;
  570. mi.cbSize = sizeof(mi);
  571. if (GetMonitorInfo(hPluginMonitor, &mi))
  572. {
  573. m_monitor_rect = mi.rcMonitor;
  574. m_monitor_rect_orig = mi.rcMonitor;
  575. m_monitor_work_rect = mi.rcWork;
  576. m_monitor_work_rect_orig = mi.rcWork;
  577. }
  578. }
  579. // 6. embedded window stuff [where the plugin window is integrated w/winamp]
  580. if (m_current_mode.m_skin)
  581. {
  582. // set up the window's position on screen
  583. // note that we'd prefer to set the CLIENT size we want, but we can't, so we'll just do
  584. // this here, and later, adjust the client rect size to what's left...
  585. int size = GetWindowedModeAutoSize(0); // note: requires 'm_monitor_rect' has been set!
  586. myWindowState.r.left = GetPrivateProfileIntW(L"settings",L"avs_wx",64,m_szIniFile);
  587. myWindowState.r.top = GetPrivateProfileIntW(L"settings",L"avs_wy",64,m_szIniFile);
  588. myWindowState.r.right = myWindowState.r.left + GetPrivateProfileIntW(L"settings",L"avs_ww",size+24,m_szIniFile);
  589. myWindowState.r.bottom = myWindowState.r.top + GetPrivateProfileIntW(L"settings",L"avs_wh",size+40,m_szIniFile);
  590. // only works on winamp 2.90+!
  591. int success = 0;
  592. if (GetWinampVersion(mod1.hwndParent) >= 0x2900)
  593. {
  594. SET_EMBED_GUID((&myWindowState), avs_guid);
  595. myWindowState.flags |= EMBED_FLAGS_NOTRANSPARENCY;
  596. HWND (*e)(embedWindowState *v);
  597. *(void**)&e = (void *)SendMessage(mod1.hwndParent,WM_WA_IPC,(LPARAM)0,IPC_GET_EMBEDIF);
  598. if (e)
  599. {
  600. m_current_mode.parent_window = e(&myWindowState);
  601. if (m_current_mode.parent_window)
  602. {
  603. SetWindowText(m_current_mode.parent_window, m_szWindowCaption);
  604. success = 1;
  605. }
  606. }
  607. }
  608. if (!success)
  609. m_current_mode.m_skin = 0;
  610. }
  611. // remember the client rect that was originally desired...
  612. RECT windowed_mode_desired_client_rect;
  613. windowed_mode_desired_client_rect.top = GetPrivateProfileIntW(L"settings",L"nMainWndTop",-1,m_szIniFile);
  614. windowed_mode_desired_client_rect.left = GetPrivateProfileIntW(L"settings",L"nMainWndLeft",-1,m_szIniFile);
  615. windowed_mode_desired_client_rect.right = GetPrivateProfileIntW(L"settings",L"nMainWndRight",-1,m_szIniFile);
  616. windowed_mode_desired_client_rect.bottom = GetPrivateProfileIntW(L"settings",L"nMainWndBottom",-1,m_szIniFile);
  617. // ...and in case windowed mode init fails severely,
  618. // set it up to try next time for a simple 256x256 window.
  619. WriteSafeWindowPos();
  620. // 7. create the window, if not already created
  621. if (!m_hwnd)
  622. {
  623. m_hwnd = CreateWindowEx(
  624. MY_EXT_WINDOW_STYLE, // extended style
  625. MAKEINTATOM(m_classAtom), // class
  626. m_szWindowCaption, // caption
  627. MY_WINDOW_STYLE, // style
  628. windowed_mode_desired_client_rect.left, // left
  629. windowed_mode_desired_client_rect.top, // top
  630. windowed_mode_desired_client_rect.right - windowed_mode_desired_client_rect.left, // temporary width
  631. windowed_mode_desired_client_rect.bottom - windowed_mode_desired_client_rect.top, // temporary height
  632. m_current_mode.parent_window, // parent window
  633. NULL, // menu
  634. m_hInstance, // instance
  635. (LPVOID)m_uWindowLong
  636. ); // parms
  637. if (!m_hwnd)
  638. {
  639. wchar_t title[64];
  640. m_lastErr = DXC_ERR_CREATEWIN;
  641. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_CREATEWINDOW_FAILED),
  642. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  643. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  644. return FALSE;
  645. }
  646. SendMessage(m_hwnd_winamp, WM_WA_IPC, (WPARAM)m_hwnd, IPC_SETVISWND);
  647. if (m_current_mode.m_skin)
  648. {
  649. if (GetWinampVersion(mod1.hwndParent) < 0x5051)
  650. ShowWindow(m_current_mode.parent_window,SW_SHOWNA); // showing the parent wnd will make it size the child, too
  651. else
  652. SendMessage(m_current_mode.parent_window, WM_USER+102, 0, 0); // benski> major hack alert. winamp's embedwnd will call ShowWindow in response. SendMessage moves us over to the main thread (we're currently sitting on the viz thread)
  653. }
  654. }
  655. // 8. minimize winamp before creating devices & such, so there aren't
  656. // any confusing window-focus issues
  657. MinimizeWinamp(hPluginMonitor);
  658. // 9. loop to try and create the window.
  659. // if in windowed mode and not enough vidmem, it will try again w/smaller window
  660. // (repeatedly, until window client size would be < 64)
  661. int iteration = 0;
  662. int device_ok = 0;
  663. do
  664. {
  665. // set the window position
  666. if (m_current_mode.screenmode==DESKTOP ||
  667. m_current_mode.screenmode==FAKE_FULLSCREEN)
  668. {
  669. int x = m_monitor_rect.right - m_monitor_rect.left;
  670. int y = m_monitor_rect.bottom - m_monitor_rect.top;
  671. if (x >= y*2)
  672. {
  673. // (pseudo-multimon modes like 2048x768)
  674. int mid = (m_monitor_rect.left + m_monitor_rect.right)/2;
  675. if (m_current_mode.m_dualhead_horz==1) // show on left side
  676. m_monitor_rect.right = mid;
  677. else if (m_current_mode.m_dualhead_horz==2) // show on right side
  678. m_monitor_rect.left = mid;
  679. }
  680. else if (y > x*4/3)
  681. {
  682. // (pseudo-multimon modes like 1024x1536)
  683. int mid = (m_monitor_rect.top + m_monitor_rect.bottom)/2;
  684. if (m_current_mode.m_dualhead_vert==1) // show on top half
  685. m_monitor_rect.bottom = mid;
  686. else if (m_current_mode.m_dualhead_vert==2) // show on bottom half
  687. m_monitor_rect.top = mid;
  688. }
  689. // recompute width & height (into x,y):
  690. x = m_monitor_rect.right - m_monitor_rect.left;
  691. y = m_monitor_rect.bottom - m_monitor_rect.top;
  692. m_client_width = x;
  693. m_client_height = y;
  694. m_window_width = x;
  695. m_window_height = y;
  696. if (m_current_mode.screenmode == DESKTOP)
  697. {
  698. // note: we initially hide the window, and then
  699. // only display it once the desktop is all nice & ready.
  700. // see CPluginShell::DrawAndDisplay().
  701. RECT r = m_monitor_rect;
  702. // if possible, shrink the desktop window so it doesn't cover the taskbar.
  703. HWND hTaskbar = FindWindow("Shell_TrayWnd", "");
  704. if (hTaskbar)
  705. {
  706. RECT taskbar;
  707. GetWindowRect(hTaskbar, &taskbar);
  708. int tbw = taskbar.right - taskbar.left;
  709. int tbh = taskbar.bottom-taskbar.top;
  710. if (taskbar.bottom == m_monitor_rect.bottom &&
  711. taskbar.left == m_monitor_rect.left &&
  712. taskbar.right == m_monitor_rect.right)
  713. {
  714. r.bottom -= tbh;
  715. }
  716. else if (taskbar.top == m_monitor_rect.top &&
  717. taskbar.left == m_monitor_rect.left &&
  718. taskbar.right == m_monitor_rect.right)
  719. {
  720. r.top += tbh;
  721. }
  722. else if (taskbar.left == m_monitor_rect.left &&
  723. taskbar.top == m_monitor_rect.top &&
  724. taskbar.bottom == m_monitor_rect.bottom)
  725. {
  726. r.left += tbw;
  727. }
  728. else if (taskbar.right == m_monitor_rect.right &&
  729. taskbar.top == m_monitor_rect.top &&
  730. taskbar.bottom == m_monitor_rect.bottom)
  731. {
  732. r.right -= tbw;
  733. }
  734. m_client_width = r.right - r.left;
  735. m_client_height = r.bottom - r.top;
  736. m_REAL_client_width = m_client_width;
  737. m_REAL_client_height = m_client_height;
  738. m_window_width = m_client_width;
  739. m_window_height = m_client_height;
  740. //...ok, but text is squished - some w/h is not right...
  741. }
  742. SetWindowPos(m_hwnd,HWND_BOTTOM,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_HIDEWINDOW);
  743. }
  744. else // FAKE_FULLSCREEN
  745. {
  746. if (memcmp(&m_all_monitors_rect, &m_monitor_rect, sizeof(RECT))==0)
  747. {
  748. // there's only one display, and it's entirely covered
  749. // by the plugin -> PUT THE PLUGIN ABOVE THE TASKBAR
  750. // -> normally, if the user clicked another window,
  751. // it would pop the taskbar to the top; but we don't
  752. // have to worry about that here, since we're taking
  753. // up the whole screen.
  754. // -> don't worry about making the text, etc. avoid
  755. // the taskbar in this case (see DrawAndDisplay())
  756. // -> DO worry about hiding the mouse cursor in this case
  757. // (see WM_SETCURSOR handler)
  758. m_fake_fs_covers_all = 1;
  759. //SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW);
  760. }
  761. else
  762. {
  763. // there is space to work outside of the plugin window.
  764. // -> here we pretty much have to let the taskbar stay on
  765. // top, because it really likes to be there; i.e.,
  766. // if you click any other window, it automatically
  767. // pops up again.
  768. // -> therefore, TRY TO KEEP THE WINDOW ON BOTTOM
  769. // (below the taskbar). (see PushWindowToBack)
  770. // -> don't worry about hiding the mouse cursor in this case
  771. // (see WM_SETCURSOR handler)
  772. // -> DO worry about making the text, etc. avoid
  773. // the taskbar in this case (see DrawAndDisplay())
  774. // (note that if taskbar is in the way, they can move it,
  775. // since there are other monitors available)
  776. m_fake_fs_covers_all = 0;
  777. //SetWindowPos(m_hwnd,HWND_TOP,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW);
  778. }
  779. SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW);
  780. }
  781. }
  782. else if (m_current_mode.screenmode == FULLSCREEN)
  783. {
  784. int x = m_current_mode.display_mode.Width ;
  785. int y = m_current_mode.display_mode.Height;
  786. int cx = m_monitor_rect.right - m_monitor_rect.left;
  787. int cy = m_monitor_rect.bottom - m_monitor_rect.top;
  788. // test #1
  789. if (x >= y*2 || y > x*4/3) // tackle problem of vert/horz spans
  790. {
  791. wchar_t title[64];
  792. int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS),
  793. WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64),
  794. MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST);
  795. if (ret==IDCANCEL)
  796. {
  797. m_lastErr = DXC_ERR_USER_CANCELED;
  798. return FALSE;
  799. }
  800. }
  801. // test #2
  802. if ((cx >= cy*2 && x < y*2) || (cy > cx*4/3 && y <= x*4/3))
  803. {
  804. wchar_t title[64];
  805. int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS_2),
  806. WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64),
  807. MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST);
  808. if (ret==IDCANCEL)
  809. {
  810. m_lastErr = DXC_ERR_USER_CANCELED;
  811. return FALSE;
  812. }
  813. }
  814. m_client_width = x;
  815. m_client_height = y;
  816. m_window_width = x;
  817. m_window_height = y;
  818. SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW);
  819. }
  820. else // WINDOWED
  821. {
  822. RECT margin;
  823. if (m_current_mode.m_skin)
  824. {
  825. RECT r1, r2;
  826. GetWindowRect(m_current_mode.parent_window, &r1);
  827. GetWindowRect(m_hwnd , &r2);
  828. margin.left = r2.left - r1.left;
  829. margin.right = r1.right - r2.right;
  830. margin.top = r2.top - r1.top;
  831. margin.bottom= r1.bottom - r2.bottom;
  832. }
  833. else
  834. {
  835. RECT r1;
  836. SetRect(&r1, 0, 0, 256, 256);
  837. AdjustWindowRect(&r1, MY_WINDOW_STYLE, 0);
  838. margin.left = 0 - r1.left;
  839. margin.right = r1.right - 256;
  840. margin.top = 0 - r1.top;
  841. margin.bottom= r1.bottom - 256;
  842. }
  843. int autosize = 1;
  844. RECT r = windowed_mode_desired_client_rect;
  845. if (iteration==0 && r.top != -1 && r.left != -1 && r.bottom != -1 && r.right != -1)
  846. {
  847. // use prev. window coordinates:
  848. m_REAL_client_width = r.right - r.left;
  849. m_REAL_client_height = r.bottom - r.top;
  850. GetSnappedClientSize();
  851. if (m_current_mode.m_skin) // check this here in case they got a non-aligned size by resizing when "integrated with winamp" was unchecked, then checked it & ran the plugin...
  852. {
  853. // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2):
  854. // the window frame's width must be divisible by 25, and height by 29.
  855. if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987)
  856. {
  857. m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right;
  858. m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom;
  859. GetSnappedClientSize();
  860. }
  861. }
  862. // transform screen-space CLIENT rect into screen-space WINDOW rect
  863. r.top = windowed_mode_desired_client_rect.top - margin.top;
  864. r.left = windowed_mode_desired_client_rect.left - margin.left;
  865. r.right = r.left + margin.left + m_REAL_client_width + margin.right;
  866. r.bottom = r.top + margin.top + m_REAL_client_height + margin.bottom;
  867. // make sure the window is entirely visible on the selected monitor;
  868. // otherwise, autosize/place it.
  869. // (note that this test is only appled 1) at startup, and 2) after a resize/max/restore.
  870. // this test is not applied when merely moving the window.)
  871. if (r.top >= m_monitor_work_rect.top &&
  872. r.left >= m_monitor_work_rect.left &&
  873. r.right <= m_monitor_work_rect.right &&
  874. r.bottom <= m_monitor_work_rect.bottom)
  875. {
  876. if (m_current_mode.m_skin)
  877. {
  878. m_window_width = m_REAL_client_width ; // m_window_width/height are for OUR borderless window, not the embedwnd parent frame.
  879. m_window_height = m_REAL_client_height;
  880. SetWindowPos(m_current_mode.parent_window,HWND_NOTOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, /*SWP_SHOWWINDOW|*//*SWP_ASYNCWINDOWPOS*/0);
  881. SetWindowPos(m_hwnd ,HWND_NOTOPMOST, windowed_mode_desired_client_rect.left,
  882. windowed_mode_desired_client_rect.top,
  883. m_REAL_client_width,
  884. m_REAL_client_height,
  885. SWP_SHOWWINDOW);
  886. }
  887. else
  888. {
  889. m_window_width = r.right - r.left;
  890. m_window_height = r.bottom - r.top;
  891. SetWindowPos(m_hwnd,HWND_NOTOPMOST,r.left,r.top,m_window_width,m_window_height,SWP_SHOWWINDOW);
  892. }
  893. autosize = 0;
  894. }
  895. }
  896. if (autosize)
  897. {
  898. int size = GetWindowedModeAutoSize(iteration); // note: requires 'm_monitor_rect' has been set!
  899. m_REAL_client_width = size;
  900. m_REAL_client_height = size;
  901. GetSnappedClientSize();
  902. if (m_current_mode.m_skin)
  903. {
  904. // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2):
  905. // the window frame's width must be divisible by 25, and height by 29.
  906. if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987)
  907. {
  908. m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right;
  909. m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom;
  910. GetSnappedClientSize();
  911. }
  912. m_window_width = m_client_width ; // m_window_width/height are for OUR [borderless] window, not the parent window (which is the embedwnd frame).
  913. m_window_height = m_client_height;
  914. SetWindowPos(m_current_mode.parent_window,HWND_NOTOPMOST, m_monitor_work_rect.left+32, m_monitor_work_rect.top+32, m_client_width + margin.left + margin.right, m_client_height + margin.top + margin.bottom, /*SWP_SHOWWINDOW|*//*SWP_ASYNCWINDOWPOS*/0);
  915. SetWindowPos(m_hwnd ,HWND_NOTOPMOST, m_monitor_work_rect.left+32 + margin.left, m_monitor_work_rect.top+32 + margin.top, m_client_width, m_client_height, SWP_SHOWWINDOW);
  916. }
  917. else
  918. {
  919. SetRect(&r, 0, 0, size, size);
  920. AdjustWindowRect(&r, MY_WINDOW_STYLE, 0);
  921. m_window_width = r.right - r.left;
  922. m_window_height = r.bottom - r.top;
  923. SetWindowPos(m_hwnd,HWND_NOTOPMOST, m_monitor_work_rect.left+32, m_monitor_work_rect.top+32, m_window_width, m_window_height, SWP_SHOWWINDOW);
  924. }
  925. }
  926. }
  927. m_frame_delay = 1; // set this to 2 if you use triple buffering!
  928. {
  929. m_current_mode.display_mode.Width = m_client_width;
  930. m_current_mode.display_mode.Height = m_client_height;
  931. // set up m_d3dpp (presentation parameters):
  932. ZeroMemory(&m_d3dpp,sizeof(m_d3dpp));
  933. m_d3dpp.Windowed = (m_current_mode.screenmode==FULLSCREEN) ? 0 : 1;
  934. m_d3dpp.BackBufferFormat = m_current_mode.display_mode.Format;
  935. m_d3dpp.BackBufferWidth = m_client_width;
  936. m_d3dpp.BackBufferHeight = m_client_height;
  937. m_d3dpp.BackBufferCount = m_current_mode.nbackbuf;
  938. if (m_current_mode.screenmode==FULLSCREEN)
  939. m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP;
  940. else // windowed or fake FS
  941. m_d3dpp.SwapEffect = (m_current_mode.allow_page_tearing) ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY;//D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP;
  942. // note: multisampling is only allowed if swapeffect is DISCARD!
  943. m_d3dpp.MultiSampleType = (m_d3dpp.SwapEffect==D3DSWAPEFFECT_DISCARD) ? m_current_mode.multisamp : D3DMULTISAMPLE_NONE;
  944. //m_d3dpp.hDeviceWindow = m_hwnd;
  945. if (m_current_mode.screenmode==FULLSCREEN)
  946. {
  947. m_d3dpp.FullScreen_RefreshRateInHz = m_current_mode.display_mode.RefreshRate;//D3DPRESENT_RATE_DEFAULT;
  948. m_d3dpp.PresentationInterval = m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE;
  949. }
  950. if (m_zFormat != D3DFMT_UNKNOWN)
  951. {
  952. m_d3dpp.EnableAutoDepthStencil=TRUE;
  953. m_d3dpp.AutoDepthStencilFormat=m_zFormat;
  954. }
  955. // finally, create the device:
  956. HRESULT hRes;
  957. if (FAILED(hRes = m_lpD3D->CreateDevice(
  958. m_ordinal_adapter,
  959. D3DDEVTYPE_HAL,
  960. m_hwnd,
  961. (m_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  962. &m_d3dpp,
  963. &m_lpDevice)))
  964. {
  965. int code = LOWORD(hRes);
  966. wchar_t str[1024];
  967. if (code==2156) //D3DERR_NOTAVAILABLE
  968. {
  969. m_lastErr = DXC_ERR_CREATEDEV_NOT_AVAIL;
  970. wchar_t str[2048];
  971. WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_CREATE_DIRECTX_DEVICE, str, 2048);
  972. if (m_current_mode.screenmode == FULLSCREEN)
  973. StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION));
  974. else
  975. StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION_2));
  976. MessageBoxW(m_hwnd,str,
  977. WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR),
  978. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  979. return FALSE;
  980. }
  981. else if (m_current_mode.screenmode==WINDOWED && m_client_width>64)
  982. {
  983. // DO NOTHING; try again w/smaller window
  984. }
  985. else if (m_current_mode.screenmode != WINDOWED || m_client_width <= 64)
  986. {
  987. // usually, code==2154 here, which is D3DERR_OUTOFVIDEOMEMORY
  988. m_lastErr = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY;
  989. StringCbPrintfW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED_X), LOWORD(hRes));
  990. // NOTE: *A 'SUGGESTION' SCREEN SHOULD APPEAR NEXT, PROVIDED BY THE CALLER*
  991. MessageBoxW(m_hwnd, str,
  992. WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR),
  993. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  994. return FALSE;
  995. }
  996. }
  997. else
  998. {
  999. device_ok = 1;
  1000. }
  1001. }
  1002. iteration++;
  1003. }
  1004. while (!device_ok);
  1005. // set initial viewport
  1006. SetViewport();
  1007. // for desktop mode, push window to back again:
  1008. if (m_current_mode.screenmode==DESKTOP)
  1009. SetWindowPos(m_hwnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
  1010. if (m_current_mode.m_skin)
  1011. {
  1012. if (GetWinampVersion(mod1.hwndParent) < 0x5051)
  1013. SetFocus(m_current_mode.parent_window);
  1014. else
  1015. PostMessage(m_current_mode.parent_window, WM_USER+103, 0, 0);
  1016. //SetActiveWindow(m_current_mode.parent_window);
  1017. //SetForegroundWindow(m_current_mode.parent_window);
  1018. }
  1019. /*if (m_current_mode.screenmode == WINDOWED)
  1020. SaveWindow();*/
  1021. // return success
  1022. m_ready = TRUE;
  1023. // benski> a little hack to get the window size correct. it seems to work
  1024. if (m_current_mode.screenmode==WINDOWED)
  1025. PostMessage(m_hwnd, WM_USER+555, 0, 0);
  1026. return TRUE;
  1027. }
  1028. BOOL DXContext::StartOrRestartDevice(DXCONTEXT_PARAMS *pParams)
  1029. {
  1030. // call this to [re]initialize the DirectX environment with new parameters.
  1031. // examples: startup; toggle windowed/fullscreen mode; change fullscreen resolution;
  1032. // and so on.
  1033. // be sure to clean up all your DirectX stuff first (textures, vertex buffers,
  1034. // D3DX allocations, etc.) and reallocate it afterwards!
  1035. // note: for windowed mode, 'pParams->disp_mode' (w/h/r/f) is ignored.
  1036. // destroy old window
  1037. if (myWindowState.me)
  1038. {
  1039. m_ignore_wm_destroy = 1;
  1040. if (m_current_mode.screenmode == WINDOWED)
  1041. SaveWindow();
  1042. DestroyWindow(myWindowState.me);
  1043. myWindowState.me = NULL;
  1044. m_ignore_wm_destroy = 0;
  1045. m_hwnd=0;
  1046. }
  1047. else if (m_hwnd)
  1048. {
  1049. SendMessage(m_hwnd_winamp, WM_WA_IPC, NULL, IPC_SETVISWND);
  1050. m_ignore_wm_destroy = 1;
  1051. DestroyWindow(m_hwnd);
  1052. m_ignore_wm_destroy = 0;
  1053. m_hwnd = NULL;
  1054. }
  1055. if (!m_ready)
  1056. {
  1057. // first-time init: create a fresh new device
  1058. return Internal_Init(pParams, TRUE);
  1059. }
  1060. else
  1061. {
  1062. // re-init: preserve the DX9 object (m_lpD3D),
  1063. // but destroy and re-create the DX9 device (m_lpDevice).
  1064. m_ready = FALSE;
  1065. SafeRelease(m_lpDevice);
  1066. // but leave the D3D object!
  1067. RestoreWinamp();
  1068. return Internal_Init(pParams, FALSE);
  1069. }
  1070. }
  1071. BOOL DXContext::OnUserResizeWindow(RECT *new_window_rect, RECT *new_client_rect)
  1072. {
  1073. // call this function on WM_EXITSIZEMOVE when running windowed.
  1074. // don't bother calling this when fullscreen.
  1075. // be sure to clean up all your DirectX stuff first (textures, vertex buffers,
  1076. // D3DX allocations, etc.) and reallocate it afterwards!
  1077. if (!m_ready || (m_current_mode.screenmode != WINDOWED))
  1078. return FALSE;
  1079. if ((m_client_width == new_client_rect->right - new_client_rect->left) &&
  1080. (m_client_height == new_client_rect->bottom - new_client_rect->top) &&
  1081. (m_window_width == new_window_rect->right - new_window_rect->left) &&
  1082. (m_window_height == new_window_rect->bottom - new_window_rect->top))
  1083. {
  1084. return TRUE;
  1085. }
  1086. m_ready = FALSE;
  1087. m_window_width = new_window_rect->right - new_window_rect->left;
  1088. m_window_height = new_window_rect->bottom - new_window_rect->top;
  1089. m_REAL_client_width = new_client_rect->right - new_client_rect->left;
  1090. m_REAL_client_height = new_client_rect->bottom - new_client_rect->top;
  1091. GetSnappedClientSize(); //sets m_client_width/height, but with snapping, if in windowed mode.
  1092. m_d3dpp.BackBufferWidth = m_client_width;
  1093. m_d3dpp.BackBufferHeight = m_client_height;
  1094. if (m_lpDevice->Reset(&m_d3dpp) != D3D_OK)
  1095. {
  1096. WriteSafeWindowPos();
  1097. wchar_t title[64];
  1098. MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_WINDOW_RESIZE_FAILED),
  1099. WASABI_API_LNGSTRINGW_BUF(IDS_OUT_OF_VIDEO_MEMORY, title, 64),
  1100. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  1101. m_lastErr = DXC_ERR_RESIZEFAILED;
  1102. return FALSE;
  1103. }
  1104. SetViewport();
  1105. m_ready = TRUE;
  1106. return TRUE;
  1107. }
  1108. void DXContext::SetViewport()
  1109. {
  1110. D3DVIEWPORT9 v;
  1111. v.X = 0;
  1112. v.Y = 0;
  1113. v.Width = m_client_width;
  1114. v.Height = m_client_height;
  1115. v.MinZ = 0.0f;
  1116. v.MaxZ = 1.0f;
  1117. m_lpDevice->SetViewport(&v);
  1118. }
  1119. void DXContext::MinimizeWinamp(HMONITOR hPluginMonitor)
  1120. {
  1121. // minimize Winamp window
  1122. HMONITOR hWinampMon = MonitorFromWindow(m_hwnd_winamp, MONITOR_DEFAULTTONEAREST);
  1123. HMONITOR hPluginMon = hPluginMonitor;//MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);//m_lpD3D->GetAdapterMonitor(ordinal_adapter);
  1124. if ((m_current_mode.screenmode == FULLSCREEN || m_current_mode.screenmode == FAKE_FULLSCREEN) &&
  1125. (m_minimize_winamp) &&
  1126. (hWinampMon && hPluginMon && hPluginMon==hWinampMon) &&
  1127. (!m_winamp_minimized)
  1128. )
  1129. {
  1130. // nitpicky check: if we're in fake fullscreen mode
  1131. // and are only going to display on half the screen,
  1132. // don't minimize Winamp.
  1133. if (m_current_mode.screenmode == FAKE_FULLSCREEN)
  1134. {
  1135. int x = m_monitor_rect.right - m_monitor_rect.left;
  1136. int y = m_monitor_rect.bottom - m_monitor_rect.top;
  1137. if ((x >= y*2 && m_current_mode.m_dualhead_horz != 0) ||
  1138. (y > x*4/3 && m_current_mode.m_dualhead_vert != 0))
  1139. {
  1140. return;
  1141. }
  1142. }
  1143. ShowWindow(m_hwnd_winamp, SW_MINIMIZE);
  1144. // also restore the focus to the plugin window, since this will steal it:
  1145. SetFocus(m_hwnd);
  1146. SetActiveWindow(m_hwnd);
  1147. SetForegroundWindow(m_hwnd);
  1148. m_winamp_minimized = 1;
  1149. }
  1150. }
  1151. void DXContext::RestoreWinamp()
  1152. {
  1153. if (m_winamp_minimized)
  1154. {
  1155. ShowWindow(m_hwnd_winamp, SW_RESTORE);
  1156. m_winamp_minimized = 0;
  1157. }
  1158. }
  1159. void DXContext::UpdateMonitorWorkRect()
  1160. {
  1161. // get active monitor's bounding rectangle (to assist w/window positioning)
  1162. // note: in vert/horz span setups (psuedo-multimon),
  1163. // this will be 2048x768 or 1024x1536 or something like that.
  1164. // calling this each frame allows you to detect when the taskbar
  1165. // moves around on the screen (from edge to edge), and rearrange
  1166. // the visual elements accordingly, so nothing is obscured.
  1167. HMONITOR hMon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);//m_lpD3D->GetAdapterMonitor(m_ordinal_adapter);
  1168. if (hMon)
  1169. {
  1170. MONITORINFO mi;
  1171. mi.cbSize = sizeof(mi);
  1172. if (GetMonitorInfo(hMon, &mi))
  1173. {
  1174. m_monitor_work_rect = mi.rcWork;
  1175. m_monitor_work_rect_orig = mi.rcWork;
  1176. // if the monitor rect we're using is the same as the
  1177. // whole area of the monitor, there's no need to update it...
  1178. //if (memcmp(&mi.rcMonitor, &m_monitor_rect, sizeof(RECT))==0)
  1179. // return;
  1180. // otherwise, we're doing a half-screen special case
  1181. // and are running in some pseudo-multimon res like
  1182. // 2048x768 or 1024x1536, but only using half of it
  1183. // (i.e. fake fullscreen or desktop mode)
  1184. // therefore... we need to update the work-area rectangle
  1185. // to reflect which half of the screen it's on.
  1186. if (m_monitor_rect.left == mi.rcMonitor.left)
  1187. m_monitor_work_rect.left = mi.rcWork.left;
  1188. else
  1189. m_monitor_work_rect.left = m_monitor_rect.left + (mi.rcWork.left - mi.rcMonitor.left);
  1190. if (m_monitor_rect.top == mi.rcMonitor.top)
  1191. m_monitor_work_rect.top = mi.rcWork.top;
  1192. else
  1193. m_monitor_work_rect.top = m_monitor_rect.top + (mi.rcWork.top - mi.rcMonitor.top);
  1194. if (m_monitor_rect.right == mi.rcMonitor.right)
  1195. m_monitor_work_rect.right = mi.rcWork.right;
  1196. else
  1197. m_monitor_work_rect.right = m_monitor_rect.right;
  1198. if (m_monitor_rect.bottom == mi.rcMonitor.bottom)
  1199. m_monitor_work_rect.bottom = mi.rcWork.bottom;
  1200. else
  1201. m_monitor_work_rect.bottom = m_monitor_rect.bottom;
  1202. }
  1203. }
  1204. }
  1205. void DXContext::SaveWindow()
  1206. {
  1207. if ( m_hwnd == NULL )
  1208. return;
  1209. if (m_current_mode.screenmode == WINDOWED)
  1210. {
  1211. RECT c;
  1212. GetClientRect(m_hwnd, &c);
  1213. // convert client rect from client coords to screen coords:
  1214. // (window rect is already in screen coords...)
  1215. POINT p;
  1216. p.x = c.left;
  1217. p.y = c.top;
  1218. if (ClientToScreen(m_hwnd, &p))
  1219. {
  1220. c.left += p.x;
  1221. c.right += p.x;
  1222. c.top += p.y;
  1223. c.bottom += p.y;
  1224. }
  1225. // save bounds for window CLIENT area, but in screen coords
  1226. WritePrivateProfileIntW(c.top, L"nMainWndTop", m_szIniFile, L"settings");
  1227. WritePrivateProfileIntW(c.left, L"nMainWndLeft", m_szIniFile, L"settings");
  1228. WritePrivateProfileIntW(c.right, L"nMainWndRight", m_szIniFile, L"settings");
  1229. WritePrivateProfileIntW(c.bottom,L"nMainWndBottom", m_szIniFile, L"settings");
  1230. // also save bounds for embedwnd
  1231. if (m_current_mode.m_skin && myWindowState.me)
  1232. {
  1233. WritePrivateProfileIntW(myWindowState.r.left,L"avs_wx",m_szIniFile,L"settings");
  1234. WritePrivateProfileIntW(myWindowState.r.top ,L"avs_wy",m_szIniFile,L"settings");
  1235. WritePrivateProfileIntW(myWindowState.r.right-myWindowState.r.left,L"avs_ww",m_szIniFile,L"settings");
  1236. WritePrivateProfileIntW(myWindowState.r.bottom-myWindowState.r.top,L"avs_wh",m_szIniFile,L"settings");
  1237. }
  1238. else if (!m_current_mode.m_skin && m_hwnd)
  1239. {
  1240. RECT r;
  1241. GetWindowRect(m_hwnd, &r);
  1242. WritePrivateProfileIntW(r.left,L"avs_wx",m_szIniFile,L"settings");
  1243. WritePrivateProfileIntW(r.top ,L"avs_wy",m_szIniFile,L"settings");
  1244. WritePrivateProfileIntW(r.right-r.left,L"avs_ww",m_szIniFile,L"settings");
  1245. WritePrivateProfileIntW(r.bottom-r.top,L"avs_wh",m_szIniFile,L"settings");
  1246. }
  1247. }
  1248. }