#include "pluginshell.h" #include "resource.h" #include "utility.h" //---------------------------------------------------------------------- #define VMS_DESKTOP_DLLNAME "vms_desktop.dll" #pragma comment(lib,"vms_desktop.lib") #pragma comment(linker,"/delayload:vms_desktop.dll") //---------------------------------------------------------------------- typedef struct _SIMPLEVERTEX { float x, y; // screen position float z; // Z-buffer depth DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims) } SIMPLEVERTEX, *LPSIMPLEVERTEX; typedef struct _HELPVERTEX { float x, y; // screen position float z; // Z-buffer depth DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims) float tu, tv; // texture coordinates for texture #0 } HELPVERTEX, *LPHELPVERTEX; #define SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE) #define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) //---------------------------------------------------------------------- // resides in vms_desktop.dll/lib: int setHook(HWND hlv,HWND w,int version); void removeHook(); //---------------------------------------------------------------------- int CPluginShell::InitDesktopMode() { if (m_screenmode != DESKTOP) return false; if (!m_desktop_show_icons) return true; // note: we have to explicitly make sure the DLL is present, // since we're delay-loading it; otherwise, calling setHook, etc. will crash it. char szVmsDesktopDll[MAX_PATH]; sprintf(szVmsDesktopDll, "%s%s", GetPluginsDirPath(), VMS_DESKTOP_DLLNAME); if (!GetModuleHandle(szVmsDesktopDll)) { if (!LoadLibrary(szVmsDesktopDll)) { char buf[2048]; sprintf(buf, "Could not find the following file:\r\r %s\r\r...which is required for this plugin to work properly in Desktop Mode.\rPlease reinstall the plugin.", szVmsDesktopDll); MessageBox(GetPluginWindow(),buf,"ERROR - FILE MISSING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); //return false; m_desktop_icons_disabled = 1; } else { m_vms_desktop_loaded = 1; } } InitializeCriticalSection(&m_desktop_cs); m_desktop_icon_state = 0; m_desktop_icon_count = 0; m_desktop_icon_update_frame = 0; m_desktop_icon_size = GetDesktopIconSize(); // GDI font for desktop mode: LOGFONT lf; ZeroMemory(&lf, sizeof(lf)); if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0)) { if (!(m_font_desktop = CreateFontIndirect(&lf))) { MessageBox(GetPluginWindow(), "Error creating GDI desktop font", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return false; } } else { if (!(m_font_desktop = CreateFont(14, 0, 0, 0, 0, 0, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, "Monotype Sans Serif"))) { MessageBox(GetPluginWindow(), "Error creating GDI desktop font", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return false; } } // Create D3DX font for drawing icon labels on desktop: if (D3DXCreateFont(m_lpDX->m_lpDevice, m_font_desktop, &m_d3dx_desktop_font) != D3D_OK) { MessageBox(GetPluginWindow(), "Error creating desktop font", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return false; } // create first texture for holding icon bitmaps: // (do it now, to ensure that at least 1 gets created, before // the plugin does all of its DX8 allocations.) if (!CreateDesktopIconTexture(&m_desktop_icons_texture[0])) { MessageBox(GetPluginWindow(), "Error creating texture for icon bitmaps", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); } if (!m_desktop_icons_disabled) { int ret = setHook(m_hWndDesktopListView, GetPluginWindow(), 1); if (ret == 1) m_desktop_hook_set = 1; else if (ret == -1) MessageBox(GetPluginWindow(), "It appears that you have an outdated copy of the file 'vms_desktop.dll'\rin your Winamp PLUGINS directory. Please reinstall the plugin\rto bring this file up to date.", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); else MessageBox(GetPluginWindow(), "Error creating hook procedure;\rdesktop icons will not be available.", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); } return true; } //---------------------------------------------------------------------- void CPluginShell::CleanUpDesktopMode() { if (m_screenmode != DESKTOP) return; if (!m_desktop_show_icons) return; if (m_desktop_hook_set) { m_desktop_hook_set = 0; removeHook(); } for (int i=0; iRelease(); *ppTex = NULL; } // create new int ntries = (m_lpDX->m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5) ? 3 : 1; for (int ntry=0; ntrym_d3dpp.BackBufferFormat; switch(m_lpDX->m_d3dpp.BackBufferFormat) { case D3DFMT_R8G8B8: case D3DFMT_X8R8G8B8: fmt = D3DFMT_A8R8G8B8; break; case D3DFMT_R5G6B5: // <- PROBLEM: NO ALPHA CHANNEL FOR ICONS if (ntry==0) switch(m_desktop_555_fix) { case 0: fmt = D3DFMT_R5G6B5; break; case 1: fmt = D3DFMT_A1R5G5B5; break; case 2: fmt = D3DFMT_A8R8G8B8; break; } else if (ntry==1) switch(m_desktop_555_fix) { case 0: fmt = D3DFMT_A1R5G5B5; break; case 1: fmt = D3DFMT_A8R8G8B8; break; case 2: fmt = D3DFMT_A1R5G5B5; break; } else switch(m_desktop_555_fix) { case 0: fmt = D3DFMT_A8R8G8B8; break; case 1: fmt = D3DFMT_R5G6B5; break; case 2: fmt = D3DFMT_R5G6B5; break; } break; case D3DFMT_X1R5G5B5: fmt = D3DFMT_A1R5G5B5; break; } if (m_lpDX->m_lpDevice->CreateTexture(ICON_TEXTURE_SIZE, ICON_TEXTURE_SIZE, 1, 0, fmt, D3DPOOL_MANAGED, ppTex) != D3D_OK) *ppTex = NULL; else break; } return (*ppTex) ? 1 : 0; } //---------------------------------------------------------------------- void CPluginShell::DeselectDesktop() { std::list::iterator p; for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) p->selected = 0; } //---------------------------------------------------------------------- void CPluginShell::UpdateDesktopBitmaps() { // update the D3DX textures that hold all the icons: int idx = 0; int texnum = 0; int show_msgs = 1; // if no icon texture could be created at startup, // don't bother trying anything here, and don't give them // any extra error messages. if (!m_desktop_icons_texture[0]) return; std::list::iterator p; for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) p->icon_bitmap_idx = -1; do { idx = StuffIconBitmaps(idx, texnum++, &show_msgs); } while (idx > 0 && texnum < MAX_ICON_TEXTURES); if (idx > 0) MessageBox(GetPluginWindow(), "Error updating icon bitmaps; the number of unique\ricon bitmaps on your desktop exceeded the maximum.\r\rAs a result, not all icons will look correct.", "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); } //---------------------------------------------------------------------- int CPluginShell::StuffIconBitmaps(int iStartIconIdx, int iTexNum, int *show_msgs) { // returns: // 0 if done (or error), or // N if the texture is full & we need to start another one, // where N is the new iStartIconIdx to use. if (m_screenmode != DESKTOP) return 0; if (!m_desktop_icons_texture[iTexNum]) { int ret = CreateDesktopIconTexture(&m_desktop_icons_texture[iTexNum]); if (!ret) { MessageBox(GetPluginWindow(), "Error updating icon bitmaps: there were a lot of unique icon bitmaps,\rbut the plugin couldn't allocate enough extra texture(s) to hold them all,\rprobably because video memory is low.\r\rAs a result, not all icons will look correct.", "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return 0; } } D3DSURFACE_DESC sd; if (m_desktop_icons_texture[iTexNum]->GetLevelDesc(0, &sd) != D3D_OK) { MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rcouldn't get level description", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return 0; } D3DLOCKED_RECT lr; if (m_desktop_icons_texture[iTexNum]->LockRect(0, &lr, NULL, 0) != D3D_OK) { MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rLockRect failed", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return 0; } if (lr.pBits == NULL) { MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rlr.pBits == NULL", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); m_desktop_icons_texture[iTexNum]->UnlockRect(0); return 0; } unsigned __int16* p16 = (unsigned __int16*)lr.pBits; unsigned __int32* p32 = (unsigned __int32*)lr.pBits; int WIDTH = sd.Width; int i; int start; int bpp; int rshift[3]; // 1. bits to first shift right r,g,b int mask[3]; // 2. mask for r, g, b int lshift[3]; // 3. bits to then shift left r,g,b switch(sd.Format) { case D3DFMT_R8G8B8: case D3DFMT_A8R8G8B8: case D3DFMT_X8R8G8B8: start = 0xFF000000; bpp = 32; rshift[0] = 0; rshift[1] = 0; rshift[2] = 0; mask[0] = 0xFF; mask[1] = 0xFF; mask[2] = 0xFF; lshift[0] = 16; lshift[1] = 8; lshift[2] = 0; break; case D3DFMT_R5G6B5: start = 0x0000; bpp = 16; rshift[0] = 3; rshift[1] = 2; rshift[2] = 3; mask[0] = 0x1F; mask[1] = 0x3F; mask[2] = 0x1F; lshift[0] = 11; lshift[1] = 5; lshift[2] = 0; break; case D3DFMT_X1R5G5B5: case D3DFMT_A1R5G5B5: start = 0x8000; bpp = 16; rshift[0] = 3; rshift[1] = 3; rshift[2] = 3; mask[0] = 0x1F; mask[1] = 0x1F; mask[2] = 0x1F; lshift[0] = 10; lshift[1] = 5; lshift[2] = 0; break; case D3DFMT_A4R4G4B4: start = 0xF000; bpp = 16; rshift[0] = 4; rshift[1] = 4; rshift[2] = 4; mask[0] = 0x0F; mask[1] = 0x0F; mask[2] = 0x0F; lshift[0] = 8; lshift[1] = 4; lshift[2] = 0; break; default: MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\runknown pixel format", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); m_desktop_icons_texture[iTexNum]->UnlockRect(0); return 0; } HDC hdc = GetDC(NULL); if (!hdc) { MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rcouldn't get HDC", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); m_desktop_icons_texture[iTexNum]->UnlockRect(0); return 0; } #define MAX_ICON_SIZE 128 unsigned char data[MAX_ICON_SIZE*MAX_ICON_SIZE*4]; int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size; int nDown = ICON_TEXTURE_SIZE/m_desktop_icon_size; // for each icon, add its bitmap to the texture (if not already there), // and set 'icon_bitmap_idx'. std::list::iterator p = m_icon_list.begin(); for (i=0; i < iStartIconIdx; i++) p++; int bitmap_idx = 0; int list_idx = iStartIconIdx; for ( ; p != m_icon_list.end() && bitmap_idx < nAcross*nDown; p++) { // note: 'p' points to the correct icon to start with, // but 'idx' starts at zero! // get the icon: SHFILEINFO sfi; int flags = SHGFI_ICON|SHGFI_PIDL|SHGFI_SHELLICONSIZE | ((m_desktop_icon_size > 32) ? SHGFI_LARGEICON : 0); if (SHGetFileInfo((LPCTSTR)p->pidl, 0, &sfi, sizeof(sfi), flags)) { ICONINFO ii; if (GetIconInfo(sfi.hIcon, &ii)) { int x0 = (bitmap_idx%nAcross)*m_desktop_icon_size; int y0 = (bitmap_idx/nAcross)*m_desktop_icon_size; int checksum[3] = { 0, 0, 0 }; BITMAPINFO bmi; // pass 1: get the colors bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = m_desktop_icon_size; bmi.bmiHeader.biHeight = m_desktop_icon_size; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; if (GetDIBits( hdc, // handle to DC ii.hbmColor, // handle to bitmap 0, // first scan line to set m_desktop_icon_size,// number of scan lines to copy data, // array for bitmap bits &bmi, // bitmap data buffer DIB_RGB_COLORS // RGB or palette index )) { int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size); int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size); for (int y=0; y> rshift[0]) & mask[0]) << lshift[0]) | (((g >> rshift[1]) & mask[1]) << lshift[1]) | (((b >> rshift[2]) & mask[2]) << lshift[2]); else p32[out_offset] = start | (((r >> rshift[0]) & mask[0]) << lshift[0]) | (((g >> rshift[1]) & mask[1]) << lshift[1]) | (((b >> rshift[2]) & mask[2]) << lshift[2]); } } else { if (*show_msgs) MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rcall #1 to GetDIBits failed.", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); *show_msgs = 0; } // pass 2: get the alpha mask bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = m_desktop_icon_size; bmi.bmiHeader.biHeight = m_desktop_icon_size; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; if (GetDIBits( hdc, // handle to DC ii.hbmMask, // handle to bitmap 0, // first scan line to set m_desktop_icon_size,// number of scan lines to copy data, // array for bitmap bits &bmi, // bitmap data buffer DIB_RGB_COLORS // RGB or palette index )) { int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size); int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size); for (int y=0; y::iterator q; for (q = m_icon_list.begin(); q != m_icon_list.end() && q != p; q++) { if (checksum[0] == q->checksum[0] && checksum[1] == q->checksum[1] && checksum[2] == q->checksum[2]) { p->icon_bitmap_idx = q->icon_bitmap_idx; done = 1; break; } } // otherwise, keep new icon if (!done) { p->icon_bitmap_idx = nAcross*nDown*iTexNum + bitmap_idx; p->checksum[0] = checksum[0]; p->checksum[1] = checksum[1]; p->checksum[2] = checksum[2]; bitmap_idx++; } DeleteObject(ii.hbmMask); DeleteObject(ii.hbmColor); } else { if (*show_msgs) MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rGetIconInfo failed.", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); *show_msgs = 0; } DestroyIcon(sfi.hIcon); } else { if (*show_msgs) MessageBox(GetPluginWindow(), "Error updating icon bitmaps:\rSHGetFileInfo failed.", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); *show_msgs = 0; } list_idx++; } ReleaseDC(NULL, hdc); m_desktop_icons_texture[iTexNum]->UnlockRect(0); if (bitmap_idx >= nAcross*nDown) return list_idx; else return 0; // all done } //---------------------------------------------------------------------- void CPluginShell::RenderDesktop() { if (m_screenmode != DESKTOP) return; if (!m_desktop_show_icons) return; if (m_desktop_icons_disabled) return; std::list::iterator p; EnterCriticalSection(&m_desktop_cs); int iconcount = static_cast(SendMessage(m_hWndDesktopListView, LVM_GETITEMCOUNT, 0, 0)); if (iconcount == 0) { LeaveCriticalSection(&m_desktop_cs); return; } // if the icons list is empty, // or if we check it for consistency and an update is recommended (GetDesktopIcons(1)==2), // update the icons list & the bitmaps: /*if (m_icon_list.size()==0 || GetDesktopIcons(1)==2) { m_icon_list.clear(); GetDesktopIcons(0); UpdateDesktopBitmaps(); }*/ // check for invalid entries. (if there is an error in getItemData(), // it will return the icon_t structure anyway, but with empty strings.) int invalid_entries = 0; if (m_desktop_icon_state >= 2) { for (p = m_icon_list.begin(); p != m_icon_list.end() && !invalid_entries; p++) { if (p->name[0]==0) invalid_entries = 1; //if (p->pidl[0].mkid.cb==0 && p->pidl[0].mkid.abID[0]==0) if (p->pidl[0]==0 && p->pidl[1]==0) invalid_entries = 1; } } if ( (m_desktop_icon_state == 0) || (m_desktop_icon_state >= 2 && m_desktop_icon_count != iconcount) || (m_desktop_icon_state >= 2 && invalid_entries) ) { // begin total refresh m_desktop_icon_state = 1; m_desktop_icon_count = iconcount; m_desktop_icon_update_frame = GetFrame(); m_icon_list.clear(); SendMessage(GetPluginWindow(), WM_USER, 0x80000000 | iconcount, 0);//getItemData(i); // try to get the desktop window's listview to respond to // the queries as quickly as possible: { LeaveCriticalSection(&m_desktop_cs); DWORD procid = NULL; DWORD threadid = GetWindowThreadProcessId(m_hWndDesktopListView, &procid); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, FALSE, procid); DWORD x = GetPriorityClass(hProcess); if (x) SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); for (int i=0; i<5; i++) { Sleep(10); MSG msg; while(PeekMessage(&msg,GetPluginWindow(),0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } if (x) SetPriorityClass(hProcess, x); CloseHandle(hProcess); EnterCriticalSection(&m_desktop_cs); } } else if (m_desktop_icon_state == 1 && m_icon_list.size() < m_desktop_icon_count) { // waiting for the 'total refresh' to complete // ... if (GetFrame() > m_desktop_icon_update_frame+64) { m_desktop_icon_state = 0; } } else if (m_desktop_icon_state == 1 && m_icon_list.size() == m_desktop_icon_count) { // done with total refresh m_desktop_icon_state = 2; m_desktop_icon_update_frame = GetFrame(); UpdateDesktopBitmaps(); } else if (m_desktop_icon_state == 2) { if (GetFrame() > m_desktop_icon_update_frame+4) { m_desktop_icon_state = 3; // will mean we're waiting on data to return. m_desktop_icon_update_frame = GetFrame(); int start = 0; int len = iconcount; SendMessage(GetPluginWindow(), WM_USER, start | (len << 16), 0);//getItemData(i); } } else if (m_desktop_icon_state == 3) { if (GetFrame() > m_desktop_icon_update_frame+64) { // timeout; give up waiting for update message to come back, // and just request another. m_desktop_icon_state = 2; m_desktop_icon_update_frame = GetFrame(); } } // get horz. spacing between icons (...determines width of labels) ICONMETRICS icm; icm.cbSize = sizeof(icm); if (!SystemParametersInfo(SPI_GETICONMETRICS, sizeof(icm), &icm, 0)) icm.iHorzSpacing = 68; /*int font_height = 0; { RECT r; m_d3dx_desktop_font->DrawText("M", -1, &r, DT_CALCRECT, 0xFFFFFFFF); font_height = r.bottom - r.top; }*/ // display the desktop. m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);//D3DTOP_SELECTARG1 ); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size; int nDown = ICON_TEXTURE_SIZE/m_desktop_icon_size; // The icon's x and y coordinates (as returned by the // getIconData/WM_COPYDATA system) are (0,0) at the // upper-left corner of the rectangle that encompasses // all the monitors together (m_lpDX->m_all_monitors_rect). // Note that in 'm_all_monitors_rect', (0,0) represents // the upper-left corner of the PRIMARY DISPLAY - not necessarily // the one we're showing the fake desktop on. // What we have to do here is determine icon_dx and icon_dy, // which are the transformation from the coordinate space used // by the desktop itself (as returned in WM_COPYDATA) // and the coordinates used by Windows itself (where 0,0 is // the upper-left corner of the PRIMARY DISPLAY, and coordinates // in other displays can be negative if they are above/left of it). int upperleft_x = min(m_lpDX->m_all_monitors_rect.left, m_lpDX->m_monitor_rect.left); int upperleft_y = min(m_lpDX->m_all_monitors_rect.top , m_lpDX->m_monitor_rect.top ); int icon_dx = m_lpDX->m_monitor_rect.left - upperleft_x; // subtract this amount int icon_dy = m_lpDX->m_monitor_rect.top - upperleft_y; // subtract this amount if (m_desktop_manual_icon_scoot) { icon_dx += m_lpDX->m_monitor_rect.left - m_lpDX->m_monitor_work_rect.left; icon_dy += m_lpDX->m_monitor_rect.top - m_lpDX->m_monitor_work_rect.top ; } // pass 0: draw normal text & icons // pass 1: redraw icon currently being dragged, transparently int nPasses = m_desktop_dragging ? 2 : 1; for (int pass=0; passm_lpDevice->SetVertexShader( SIMPLE_VERTEX_FORMAT ); m_lpDX->m_lpDevice->SetTexture(0, NULL); SIMPLEVERTEX verts[4]; // pass2==0: draw text labels // pass2==1: draw text overtop // (separated for speed, so ID3DXFont can get the HDC just once for all the DrawText calls) for (int pass2=0; pass2<2; pass2++) { if (pass2==1) m_d3dx_desktop_font->Begin(); for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) { if (pass==0 || (p->selected && m_desktop_dragging)) { int max_width = icm.iHorzSpacing-5+m_desktop_icon_size-32;//icm.iHorzSpacing-5; int dx = 0; int dy = 4; if (pass>0) { dx += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x; dy += m_desktop_drag_curpos.y - m_desktop_drag_startpos.y; } SetRect(&p->label_rect, p->x + m_desktop_icon_size/2 - icon_dx - max_width/2 + dx, p->y + m_desktop_icon_size - icon_dy + dy, p->x + m_desktop_icon_size/2 - icon_dx + max_width/2 + dx, p->y + m_desktop_icon_size - icon_dy + 0 + dy // will be extended by DT_CALCRECT step! ); // calculate rect for the text label DWORD style = DT_CENTER|DT_WORDBREAK|DT_END_ELLIPSIS|DT_WORD_ELLIPSIS; m_d3dx_desktop_font->DrawText(p->name, -1, &p->label_rect, style|DT_CALCRECT, 0xFFFFFFFF); // D3DX doesn't handle text so well if it goes off // the left edge of the screen, so don't show text labels // that are mostly off (on the left side): if ((p->label_rect.left + p->label_rect.right)/2 > 0) { // also, if label would go off left edge of screen, // push it to the right: if (p->label_rect.left < 0 && p->label_rect.right > 0) { p->label_rect.right -= p->label_rect.left; p->label_rect.left = 0; } //if (p->selected) // ...draw blue background around text label if (pass2==0) { if (m_desktop_textlabel_boxes || p->selected) { #define EXTEND_LEFT 3 #define EXTEND_RIGHT 2 #define EXTEND_TOP 0 #define EXTEND_BOTTOM 2 for (int i=0; i<4; i++) { verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width/2 + p->label_rect.left - EXTEND_LEFT) : (float)(-m_lpDX->m_client_width/2 + p->label_rect.right + EXTEND_RIGHT); // was -2/+3 verts[i].y = (i/2==0) ? (float)(m_lpDX->m_client_height/2 - p->label_rect.top + EXTEND_TOP ) : (float)(m_lpDX->m_client_height/2 - p->label_rect.bottom - EXTEND_BOTTOM); // was +1/-1 verts[i].z = 0; verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : m_desktop_bk_color;//0xFF000000; if (pass>0) verts[i].Diffuse &= 0x7FFFFFFF; } m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(SIMPLEVERTEX)); } } else { DWORD text_color = (p->selected) ? m_desktop_sel_text_color : m_desktop_text_color; if (pass==1) text_color &= 0x7FFFFFFF; m_d3dx_desktop_font->DrawText(p->name, -1, &p->label_rect, style, text_color); } } } } if (pass2==1) m_d3dx_desktop_font->End(); } } m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); m_lpDX->m_lpDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); m_lpDX->m_lpDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); // second, draw icon bitmaps (overtop) if (m_desktop_icon_state >= 2) { int dx = 0; int dy = 0; int iTexNum = 0; while (m_desktop_icons_texture[iTexNum] && iTexNum < MAX_ICON_TEXTURES) { HELPVERTEX verts[4]; m_lpDX->m_lpDevice->SetVertexShader( HELP_VERTEX_FORMAT ); m_lpDX->m_lpDevice->SetTexture(0, m_desktop_icons_texture[iTexNum]); for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) { int icon_tex_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx / (nAcross*nDown)); int icon_bitmap_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx % (nAcross*nDown)); if ( (icon_tex_idx == iTexNum) && (pass==0 || (p->selected && m_desktop_dragging)) ) { SetRect(&p->icon_rect, p->x - icon_dx + dx, p->y - icon_dy + dy, p->x - icon_dx + dx + m_desktop_icon_size, p->y - icon_dy + dy + m_desktop_icon_size); int lookup_x = 0; int lookup_y = 0; if (icon_bitmap_idx >= 0) // if -1, means icon didn't fit in the texture { lookup_x = icon_bitmap_idx % nAcross; lookup_y = icon_bitmap_idx / nAcross; } for (int i=0; i<4; i++) { verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width/2 + p->icon_rect.left) : (float)(-m_lpDX->m_client_width/2 + p->icon_rect.right ); verts[i].y = (i/2==0) ? (float)(m_lpDX->m_client_height/2 - p->icon_rect.top ) : (float)(m_lpDX->m_client_height/2 - p->icon_rect.bottom); verts[i].z = 0; verts[i].tu = ((lookup_x + i%2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE; verts[i].tv = ((lookup_y + i/2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE; verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : 0xFFFFFFFF; if (pass>0) { verts[i].x += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x; verts[i].y -= m_desktop_drag_curpos.y - m_desktop_drag_startpos.y; verts[i].Diffuse &= 0x7FFFFFFF; } } m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(HELPVERTEX)); } } iTexNum++; } } } // finally, draw selection box (if user is dragging one) if (m_desktop_box) { m_lpDX->m_lpDevice->SetVertexShader( SIMPLE_VERTEX_FORMAT ); m_lpDX->m_lpDevice->SetTexture(0, NULL); SIMPLEVERTEX verts[5]; for (int i=0; i<4; i++) { verts[i].x = (i==1||i==2) ? (float)(-m_lpDX->m_client_width/2 + m_desktop_drag_startpos.x) : (float)(-m_lpDX->m_client_width/2 + m_desktop_drag_curpos.x); verts[i].y = (i==0||i==1) ? (float)(m_lpDX->m_client_height/2 - m_desktop_drag_startpos.y) : (float)(m_lpDX->m_client_height/2 - m_desktop_drag_curpos.y); verts[i].z = 0; verts[i].Diffuse = 0x80FFFFFF; } verts[4] = verts[0]; m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, 4, verts, sizeof(SIMPLEVERTEX)); } m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); m_lpDX->m_lpDevice->SetTexture(0, NULL); LeaveCriticalSection(&m_desktop_cs); } //---------------------------------------------------------------------- /* NOTES LOG -problem: you can't click on the 1st monitor's desktop & do stuff -> fixed if you get rid of m_desktop_focuswnd and don't block WM_MOUSEACTIVATE. -> but doing this causes a flash when you click on the real desktop (in multimon setup) of any windows that are overtop of the fake desktop, since the fake desktop rises up in the Z order (activates) and then, next frame, gets pushed back again. -> so how do we avoid the flash? by [conditionally] stopping any z-order changes; intercept & change WM_WINDOWPOSCHANGING messages so there's no z-change, unless *we* specifically requested it (in PushWindowToBack()). -> new problem: right-click context menu won't go away until you click something. -> was fixed by making the plugin window a child of m_hWndDesktopListView. */