// initialization. Registers our window class, creates our window, etc. Again, this one works for // both modules, but you could make init1() and init2()... // returns 0 on success, 1 on failure. int init(struct winampVisModule *this_mod) { DWORD version = GetWinampVersion(mod1.hwndParent); if (!warand) { warand = (int (*)(void))SendMessage(this_mod->hwndParent, WM_WA_IPC, 0, IPC_GET_RANDFUNC); if ((size_t)warand <= 1) { warand = fallback_rand_fn; } } if (!WaitUntilPluginFinished(this_mod->hwndParent)) { return 1; } if (GetWinampVersion(mod1.hwndParent) < 0x4000) { // query winamp for its playback state LRESULT ret = SendMessage(this_mod->hwndParent, WM_USER, 0, 104); // ret=1: playing, ret=3: paused, other: stopped if (ret != 1) { wchar_t title[64]; MessageBoxW(this_mod->hwndParent, WASABI_API_LNGSTRINGW(IDS_THIS_PLUGIN_NEEDS_MUSIC_TO_RUN), WASABI_API_LNGSTRINGW_BUF(IDS_NO_MUSIC_PLAYING, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL ); return 1; // failure } } g_bFullyExited = false; if (!g_plugin.PluginPreInitialize(this_mod->hwndParent, this_mod->hDllInstance)) { g_plugin.PluginQuit(); g_bFullyExited = true; return 1; } if (!g_plugin.PluginInitialize()) { g_plugin.PluginQuit(); g_bFullyExited = true; return 1; } return 0; // success }
BOOL DXContext::OnUserResizeWindow(RECT *new_window_rect, RECT *new_client_rect) { // call this function on WM_EXITSIZEMOVE when running windowed. // don't bother calling this when fullscreen. // be sure to clean up all your DirectX stuff first (textures, vertex buffers, // D3DX allocations, etc.) and reallocate it afterwards! if (!m_ready || (m_current_mode.screenmode != WINDOWED)) return FALSE; if ((m_client_width == new_client_rect->right - new_client_rect->left) && (m_client_height == new_client_rect->bottom - new_client_rect->top) && (m_window_width == new_window_rect->right - new_window_rect->left) && (m_window_height == new_window_rect->bottom - new_window_rect->top)) { return TRUE; } m_ready = FALSE; m_window_width = new_window_rect->right - new_window_rect->left; m_window_height = new_window_rect->bottom - new_window_rect->top; m_REAL_client_width = new_client_rect->right - new_client_rect->left; m_REAL_client_height = new_client_rect->bottom - new_client_rect->top; GetSnappedClientSize(); //sets m_client_width/height, but with snapping, if in windowed mode. m_d3dpp.BackBufferWidth = m_client_width; m_d3dpp.BackBufferHeight = m_client_height; if (m_lpDevice->Reset(&m_d3dpp) != D3D_OK) { WriteSafeWindowPos(); wchar_t title[64]; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_WINDOW_RESIZE_FAILED), WASABI_API_LNGSTRINGW_BUF(IDS_OUT_OF_VIDEO_MEMORY, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); m_lastErr = DXC_ERR_RESIZEFAILED; return FALSE; } SetViewport(); m_ready = TRUE; return TRUE; }
bool WaitUntilPluginFinished(HWND hWndWinamp) { int slept = 0; while (!g_bFullyExited && slept < 1000) { Sleep(50); slept += 50; } if (!g_bFullyExited) { wchar_t title[64]; MessageBoxW(hWndWinamp, WASABI_API_LNGSTRINGW(IDS_ERROR_THE_PLUGIN_IS_ALREADY_RUNNING), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return false; } return true; }
inline std::wstring lines::MetaWord(const std::wstring &word) { if (word == __T("%curtime%")) { int res = SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME); if (res == -1) return __T("~"); return SecToTime(res/1000); } if (word == __T("%timeleft%")) { int cur = SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME); int tot = SendMessage(m_hwnd,WM_WA_IPC,1,IPC_GETOUTPUTTIME); if (cur == -1 || tot == -1) return __T("~"); return SecToTime(tot - cur / 1000); } if (word == __T("%totaltime%")) { int res = SendMessage(m_hwnd,WM_WA_IPC,1,IPC_GETOUTPUTTIME); if (res == -1) return __T(""); return SecToTime(res); } if (word == __T("%kbps%")) { int inf=SendMessage(m_hwnd,WM_WA_IPC,1,IPC_GETINFO); if (inf == NULL) return std::wstring(__T("")); std::wstringstream w; w << inf; return w.str(); } if (word == __T("%khz%")) { int inf=SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETINFO); if (inf == NULL) return std::wstring(__T("")); std::wstringstream w; w << inf; return w.str(); } if (word == __T("%c%")) return __T("‡center‡"); if (word == __T("%l%")) return __T("‡largefont‡"); if (word == __T("%f%")) return __T("‡forceleft‡"); if (word == __T("%s%")) return __T("‡shadow‡"); if (word == __T("%b%")) return __T("‡darkbox‡"); if (word == __T("%d%")) return __T("‡dontscroll‡"); if (word == __T("%volume%")) { std::wstringstream w; w << (m_settings.play_volume * 100) /255; return w.str(); } if (word == __T("%shuffle%")) { static wchar_t tmp[8]; return WASABI_API_LNGSTRINGW_BUF((SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GET_SHUFFLE)?IDS_ON:IDS_OFF),tmp,8); } if (word == __T("%repeat%")) { static wchar_t tmp[8]; return WASABI_API_LNGSTRINGW_BUF((SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GET_REPEAT)?IDS_ON:IDS_OFF),tmp,8); } if (word == __T("%curpl%")) { std::wstringstream w; w << (SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETLISTLENGTH)? m_settings.play_playlistpos+1 : 0); return w.str(); } if (word == __T("%totalpl%")) { std::wstringstream w; w << SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETLISTLENGTH); return w.str(); } if (word == __T("%rating1%") || word == __T("%rating2%")) { std::wstringstream w; int x = SendMessage(m_hwnd,WM_WA_IPC,0,IPC_GETRATING); if (word == __T("%rating1%")) w << x; else { for (int i=0; i < x; i++) w << L"\u2605"; for (int i=0; i < 5-x; i++) w << L"\u2606"/*" \u25CF"*/; } return w.str(); } return m_metadata.getMetadata(word.substr(1, word.length()-2)); }
DXContext::DXContext(HWND hWndWinamp,HINSTANCE hInstance,LPCWSTR szClassName,LPCSTR szWindowCaption,WNDPROC pProc,LONG_PTR uWindowLong, int minimize_winamp, wchar_t* szIniFile) { m_classAtom = 0; m_szWindowCaption[0] = 0; m_hwnd = NULL; m_lpD3D = NULL; m_lpDevice = NULL; m_hmod_d3d9 = NULL; m_hmod_d3dx9 = NULL; m_zFormat = D3DFMT_UNKNOWN; for (int i=0; i<MAX_DXC_ADAPTERS; i++) m_orig_windowed_mode_format[i] = D3DFMT_UNKNOWN; m_ordinal_adapter = D3DADAPTER_DEFAULT; m_ignore_wm_destroy = 0; m_hwnd_winamp = hWndWinamp; m_minimize_winamp = minimize_winamp; m_winamp_minimized = 0; m_truly_exiting = 0; m_bpp = 0; m_frame_delay = 0; StringCbCopyW(m_szIniFile, sizeof(m_szIniFile), szIniFile); memset(&myWindowState,0,sizeof(myWindowState)); m_szDriver[0] = 0; m_szDesc[0] = 0; WNDCLASSW wc = {0}; // clear the error register m_lastErr = S_OK; // clear the active flag m_ready=FALSE; // Set up and register window class wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode... wc.lpfnWndProc = (WNDPROC) pProc; wc.cbWndExtra = sizeof(DWORD); wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PLUGIN_ICON));//NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; m_classAtom = RegisterClassW(&wc); if (!m_classAtom) { wchar_t title[64]; int y = GetLastError(); m_lastErr = DXC_ERR_REGWIN; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_REGISTER_WINDOW_CLASS), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); Internal_CleanUp(); return; } StringCbCopy(m_szWindowCaption, sizeof(m_szWindowCaption), szWindowCaption); m_hInstance = hInstance; m_uWindowLong = uWindowLong; }
BOOL DXContext::Internal_Init(DXCONTEXT_PARAMS *pParams, BOOL bFirstInit) { memcpy(&m_current_mode, pParams, sizeof(DXCONTEXT_PARAMS)); memset(&myWindowState,0,sizeof(myWindowState)); // various checks if (m_current_mode.screenmode != WINDOWED) m_current_mode.m_skin = 0; // 1. destroy old window if (m_hwnd) { m_ignore_wm_destroy = 1; DestroyWindow(m_hwnd); m_ignore_wm_destroy = 0; m_hwnd = NULL; } // 2. CHECK TO MAKE SURE DIRECTX/DDRAW IS INSTALLED if (bFirstInit) { // Test for DirectX 9 + start it // note: if you don't call LoadLibrary here, and you're on a system // where DX9 is missing, Direct3DCreate8() might crash; so call it. int d3d9_already_loaded = (GetModuleHandle("d3d9.dll") != NULL) ? 1 : 0; if (!d3d9_already_loaded) m_hmod_d3d9 = LoadLibrary("d3d9.dll"); if ((!d3d9_already_loaded && !m_hmod_d3d9) || !(m_lpD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) { MissingDirectX(NULL); m_lastErr = DXC_ERR_CREATE3D; return FALSE; } if (!m_hmod_d3dx9) m_hmod_d3dx9 = FindD3DX9(m_hwnd_winamp); if ((!m_hmod_d3dx9)) { MissingDirectX(NULL); m_lastErr = DXC_ERR_CREATE3D; return FALSE; } } // 3. get the smallest single rectangle that encloses ALL the monitors on the desktop: SetRect(&m_all_monitors_rect, 0, 0, 0, 0); EnumDisplayMonitors(NULL, NULL, MyMonitorEnumProc, (LPARAM)&m_all_monitors_rect); // 4. some DirectX- / DDraw-specific stuff. Also determine hPluginMonitor. HMONITOR hPluginMonitor = NULL; { D3DADAPTER_IDENTIFIER9 temp; // find the ordinal # of the adapter whose GUID matches what the user picked from the config panel, // and whose DeviceName matches as well. // if no match found, use D3DADAPTER_DEFAULT. m_ordinal_adapter = D3DADAPTER_DEFAULT; int nAdapters = m_lpD3D->GetAdapterCount(); { for (int i=0; i<nAdapters; i++) { if ((m_lpD3D->GetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) && (memcmp(&temp.DeviceIdentifier, &m_current_mode.adapter_guid, sizeof(GUID))==0) && !strcmp(temp.DeviceName, m_current_mode.adapter_devicename) ) { m_ordinal_adapter = i; break; } } } if (m_lpD3D->GetAdapterIdentifier(m_ordinal_adapter, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) { StringCbCopy(m_szDriver, sizeof(m_szDriver), temp.Driver); StringCbCopy(m_szDesc, sizeof(m_szDesc), temp.Description); } int caps_ok = 0; int caps_tries = 0; int changed_fs_disp_mode; // try to get the device caps for the adapter selected from the config panel. // if GetDeviceCaps() fails, it's probably because the adapter has been // removed from the system (or disabled), so we try again with other adapter(s). do { changed_fs_disp_mode = 0; SetRect(&m_monitor_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); // get bounding rect of the monitor attached to the adapter (to assist w/window positioning) // note: in vert/horz span setups (psuedo-multimon), // this will be 2048x768 or 1024x1536 or something like that. hPluginMonitor = m_lpD3D->GetAdapterMonitor(m_ordinal_adapter); /*if (hPluginMonitor) { MONITORINFO mi; mi.cbSize = sizeof(mi); if (GetMonitorInfo(hPluginMonitor, &mi)) { memcpy(&m_monitor_rect, &mi.rcMonitor, sizeof(RECT)); memcpy(&m_monitor_work_rect, &mi.rcWork, sizeof(RECT)); } }*/ if (bFirstInit) { for (int i=0; i<min(nAdapters, MAX_DXC_ADAPTERS); i++) { // if this is the first call to Init, get the display mode's original color format, // before we go changing it: D3DDISPLAYMODE d3ddm; if (FAILED(m_lpD3D->GetAdapterDisplayMode(i, &d3ddm))) { d3ddm.Format = D3DFMT_UNKNOWN; } m_orig_windowed_mode_format[i] = d3ddm.Format; } } // figure out pixel (color) format for back buffer: (m_current_mode.display_mode.Format) if (m_current_mode.screenmode!=FULLSCREEN && m_ordinal_adapter < MAX_DXC_ADAPTERS) m_current_mode.display_mode.Format = m_orig_windowed_mode_format[m_ordinal_adapter]; // else // for fullscreen, use what they gave us if (m_current_mode.display_mode.Format == D3DFMT_UNKNOWN || !TestFormat(m_ordinal_adapter, m_current_mode.display_mode.Format)) { // if they try to run the plugin without ever running the config panel // first (& pressing OK), then the fullscreen pixelformat hasn't been // chosen... so we try all the possilibities until one works: if (TestFormat(m_ordinal_adapter,D3DFMT_A8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_A8R8G8B8; else if (TestFormat(m_ordinal_adapter,D3DFMT_X8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_X8R8G8B8; else if (TestFormat(m_ordinal_adapter,D3DFMT_R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_R8G8B8 ; else if (TestFormat(m_ordinal_adapter,D3DFMT_R5G6B5)) m_current_mode.display_mode.Format = D3DFMT_R5G6B5 ; else if (TestFormat(m_ordinal_adapter,D3DFMT_X1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_X1R5G5B5; else if (TestFormat(m_ordinal_adapter,D3DFMT_A1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_A1R5G5B5; else if (TestFormat(m_ordinal_adapter,D3DFMT_A4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_A4R4G4B4; else if (TestFormat(m_ordinal_adapter,D3DFMT_X4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_X4R4G4B4; } if (m_current_mode.display_mode.Format==D3DFMT_UNKNOWN) { wchar_t title[64]; m_lastErr = DXC_ERR_FORMAT; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return FALSE; } if (m_current_mode.screenmode == FULLSCREEN) changed_fs_disp_mode = CheckAndCorrectFullscreenDispMode(m_ordinal_adapter, &m_current_mode.display_mode); // figure out pixel format of the z-buffer: (m_zFormat) m_zFormat = D3DFMT_UNKNOWN; /* if (TestDepth(m_ordinal_adapter,D3DFMT_D32 )) m_zFormat=D3DFMT_D32; else if (TestDepth(m_ordinal_adapter,D3DFMT_D24S8 )) m_zFormat=D3DFMT_D24S8; else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X4S4 )) m_zFormat=D3DFMT_D24X4S4; else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X8 )) m_zFormat=D3DFMT_D24X8; else if (TestDepth(m_ordinal_adapter,D3DFMT_D16 )) m_zFormat=D3DFMT_D16; else if (TestDepth(m_ordinal_adapter,D3DFMT_D15S1 )) m_zFormat=D3DFMT_D15S1; else if (TestDepth(m_ordinal_adapter,D3DFMT_D16_LOCKABLE)) m_zFormat=D3DFMT_D16_LOCKABLE; */ // get device caps: memset(&m_caps, 0, sizeof(m_caps)); if (FAILED(m_lpD3D->GetDeviceCaps(m_ordinal_adapter, D3DDEVTYPE_HAL, &m_caps))) { // that adapter was found in the system, but it might be disabled // (i.e. 'extend my Windows desktop onto this monitor') is unchecked) // so, try other adapters (try all sequentially). if (caps_tries < nAdapters) { // try again, this time using the default adapter: m_ordinal_adapter = caps_tries; caps_tries++; } else { wchar_t title[64]; m_lastErr = DXC_ERR_CAPSFAIL; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DXC_ERR_CAPSFAIL), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return FALSE; } } else { caps_ok = 1; } } while (!caps_ok); if (changed_fs_disp_mode) { wchar_t title[64]; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_FS_DISPLAY_MODE_SELECTED_IS_INVALID), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); } switch (m_current_mode.display_mode.Format) { case D3DFMT_R8G8B8 : m_bpp = 32; break; case D3DFMT_A8R8G8B8: m_bpp = 32; break; case D3DFMT_X8R8G8B8: m_bpp = 32; break; case D3DFMT_R5G6B5 : m_bpp = 16; break; case D3DFMT_X1R5G5B5: m_bpp = 16; break; case D3DFMT_A1R5G5B5: m_bpp = 16; break; case D3DFMT_A8R3G3B2: m_bpp = 16; break; case D3DFMT_A4R4G4B4: m_bpp = 16; break; case D3DFMT_X4R4G4B4: m_bpp = 16; break; case D3DFMT_R3G3B2 : m_bpp = 8; break; // misleading? implies a palette... } } // 5. set m_monitor_rect and m_monitor_work_rect. if (hPluginMonitor) { MONITORINFO mi; mi.cbSize = sizeof(mi); if (GetMonitorInfo(hPluginMonitor, &mi)) { m_monitor_rect = mi.rcMonitor; m_monitor_rect_orig = mi.rcMonitor; m_monitor_work_rect = mi.rcWork; m_monitor_work_rect_orig = mi.rcWork; } } // 6. embedded window stuff [where the plugin window is integrated w/winamp] if (m_current_mode.m_skin) { // set up the window's position on screen // note that we'd prefer to set the CLIENT size we want, but we can't, so we'll just do // this here, and later, adjust the client rect size to what's left... int size = GetWindowedModeAutoSize(0); // note: requires 'm_monitor_rect' has been set! myWindowState.r.left = GetPrivateProfileIntW(L"settings",L"avs_wx",64,m_szIniFile); myWindowState.r.top = GetPrivateProfileIntW(L"settings",L"avs_wy",64,m_szIniFile); myWindowState.r.right = myWindowState.r.left + GetPrivateProfileIntW(L"settings",L"avs_ww",size+24,m_szIniFile); myWindowState.r.bottom = myWindowState.r.top + GetPrivateProfileIntW(L"settings",L"avs_wh",size+40,m_szIniFile); // only works on winamp 2.90+! int success = 0; if (GetWinampVersion(mod1.hwndParent) >= 0x2900) { SET_EMBED_GUID((&myWindowState), avs_guid); myWindowState.flags |= EMBED_FLAGS_NOTRANSPARENCY; HWND (*e)(embedWindowState *v); *(void**)&e = (void *)SendMessage(mod1.hwndParent,WM_WA_IPC,(LPARAM)0,IPC_GET_EMBEDIF); if (e) { m_current_mode.parent_window = e(&myWindowState); if (m_current_mode.parent_window) { SetWindowText(m_current_mode.parent_window, m_szWindowCaption); success = 1; } } } if (!success) m_current_mode.m_skin = 0; } // remember the client rect that was originally desired... RECT windowed_mode_desired_client_rect; windowed_mode_desired_client_rect.top = GetPrivateProfileIntW(L"settings",L"nMainWndTop",-1,m_szIniFile); windowed_mode_desired_client_rect.left = GetPrivateProfileIntW(L"settings",L"nMainWndLeft",-1,m_szIniFile); windowed_mode_desired_client_rect.right = GetPrivateProfileIntW(L"settings",L"nMainWndRight",-1,m_szIniFile); windowed_mode_desired_client_rect.bottom = GetPrivateProfileIntW(L"settings",L"nMainWndBottom",-1,m_szIniFile); // ...and in case windowed mode init fails severely, // set it up to try next time for a simple 256x256 window. WriteSafeWindowPos(); // 7. create the window, if not already created if (!m_hwnd) { m_hwnd = CreateWindowEx( MY_EXT_WINDOW_STYLE, // extended style MAKEINTATOM(m_classAtom), // class m_szWindowCaption, // caption MY_WINDOW_STYLE, // style 0, // left 0, // top 256, // temporary width 256, // temporary height m_current_mode.parent_window, // parent window NULL, // menu m_hInstance, // instance (LPVOID)m_uWindowLong ); // parms if (!m_hwnd) { wchar_t title[64]; m_lastErr = DXC_ERR_CREATEWIN; MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_CREATEWINDOW_FAILED), WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return FALSE; } SendMessage(m_hwnd_winamp, WM_WA_IPC, (WPARAM)m_hwnd, IPC_SETVISWND); if (m_current_mode.m_skin) { if (GetWinampVersion(mod1.hwndParent) < 0x5051) ShowWindow(m_current_mode.parent_window,SW_SHOWNA); // showing the parent wnd will make it size the child, too else 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) } } // 8. minimize winamp before creating devices & such, so there aren't // any confusing window-focus issues MinimizeWinamp(hPluginMonitor); // 9. loop to try and create the window. // if in windowed mode and not enough vidmem, it will try again w/smaller window // (repeatedly, until window client size would be < 64) int iteration = 0; int device_ok = 0; do { // set the window position if (m_current_mode.screenmode==DESKTOP || m_current_mode.screenmode==FAKE_FULLSCREEN) { int x = m_monitor_rect.right - m_monitor_rect.left; int y = m_monitor_rect.bottom - m_monitor_rect.top; if (x >= y*2) { // (pseudo-multimon modes like 2048x768) int mid = (m_monitor_rect.left + m_monitor_rect.right)/2; if (m_current_mode.m_dualhead_horz==1) // show on left side m_monitor_rect.right = mid; else if (m_current_mode.m_dualhead_horz==2) // show on right side m_monitor_rect.left = mid; } else if (y > x*4/3) { // (pseudo-multimon modes like 1024x1536) int mid = (m_monitor_rect.top + m_monitor_rect.bottom)/2; if (m_current_mode.m_dualhead_vert==1) // show on top half m_monitor_rect.bottom = mid; else if (m_current_mode.m_dualhead_vert==2) // show on bottom half m_monitor_rect.top = mid; } // recompute width & height (into x,y): x = m_monitor_rect.right - m_monitor_rect.left; y = m_monitor_rect.bottom - m_monitor_rect.top; m_client_width = x; m_client_height = y; m_window_width = x; m_window_height = y; if (m_current_mode.screenmode == DESKTOP) { // note: we initially hide the window, and then // only display it once the desktop is all nice & ready. // see CPluginShell::DrawAndDisplay(). RECT r = m_monitor_rect; // if possible, shrink the desktop window so it doesn't cover the taskbar. HWND hTaskbar = FindWindow("Shell_TrayWnd", ""); if (hTaskbar) { RECT taskbar; GetWindowRect(hTaskbar, &taskbar); int tbw = taskbar.right - taskbar.left; int tbh = taskbar.bottom-taskbar.top; if (taskbar.bottom == m_monitor_rect.bottom && taskbar.left == m_monitor_rect.left && taskbar.right == m_monitor_rect.right) { r.bottom -= tbh; } else if (taskbar.top == m_monitor_rect.top && taskbar.left == m_monitor_rect.left && taskbar.right == m_monitor_rect.right) { r.top += tbh; } else if (taskbar.left == m_monitor_rect.left && taskbar.top == m_monitor_rect.top && taskbar.bottom == m_monitor_rect.bottom) { r.left += tbw; } else if (taskbar.right == m_monitor_rect.right && taskbar.top == m_monitor_rect.top && taskbar.bottom == m_monitor_rect.bottom) { r.right -= tbw; } m_client_width = r.right - r.left; m_client_height = r.bottom - r.top; m_REAL_client_width = m_client_width; m_REAL_client_height = m_client_height; m_window_width = m_client_width; m_window_height = m_client_height; //...ok, but text is squished - some w/h is not right... } SetWindowPos(m_hwnd,HWND_BOTTOM,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_HIDEWINDOW); } else // FAKE_FULLSCREEN { if (memcmp(&m_all_monitors_rect, &m_monitor_rect, sizeof(RECT))==0) { // there's only one display, and it's entirely covered // by the plugin -> PUT THE PLUGIN ABOVE THE TASKBAR // -> normally, if the user clicked another window, // it would pop the taskbar to the top; but we don't // have to worry about that here, since we're taking // up the whole screen. // -> don't worry about making the text, etc. avoid // the taskbar in this case (see DrawAndDisplay()) // -> DO worry about hiding the mouse cursor in this case // (see WM_SETCURSOR handler) m_fake_fs_covers_all = 1; //SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); } else { // there is space to work outside of the plugin window. // -> here we pretty much have to let the taskbar stay on // top, because it really likes to be there; i.e., // if you click any other window, it automatically // pops up again. // -> therefore, TRY TO KEEP THE WINDOW ON BOTTOM // (below the taskbar). (see PushWindowToBack) // -> don't worry about hiding the mouse cursor in this case // (see WM_SETCURSOR handler) // -> DO worry about making the text, etc. avoid // the taskbar in this case (see DrawAndDisplay()) // (note that if taskbar is in the way, they can move it, // since there are other monitors available) m_fake_fs_covers_all = 0; //SetWindowPos(m_hwnd,HWND_TOP,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); } SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); } } else if (m_current_mode.screenmode == FULLSCREEN) { int x = m_current_mode.display_mode.Width ; int y = m_current_mode.display_mode.Height; int cx = m_monitor_rect.right - m_monitor_rect.left; int cy = m_monitor_rect.bottom - m_monitor_rect.top; // test #1 if (x >= y*2 || y > x*4/3) // tackle problem of vert/horz spans { wchar_t title[64]; int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS), WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64), MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST); if (ret==IDCANCEL) { m_lastErr = DXC_ERR_USER_CANCELED; return FALSE; } } // test #2 if ((cx >= cy*2 && x < y*2) || (cy > cx*4/3 && y <= x*4/3)) { wchar_t title[64]; int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS_2), WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64), MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST); if (ret==IDCANCEL) { m_lastErr = DXC_ERR_USER_CANCELED; return FALSE; } } m_client_width = x; m_client_height = y; m_window_width = x; m_window_height = y; SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); } else // WINDOWED { RECT margin; if (m_current_mode.m_skin) { RECT r1, r2; GetWindowRect(m_current_mode.parent_window, &r1); GetWindowRect(m_hwnd , &r2); margin.left = r2.left - r1.left; margin.right = r1.right - r2.right; margin.top = r2.top - r1.top; margin.bottom= r1.bottom - r2.bottom; } else { RECT r1; SetRect(&r1, 0, 0, 256, 256); AdjustWindowRect(&r1, MY_WINDOW_STYLE, 0); margin.left = 0 - r1.left; margin.right = r1.right - 256; margin.top = 0 - r1.top; margin.bottom= r1.bottom - 256; } int autosize = 1; RECT r = windowed_mode_desired_client_rect; if (iteration==0 && r.top != -1 && r.left != -1 && r.bottom != -1 && r.right != -1) { // use prev. window coordinates: m_REAL_client_width = r.right - r.left; m_REAL_client_height = r.bottom - r.top; GetSnappedClientSize(); 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... { // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2): // the window frame's width must be divisible by 25, and height by 29. if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987) { m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right; m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom; GetSnappedClientSize(); } } // transform screen-space CLIENT rect into screen-space WINDOW rect r.top = windowed_mode_desired_client_rect.top - margin.top; r.left = windowed_mode_desired_client_rect.left - margin.left; r.right = r.left + margin.left + m_REAL_client_width + margin.right; r.bottom = r.top + margin.top + m_REAL_client_height + margin.bottom; // make sure the window is entirely visible on the selected monitor; // otherwise, autosize/place it. // (note that this test is only appled 1) at startup, and 2) after a resize/max/restore. // this test is not applied when merely moving the window.) if (r.top >= m_monitor_work_rect.top && r.left >= m_monitor_work_rect.left && r.right <= m_monitor_work_rect.right && r.bottom <= m_monitor_work_rect.bottom) { if (m_current_mode.m_skin) { m_window_width = m_REAL_client_width ; // m_window_width/height are for OUR borderless window, not the embedwnd parent frame. m_window_height = m_REAL_client_height; 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); SetWindowPos(m_hwnd ,HWND_NOTOPMOST, windowed_mode_desired_client_rect.left, windowed_mode_desired_client_rect.top, m_REAL_client_width, m_REAL_client_height, SWP_SHOWWINDOW); } else { m_window_width = r.right - r.left; m_window_height = r.bottom - r.top; SetWindowPos(m_hwnd,HWND_NOTOPMOST,r.left,r.top,m_window_width,m_window_height,SWP_SHOWWINDOW); } autosize = 0; } } if (autosize) { int size = GetWindowedModeAutoSize(iteration); // note: requires 'm_monitor_rect' has been set! m_REAL_client_width = size; m_REAL_client_height = size; GetSnappedClientSize(); if (m_current_mode.m_skin) { // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2): // the window frame's width must be divisible by 25, and height by 29. if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987) { m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right; m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom; GetSnappedClientSize(); } m_window_width = m_client_width ; // m_window_width/height are for OUR [borderless] window, not the parent window (which is the embedwnd frame). m_window_height = m_client_height; 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); 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); } else { SetRect(&r, 0, 0, size, size); AdjustWindowRect(&r, MY_WINDOW_STYLE, 0); m_window_width = r.right - r.left; m_window_height = r.bottom - r.top; 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); } } } m_frame_delay = 1; // set this to 2 if you use triple buffering! { m_current_mode.display_mode.Width = m_client_width; m_current_mode.display_mode.Height = m_client_height; // set up m_d3dpp (presentation parameters): ZeroMemory(&m_d3dpp,sizeof(m_d3dpp)); m_d3dpp.Windowed = (m_current_mode.screenmode==FULLSCREEN) ? 0 : 1; m_d3dpp.BackBufferFormat = m_current_mode.display_mode.Format; m_d3dpp.BackBufferWidth = m_client_width; m_d3dpp.BackBufferHeight = m_client_height; m_d3dpp.BackBufferCount = m_current_mode.nbackbuf; if (m_current_mode.screenmode==FULLSCREEN) m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP; else // windowed or fake FS m_d3dpp.SwapEffect = (m_current_mode.allow_page_tearing) ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY;//D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP; // note: multisampling is only allowed if swapeffect is DISCARD! m_d3dpp.MultiSampleType = (m_d3dpp.SwapEffect==D3DSWAPEFFECT_DISCARD) ? m_current_mode.multisamp : D3DMULTISAMPLE_NONE; //m_d3dpp.hDeviceWindow = m_hwnd; if (m_current_mode.screenmode==FULLSCREEN) { m_d3dpp.FullScreen_RefreshRateInHz = m_current_mode.display_mode.RefreshRate;//D3DPRESENT_RATE_DEFAULT; m_d3dpp.PresentationInterval = m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE; } if (m_zFormat != D3DFMT_UNKNOWN) { m_d3dpp.EnableAutoDepthStencil=TRUE; m_d3dpp.AutoDepthStencilFormat=m_zFormat; } // finally, create the device: HRESULT hRes; if (FAILED(hRes = m_lpD3D->CreateDevice( m_ordinal_adapter, D3DDEVTYPE_HAL, m_hwnd, (m_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_d3dpp, &m_lpDevice))) { int code = LOWORD(hRes); wchar_t str[1024]; if (code==2156) //D3DERR_NOTAVAILABLE { m_lastErr = DXC_ERR_CREATEDEV_NOT_AVAIL; wchar_t str[2048]; WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_CREATE_DIRECTX_DEVICE, str, 2048); if (m_current_mode.screenmode == FULLSCREEN) StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION)); else StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION_2)); MessageBoxW(m_hwnd,str, WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return FALSE; } else if (m_current_mode.screenmode==WINDOWED && m_client_width>64) { // DO NOTHING; try again w/smaller window } else if (m_current_mode.screenmode != WINDOWED || m_client_width <= 64) { // usually, code==2154 here, which is D3DERR_OUTOFVIDEOMEMORY m_lastErr = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY; StringCbPrintfW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED_X), LOWORD(hRes)); // NOTE: *A 'SUGGESTION' SCREEN SHOULD APPEAR NEXT, PROVIDED BY THE CALLER* MessageBoxW(m_hwnd, str, WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return FALSE; } } else { device_ok = 1; } } iteration++; } while (!device_ok); // set initial viewport SetViewport(); // for desktop mode, push window to back again: if (m_current_mode.screenmode==DESKTOP) SetWindowPos(m_hwnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); if (m_current_mode.m_skin) { if (GetWinampVersion(mod1.hwndParent) < 0x5051) SetFocus(m_current_mode.parent_window); else PostMessage(m_current_mode.parent_window, WM_USER+103, 0, 0); //SetActiveWindow(m_current_mode.parent_window); //SetForegroundWindow(m_current_mode.parent_window); } /*if (m_current_mode.screenmode == WINDOWED) SaveWindow();*/ // return success m_ready = TRUE; // benski> a little hack to get the window size correct. it seems to work if (m_current_mode.screenmode==WINDOWED) PostMessage(m_hwnd, WM_USER+555, 0, 0); return TRUE; }