1 /*
2   LICENSE
3   -------
4 Copyright 2005-2013 Nullsoft, Inc.
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9 
10   * Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12 
13   * Redistributions in binary form must reproduce the above copyright notice,
14     this list of conditions and the following disclaimer in the documentation
15     and/or other materials provided with the distribution.
16 
17   * Neither the name of Nullsoft nor the names of its contributors may be used to
18     endorse or promote products derived from this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
21 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include "api.h"
31 #include "pluginshell.h"
32 #include "resource.h"
33 #include "utility.h"
34 #include "defines.h"
35 #include <shellapi.h>
36 
37 //----------------------------------------------------------------------
38 
39 #define VMS_DESKTOP_DLLNAME (SUBDIR L"data\\vms_desktop.dll")
40 
41 //----------------------------------------------------------------------
42 
43 typedef struct _SIMPLEVERTEX
44 {
45     float x, y;      // screen position
46     float z;         // Z-buffer depth
47     DWORD Diffuse;   // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
48 } SIMPLEVERTEX, *LPSIMPLEVERTEX;
49 
50 typedef struct _HELPVERTEX
51 {
52     float x, y;      // screen position
53     float z;         // Z-buffer depth
54     DWORD Diffuse;   // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
55     float tu, tv;    // texture coordinates for texture #0
56 } HELPVERTEX, *LPHELPVERTEX;
57 
58 #define SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE)
59 #define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
60 
61 //----------------------------------------------------------------------
62 
63 // resides in vms_desktop.dll/lib:
64 int setHook(HWND hlv,HWND w,int version);
65 void removeHook();
66 
67 //----------------------------------------------------------------------
68 
69 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
IsVistaOrLater()70 bool IsVistaOrLater()
71 {
72     // adapted from "Getting the System Version" on MSDN - http://msdn2.microsoft.com/en-us/library/ms724429.aspx
73     OSVERSIONINFOEX osvi;
74     SYSTEM_INFO si;
75     PGNSI pGNSI;
76     BOOL bOsVersionInfoEx;
77 
78     ZeroMemory(&si, sizeof(SYSTEM_INFO));
79     ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
80     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
81     if (bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi))
82     {
83         // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
84         pGNSI = (PGNSI) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo" );
85         if(NULL != pGNSI)
86             pGNSI(&si);
87         else
88             GetSystemInfo(&si);
89 
90         if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion > 4 )
91         {
92             if ( osvi.dwMajorVersion >= 6 )
93                 return true;
94         }
95     }
96     return false;
97 }
98 
InitDesktopMode()99 int CPluginShell::InitDesktopMode()
100 {
101     if (m_screenmode != DESKTOP)
102         return false;
103 
104     // check for Vista - if Vista, don't try to draw desktop icons.
105     // [ vms_desktop.dll's message posts to the desktop listview window cause explorer to crash...
106     //   whether it sends WM_NULL or WM_USER+516/517. ]
107     if (m_desktop_show_icons && IsVistaOrLater())
108         m_desktop_show_icons = false;
109 
110     if (!m_desktop_show_icons)
111         return true;
112 
113     // note: we have to explicitly make sure the DLL is present,
114     // since we're delay-loading it; otherwise, calling setHook, etc. will crash it.
115     wchar_t szVmsDesktopDll[MAX_PATH];
116     swprintf(szVmsDesktopDll, L"%s%s", GetPluginsDirPath(), VMS_DESKTOP_DLLNAME);
117     if (!GetModuleHandleW(szVmsDesktopDll))
118     {
119         if (!LoadLibraryW(szVmsDesktopDll))
120         {
121             wchar_t buf[2048];
122             swprintf(buf, WASABI_API_LNGSTRINGW(IDS_COULD_NOT_FIND_FILE_FOR_DESKTOP_MODE_X), szVmsDesktopDll);
123             MessageBoxW(GetPluginWindow(),buf,WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR_FILE_MISSING), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
124             //return false;
125             m_desktop_icons_disabled = 1;
126         }
127         else
128         {
129             m_vms_desktop_loaded = 1;
130         }
131     }
132 
133     InitializeCriticalSection(&m_desktop_cs);
134 
135     m_desktop_icon_state = 0;
136     m_desktop_icon_count = 0;
137     m_desktop_icon_update_frame = 0;
138     m_desktop_icon_size  = GetDesktopIconSize();
139 
140     // GDI font for desktop mode:
141 	LOGFONT lf = {0};
142 	wchar_t title[64];
143     if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0))
144     {
145         if (!(m_font_desktop = CreateFontIndirect(&lf)))
146         {
147             MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_DESKTOP_FONT),
148 					    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
149 					    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
150             return false;
151         }
152     }
153     else
154     {
155         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")))
156         {
157             MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_DESKTOP_FONT),
158 					    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
159 					    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
160             return false;
161         }
162     }
163 
164     // Create D3DX font for drawing icon labels on desktop:
165     if (pCreateFontW(m_lpDX->m_lpDevice, 14, 0, 0, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"Monotype Sans Serif", &m_d3dx_desktop_font) != D3D_OK)
166     {
167         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DESKTOP_FONT),
168 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
169 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
170         return false;
171     }
172 
173     // create first texture for holding icon bitmaps:
174     // (do it now, to ensure that at least 1 gets created, before
175     //  the plugin does all of its DX9 allocations.)
176     if (!CreateDesktopIconTexture(&m_desktop_icons_texture[0]))
177     {
178         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_TEXTURE_FOR_ICON_BITMAPS),
179 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
180 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
181     }
182 
183     if (!m_desktop_icons_disabled)
184     {
185         int ret = setHook(m_hWndDesktopListView, GetPluginWindow(), 1);
186         if (ret == 1)
187             m_desktop_hook_set = 1;
188         else if (ret == -1)
189             MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_OUTDATED_VMS_DESKTOP_DLL_NEED_TO_REINSTALL),
190 					    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
191 					    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
192         else
193             MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_HOOK_PROC_DESKTOP_ICONS_NOT_AVAILABLE),
194 					    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
195 					    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
196     }
197 
198     return true;
199 }
200 
201 //----------------------------------------------------------------------
202 
CleanUpDesktopMode()203 void CPluginShell::CleanUpDesktopMode()
204 {
205     if (m_screenmode != DESKTOP)
206         return;
207     if (!m_desktop_show_icons)
208         return;
209 
210     if (m_desktop_hook_set)
211     {
212         m_desktop_hook_set = 0;
213         removeHook();
214     }
215 
216     for (int i=0; i<MAX_ICON_TEXTURES; i++)
217         SafeRelease(m_desktop_icons_texture[i]);
218     SafeRelease(m_d3dx_desktop_font);
219 
220     if (m_desktop_wc_registered)
221     {
222         UnregisterClass(DESKTOP_MODE_KEYBOARD_INPUT_WINDOW_CLASSNAME, m_hInstance);
223         m_desktop_wc_registered = 0;
224     }
225 
226     if (m_font_desktop)
227     {
228         DeleteObject(m_font_desktop);
229         m_font_desktop = 0;
230     }
231 
232     m_icon_list.clear();
233 
234     DeleteCriticalSection(&m_desktop_cs);
235 
236     if (m_vms_desktop_loaded)
237     {
238         char szVmsDesktopDll[MAX_PATH];
239         sprintf(szVmsDesktopDll, "%s%s", GetPluginsDirPath(), VMS_DESKTOP_DLLNAME);
240         FreeLibrary(GetModuleHandle(szVmsDesktopDll));
241         m_vms_desktop_loaded = 0;
242     }
243 }
244 
245 //----------------------------------------------------------------------
246 
CreateDesktopIconTexture(IDirect3DTexture9 ** ppTex)247 int CPluginShell::CreateDesktopIconTexture(IDirect3DTexture9** ppTex)
248 {
249     // release old texture (shouldn't really be necessary)
250     if (*ppTex)
251     {
252         (*ppTex)->Release();
253         *ppTex = NULL;
254     }
255 
256     // create new
257     int ntries = (m_lpDX->m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5) ? 3 : 1;
258     for (int ntry=0; ntry<ntries; ntry++)
259     {
260         D3DFORMAT fmt = m_lpDX->m_d3dpp.BackBufferFormat;
261         switch(m_lpDX->m_d3dpp.BackBufferFormat)
262         {
263         case D3DFMT_R8G8B8:
264         case D3DFMT_X8R8G8B8:
265             fmt = D3DFMT_A8R8G8B8;
266             break;
267         case D3DFMT_R5G6B5: // <- PROBLEM: NO ALPHA CHANNEL FOR ICONS
268             if (ntry==0)
269                 switch(m_desktop_555_fix)
270                 {
271                 case 0: fmt = D3DFMT_R5G6B5;   break;
272                 case 1: fmt = D3DFMT_A1R5G5B5; break;
273                 case 2: fmt = D3DFMT_A8R8G8B8; break;
274                 }
275             else if (ntry==1)
276                 switch(m_desktop_555_fix)
277                 {
278                 case 0: fmt = D3DFMT_A1R5G5B5; break;
279                 case 1: fmt = D3DFMT_A8R8G8B8; break;
280                 case 2: fmt = D3DFMT_A1R5G5B5; break;
281                 }
282             else
283                 switch(m_desktop_555_fix)
284                 {
285                 case 0: fmt = D3DFMT_A8R8G8B8; break;
286                 case 1: fmt = D3DFMT_R5G6B5;   break;
287                 case 2: fmt = D3DFMT_R5G6B5;   break;
288                 }
289             break;
290         case D3DFMT_X1R5G5B5:
291             fmt = D3DFMT_A1R5G5B5;
292             break;
293         }
294 
295         if (m_lpDX->m_lpDevice->CreateTexture(ICON_TEXTURE_SIZE, ICON_TEXTURE_SIZE, 1, 0, fmt, D3DPOOL_MANAGED, ppTex, NULL) != D3D_OK)
296             *ppTex = NULL;
297         else
298             break;
299     }
300 
301     return (*ppTex) ? 1 : 0;
302 }
303 
304 //----------------------------------------------------------------------
305 
DeselectDesktop()306 void CPluginShell::DeselectDesktop()
307 {
308     IconList::iterator p;
309     for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
310         p->selected = 0;
311 }
312 
313 //----------------------------------------------------------------------
314 
UpdateDesktopBitmaps()315 void CPluginShell::UpdateDesktopBitmaps()
316 {
317     // update the D3DX textures that hold all the icons:
318 
319     int idx = 0;
320     int texnum = 0;
321     int show_msgs = 1;
322 
323     // if no icon texture could be created at startup,
324     // don't bother trying anything here, and don't give them
325     // any extra error messages.
326     if (!m_desktop_icons_texture[0])
327         return;
328 
329     IconList::iterator p;
330     for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
331         p->icon_bitmap_idx = -1;
332 
333     do
334     {
335         idx = StuffIconBitmaps(idx, texnum++, &show_msgs);
336     }
337     while (idx > 0 && texnum < MAX_ICON_TEXTURES);
338 
339 	if (idx > 0)
340 	{
341 		wchar_t title[64];
342         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS),
343 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64),
344 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
345 	}
346 }
347 
348 //----------------------------------------------------------------------
349 
StuffIconBitmaps(int iStartIconIdx,int iTexNum,int * show_msgs)350 int CPluginShell::StuffIconBitmaps(int iStartIconIdx, int iTexNum, int *show_msgs)
351 {
352     // returns:
353     //   0 if done (or error), or
354     //   N if the texture is full & we need to start another one,
355     //      where N is the new iStartIconIdx to use.
356 
357     if (m_screenmode != DESKTOP)
358         return 0;
359 
360 	wchar_t title[64];
361     if (!m_desktop_icons_texture[iTexNum])
362     {
363         int ret = CreateDesktopIconTexture(&m_desktop_icons_texture[iTexNum]);
364         if (!ret)
365         {
366             MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_TOO_MANY_UNIQUE_ICON_BITMAPS),
367 					    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64),
368 					    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
369             return 0;
370         }
371     }
372 
373     D3DSURFACE_DESC sd;
374     if (m_desktop_icons_texture[iTexNum]->GetLevelDesc(0, &sd) != D3D_OK)
375     {
376         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_COULD_NOT_GET_LEVEL_DESCRIPTION),
377 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
378 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
379         return 0;
380     }
381 
382     D3DLOCKED_RECT lr;
383     if (m_desktop_icons_texture[iTexNum]->LockRect(0, &lr, NULL, 0) != D3D_OK)
384     {
385         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_LOCKRECT_FAILED),
386 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
387 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
388         return 0;
389     }
390     if (lr.pBits == NULL)
391     {
392         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_LR_PBITS_IS_NULL),
393 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
394 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
395         m_desktop_icons_texture[iTexNum]->UnlockRect(0);
396         return 0;
397     }
398 
399     unsigned __int16* p16 = (unsigned __int16*)lr.pBits;
400     unsigned __int32* p32 = (unsigned __int32*)lr.pBits;
401     int WIDTH = sd.Width;
402 
403     int i;
404 
405     int start;
406     int bpp;
407     int rshift[3];      // 1. bits to first shift right r,g,b
408     int mask[3];        // 2. mask for r, g, b
409     int lshift[3];      // 3. bits to then shift left r,g,b
410 
411     switch(sd.Format)
412     {
413     case D3DFMT_R8G8B8:
414     case D3DFMT_A8R8G8B8:
415     case D3DFMT_X8R8G8B8:
416         start = 0xFF000000;
417         bpp = 32;
418         rshift[0] = 0;
419         rshift[1] = 0;
420         rshift[2] = 0;
421         mask[0] = 0xFF;
422         mask[1] = 0xFF;
423         mask[2] = 0xFF;
424         lshift[0] = 16;
425         lshift[1] = 8;
426         lshift[2] = 0;
427         break;
428 
429     case D3DFMT_R5G6B5:
430         start = 0x0000;
431         bpp = 16;
432         rshift[0] = 3;
433         rshift[1] = 2;
434         rshift[2] = 3;
435         mask[0] = 0x1F;
436         mask[1] = 0x3F;
437         mask[2] = 0x1F;
438         lshift[0] = 11;
439         lshift[1] = 5;
440         lshift[2] = 0;
441         break;
442 
443     case D3DFMT_X1R5G5B5:
444     case D3DFMT_A1R5G5B5:
445         start = 0x8000;
446         bpp = 16;
447         rshift[0] = 3;
448         rshift[1] = 3;
449         rshift[2] = 3;
450         mask[0] = 0x1F;
451         mask[1] = 0x1F;
452         mask[2] = 0x1F;
453         lshift[0] = 10;
454         lshift[1] = 5;
455         lshift[2] = 0;
456         break;
457 
458     case D3DFMT_A4R4G4B4:
459         start = 0xF000;
460         bpp = 16;
461         rshift[0] = 4;
462         rshift[1] = 4;
463         rshift[2] = 4;
464         mask[0] = 0x0F;
465         mask[1] = 0x0F;
466         mask[2] = 0x0F;
467         lshift[0] = 8;
468         lshift[1] = 4;
469         lshift[2] = 0;
470         break;
471 
472     default:
473         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_UNKNOWN_PIXEL_FORMAT),
474 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
475 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
476         m_desktop_icons_texture[iTexNum]->UnlockRect(0);
477         return 0;
478     }
479 
480     HDC hdc = GetDC(NULL);
481     if (!hdc)
482     {
483         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_COULDNT_GET_HDC),
484 				    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
485 				    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
486         m_desktop_icons_texture[iTexNum]->UnlockRect(0);
487         return 0;
488     }
489 
490     #define MAX_ICON_SIZE 128
491     unsigned char data[MAX_ICON_SIZE*MAX_ICON_SIZE*4];
492 
493     int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size;
494     int nDown   = ICON_TEXTURE_SIZE/m_desktop_icon_size;
495 
496     // for each icon, add its bitmap to the texture (if not already there),
497     //   and set 'icon_bitmap_idx'.
498     IconList::iterator p = m_icon_list.begin();
499     for (i=0; i < iStartIconIdx; i++)
500         p++;
501 
502     int bitmap_idx = 0;
503     int list_idx   = iStartIconIdx;
504 
505     for ( ; p != m_icon_list.end() && bitmap_idx < nAcross*nDown; p++)
506     {
507         // note: 'p' points to the correct icon to start with,
508         //       but 'idx' starts at zero!
509 
510         // get the icon:
511         SHFILEINFO sfi;
512         int flags = SHGFI_ICON|SHGFI_PIDL|SHGFI_SHELLICONSIZE | ((m_desktop_icon_size > 32) ? SHGFI_LARGEICON : 0);
513         if (SHGetFileInfo((LPCTSTR)p->pidl, 0, &sfi, sizeof(sfi), flags))
514         {
515             ICONINFO ii;
516             if (GetIconInfo(sfi.hIcon, &ii))
517             {
518                 int x0 = (bitmap_idx%nAcross)*m_desktop_icon_size;
519                 int y0 = (bitmap_idx/nAcross)*m_desktop_icon_size;
520                 int checksum[3] = { 0, 0, 0 };
521 
522                 BITMAPINFO bmi;
523 
524                 // pass 1: get the colors
525 
526                 bmi.bmiHeader.biSize   = sizeof(BITMAPINFOHEADER);
527                 bmi.bmiHeader.biWidth  = m_desktop_icon_size;
528                 bmi.bmiHeader.biHeight = m_desktop_icon_size;
529                 bmi.bmiHeader.biPlanes = 1;
530                 bmi.bmiHeader.biBitCount = 32;
531                 bmi.bmiHeader.biCompression = BI_RGB;
532 
533                 if (GetDIBits(
534                   hdc,               // handle to DC
535                   ii.hbmColor,       // handle to bitmap
536                   0,                 // first scan line to set
537                   m_desktop_icon_size,// number of scan lines to copy
538                   data,              // array for bitmap bits
539                   &bmi,              // bitmap data buffer
540                   DIB_RGB_COLORS     // RGB or palette index
541                 ))
542                 {
543                     int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size);
544                     int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size);
545 
546                     for (int y=0; y<h; y++)
547                     for (int x=0; x<w; x++)
548                     {
549                         int in_offset = ((h-1-y)*w + x)*4;
550                         int r = data[in_offset+2];
551                         int g = data[in_offset+1];
552                         int b = data[in_offset+0];
553 
554                         checksum[0] += r;
555                         checksum[1] += g;
556                         checksum[2] += b;
557 
558                         int out_offset = (y0+y)*WIDTH + (x0+x);
559                         if (bpp==16)
560                             p16[out_offset] = start |
561                                 (((r >> rshift[0]) & mask[0]) << lshift[0]) |
562                                 (((g >> rshift[1]) & mask[1]) << lshift[1]) |
563                                 (((b >> rshift[2]) & mask[2]) << lshift[2]);
564                         else
565                             p32[out_offset] = start |
566                                 (((r >> rshift[0]) & mask[0]) << lshift[0]) |
567                                 (((g >> rshift[1]) & mask[1]) << lshift[1]) |
568                                 (((b >> rshift[2]) & mask[2]) << lshift[2]);
569                     }
570                 }
571                 else
572                 {
573                     if (*show_msgs)
574                         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_TO_GETDIBITS_FAILED),
575 								    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
576 								    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
577                     *show_msgs = 0;
578                 }
579 
580                 // pass 2: get the alpha mask
581 
582                 bmi.bmiHeader.biSize   = sizeof(BITMAPINFOHEADER);
583                 bmi.bmiHeader.biWidth  = m_desktop_icon_size;
584                 bmi.bmiHeader.biHeight = m_desktop_icon_size;
585                 bmi.bmiHeader.biPlanes = 1;
586                 bmi.bmiHeader.biBitCount = 32;
587                 bmi.bmiHeader.biCompression = BI_RGB;
588 
589                 if (GetDIBits(
590                   hdc,               // handle to DC
591                   ii.hbmMask,        // handle to bitmap
592                   0,                 // first scan line to set
593                   m_desktop_icon_size,// number of scan lines to copy
594                   data,              // array for bitmap bits
595                   &bmi,              // bitmap data buffer
596                   DIB_RGB_COLORS     // RGB or palette index
597                 ))
598                 {
599                     int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size);
600                     int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size);
601 
602                     for (int y=0; y<h; y++)
603                     for (int x=0; x<w; x++)
604                     {
605                         int in_offset = ((h-1-y)*w + x)*4;
606                         int r = data[in_offset+2];
607                         int g = data[in_offset+1];
608                         int b = data[in_offset+0];
609 
610                         checksum[0] += r;
611                         checksum[1] += g;
612                         checksum[2] += b;
613 
614                         if (r || g || b)
615                         {
616                             int out_offset = (y0+y)*WIDTH + (x0+x);
617                             if (bpp==16)
618                                 p16[out_offset] &= ~start;
619                             else
620                                 p32[out_offset] &= ~start;
621                         }
622                     }
623                 }
624                 else
625                 {
626                     if (*show_msgs)
627                         MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_2_TO_GETDIBITS_FAILED),
628 								    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
629 								    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
630                     *show_msgs = 0;
631                 }
632 
633                 // check for duplicate icon, and if found, reuse it
634                 int done = 0;
635                 IconList::iterator q;
636                 for (q = m_icon_list.begin(); q != m_icon_list.end() && q != p; q++)
637                 {
638                     if (checksum[0] == q->checksum[0] &&
639                         checksum[1] == q->checksum[1] &&
640                         checksum[2] == q->checksum[2])
641                     {
642                         p->icon_bitmap_idx = q->icon_bitmap_idx;
643                         done = 1;
644                         break;
645                     }
646                 }
647 
648                 // otherwise, keep new icon
649                 if (!done)
650                 {
651                     p->icon_bitmap_idx = nAcross*nDown*iTexNum + bitmap_idx;
652                     p->checksum[0] = checksum[0];
653                     p->checksum[1] = checksum[1];
654                     p->checksum[2] = checksum[2];
655 
656                     bitmap_idx++;
657                 }
658 
659                 DeleteObject(ii.hbmMask);
660                 DeleteObject(ii.hbmColor);
661             }
662             else
663             {
664                 if (*show_msgs)
665                     MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_GETICONINFO_FAILED),
666 							    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
667 							    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
668                 *show_msgs = 0;
669             }
670 
671             DestroyIcon(sfi.hIcon);
672         }
673         else
674         {
675             if (*show_msgs)
676                 MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_SHGETFILEINFO_FAILED),
677 						    WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
678 						    MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
679             *show_msgs = 0;
680         }
681 
682         list_idx++;
683     }
684 
685     ReleaseDC(NULL, hdc);
686     m_desktop_icons_texture[iTexNum]->UnlockRect(0);
687 
688     if (bitmap_idx >= nAcross*nDown)
689         return list_idx;
690     else
691         return 0; // all done
692 }
693 
694 //----------------------------------------------------------------------
695 
RenderDesktop()696 void CPluginShell::RenderDesktop()
697 {
698     if (m_screenmode != DESKTOP)
699         return;
700     if (!m_desktop_show_icons)
701         return;
702     if (m_desktop_icons_disabled)
703         return;
704 
705     IconList::iterator p;
706 
707     EnterCriticalSection(&m_desktop_cs);
708 
709 	int iconcount = static_cast<unsigned long>(SendMessage(m_hWndDesktopListView, LVM_GETITEMCOUNT, 0, 0));
710     if (iconcount == 0)
711     {
712         LeaveCriticalSection(&m_desktop_cs);
713         return;
714     }
715 
716     // if the icons list is empty,
717     // or if we check it for consistency and an update is recommended (GetDesktopIcons(1)==2),
718     // update the icons list & the bitmaps:
719     /*if (m_icon_list.size()==0 || GetDesktopIcons(1)==2)
720     {
721         m_icon_list.clear();
722         GetDesktopIcons(0);
723 
724         UpdateDesktopBitmaps();
725     }*/
726 
727     // check for invalid entries.  (if there is an error in getItemData(),
728     // it will return the icon_t structure anyway, but with empty strings.)
729     int invalid_entries = 0;
730     if (m_desktop_icon_state >= 2)
731     {
732         for (p = m_icon_list.begin(); p != m_icon_list.end() && !invalid_entries; p++)
733         {
734             if (p->name[0]==0)
735                 invalid_entries = 1;
736             //if (p->pidl[0].mkid.cb==0 && p->pidl[0].mkid.abID[0]==0)
737             if (p->pidl[0]==0 && p->pidl[1]==0)
738                 invalid_entries = 1;
739         }
740     }
741 
742     if (
743         (m_desktop_icon_state == 0)         ||
744         (m_desktop_icon_state >= 2 && m_desktop_icon_count != iconcount)   ||
745         (m_desktop_icon_state >= 2 && invalid_entries)
746        )
747     {
748         // begin total refresh
749         m_desktop_icon_state = 1;
750         m_desktop_icon_count = iconcount;
751         m_desktop_icon_update_frame = GetFrame();
752         m_icon_list.clear();
753 
754         SendMessage(GetPluginWindow(), WM_USER, 0x80000000 | iconcount, 0);//getItemData(i);
755 
756         // try to get the desktop window's listview to respond to
757         // the queries as quickly as possible:
758         {
759             LeaveCriticalSection(&m_desktop_cs);
760 
761             DWORD procid = NULL;
762             DWORD threadid = GetWindowThreadProcessId(m_hWndDesktopListView, &procid);
763 
764             HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, FALSE, procid);
765             DWORD x = GetPriorityClass(hProcess);
766             if (x) SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
767 
768             for (int i=0; i<5; i++)
769             {
770                 Sleep(10);
771 
772                 MSG msg;
773                 while(PeekMessage(&msg,GetPluginWindow(),0,0,PM_REMOVE))
774                 {
775                     TranslateMessage(&msg);
776                     DispatchMessage(&msg);
777                 }
778             }
779 
780             if (x) SetPriorityClass(hProcess, x);
781             CloseHandle(hProcess);
782 
783             EnterCriticalSection(&m_desktop_cs);
784         }
785     }
786     else if (m_desktop_icon_state == 1 &&
787              m_icon_list.size() < (size_t)m_desktop_icon_count)
788     {
789         // waiting for the 'total refresh' to complete
790         // ...
791         if (GetFrame() > m_desktop_icon_update_frame+64)
792         {
793             m_desktop_icon_state = 0;
794         }
795     }
796     else
797     if (m_desktop_icon_state == 1 &&
798         m_icon_list.size() == m_desktop_icon_count)
799     {
800         // done with total refresh
801         m_desktop_icon_state = 2;
802         m_desktop_icon_update_frame = GetFrame();
803         UpdateDesktopBitmaps();
804     }
805     else if (m_desktop_icon_state == 2)
806     {
807         if (GetFrame() > m_desktop_icon_update_frame+4)
808         {
809             m_desktop_icon_state = 3; // will mean we're waiting on data to return.
810             m_desktop_icon_update_frame = GetFrame();
811             int start = 0;
812             int len = iconcount;
813             SendMessage(GetPluginWindow(), WM_USER, start | (len << 16), 0);//getItemData(i);
814         }
815     }
816     else if (m_desktop_icon_state == 3)
817     {
818         if (GetFrame() > m_desktop_icon_update_frame+64)
819         {
820             // timeout; give up waiting for update message to come back,
821             // and just request another.
822             m_desktop_icon_state = 2;
823             m_desktop_icon_update_frame = GetFrame();
824         }
825     }
826 
827     // get horz. spacing between icons (...determines width of labels)
828     ICONMETRICS icm;
829     icm.cbSize = sizeof(icm);
830     if (!SystemParametersInfo(SPI_GETICONMETRICS, sizeof(icm), &icm, 0))
831         icm.iHorzSpacing = 68;
832 
833     /*int font_height = 0;
834     {
835         RECT r;
836         m_d3dx_desktop_font->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF);
837         font_height = r.bottom - r.top;
838     }*/
839 
840     // display the desktop.
841 
842     m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
843 
844 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
845 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
846 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
847 	m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
848 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);//D3DTOP_SELECTARG1 );
849     m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
850 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
851 	m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
852 
853     int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size;
854     int nDown   = ICON_TEXTURE_SIZE/m_desktop_icon_size;
855 
856     // The icon's x and y coordinates (as returned by the
857     // getIconData/WM_COPYDATA system) are (0,0) at the
858     // upper-left corner of the rectangle that encompasses
859     // all the monitors together (m_lpDX->m_all_monitors_rect).
860 
861     // Note that in 'm_all_monitors_rect', (0,0) represents
862     // the upper-left corner of the PRIMARY DISPLAY - not necessarily
863     // the one we're showing the fake desktop on.
864 
865     // What we have to do here is determine icon_dx and icon_dy,
866     // which are the transformation from the coordinate space used
867     // by the desktop itself (as returned in WM_COPYDATA)
868     // and the coordinates used by Windows itself (where 0,0 is
869     // the upper-left corner of the PRIMARY DISPLAY, and coordinates
870     // in other displays can be negative if they are above/left of it).
871 
872     int upperleft_x = min(m_lpDX->m_all_monitors_rect.left, m_lpDX->m_monitor_rect.left);
873     int upperleft_y = min(m_lpDX->m_all_monitors_rect.top , m_lpDX->m_monitor_rect.top );
874     int icon_dx = m_lpDX->m_monitor_rect.left - upperleft_x; // subtract this amount
875     int icon_dy = m_lpDX->m_monitor_rect.top  - upperleft_y; // subtract this amount
876 
877     if (!m_desktop_manual_icon_scoot)
878     {
879         icon_dx -= m_lpDX->m_monitor_rect.left - m_lpDX->m_monitor_work_rect.left;
880         icon_dy -= m_lpDX->m_monitor_rect.top  - m_lpDX->m_monitor_work_rect.top ;
881     }
882 
883     // pass 0: draw normal text & icons
884     // pass 1: redraw icon currently being dragged, transparently
885     int nPasses = m_desktop_dragging ? 2 : 1;
886     for (int pass=0; pass<nPasses; pass++)
887     {
888         // first, draw [blue backgrounds &] text labels
889         {
890             m_lpDX->m_lpDevice->SetVertexShader( NULL );
891             m_lpDX->m_lpDevice->SetFVF( SIMPLE_VERTEX_FORMAT );
892             m_lpDX->m_lpDevice->SetTexture(0, NULL);
893             SIMPLEVERTEX verts[4];
894 
895             // pass2==0: draw text labels
896             // pass2==1: draw text overtop
897             // (separated for speed, so ID3DXFont can get the HDC just once for all the DrawText calls)
898             for (int pass2=0; pass2<2; pass2++)
899             {
900                 //if (pass2==1)
901                     //m_d3dx_desktop_font->Begin();
902 
903                 for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
904                 {
905                     if (pass==0 || (p->selected && m_desktop_dragging))
906                     {
907                         int max_width = icm.iHorzSpacing-5+m_desktop_icon_size-32;//icm.iHorzSpacing-5;
908 
909                         int dx = 0;
910                         int dy = 4;
911 
912                         if (pass>0)
913                         {
914                             dx += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x;
915                             dy += m_desktop_drag_curpos.y - m_desktop_drag_startpos.y;
916                         }
917 
918                         SetRect(&p->label_rect,
919                             p->x + m_desktop_icon_size/2 - icon_dx - max_width/2 + dx,
920                             p->y + m_desktop_icon_size   - icon_dy               + dy,
921                             p->x + m_desktop_icon_size/2 - icon_dx + max_width/2 + dx,
922                             p->y + m_desktop_icon_size   - icon_dy + 0           + dy // will be extended by DT_CALCRECT step!
923                         );
924 
925                         // calculate rect for the text label
926                         DWORD style = DT_CENTER|DT_WORDBREAK|DT_END_ELLIPSIS|DT_WORD_ELLIPSIS;
927                         // these aren't supported by D3DX9:
928                         style &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX);
929                         m_d3dx_desktop_font->DrawText(NULL, p->name, -1, &p->label_rect, style|DT_CALCRECT, 0xFFFFFFFF);
930 
931                         // D3DX doesn't handle text so well if it goes off
932                         // the left edge of the screen, so don't show text labels
933                         // that are mostly off (on the left side):
934                         if ((p->label_rect.left + p->label_rect.right)/2 > 0)
935                         {
936                             // also, if label would go off left edge of screen,
937                             // push it to the right:
938                             if (p->label_rect.left < 0 && p->label_rect.right > 0)
939                             {
940                                 p->label_rect.right -= p->label_rect.left;
941                                 p->label_rect.left = 0;
942                             }
943 
944                             //if (p->selected)  // ...draw blue background around text label
945                             if (pass2==0)
946                             {
947                                 if (m_desktop_textlabel_boxes || p->selected)
948                                 {
949                                     #define EXTEND_LEFT   3
950                                     #define EXTEND_RIGHT  2
951                                     #define EXTEND_TOP    0
952                                     #define EXTEND_BOTTOM 2
953                                     for (int i=0; i<4; i++)
954                                     {
955                                         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
956                                         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
957                                         verts[i].z = 0;
958                                         verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : m_desktop_bk_color;//0xFF000000;
959                                         if (pass>0)
960                                             verts[i].Diffuse &= 0x7FFFFFFF;
961                                     }
962                                     m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(SIMPLEVERTEX));
963                                 }
964                             }
965                             else
966                             {
967                                 DWORD text_color = (p->selected) ? m_desktop_sel_text_color : m_desktop_text_color;
968                                 if (pass==1)
969                                     text_color &= 0x7FFFFFFF;
970                                 // these aren't supported by D3DX9:
971                                 style &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX);
972                                 m_d3dx_desktop_font->DrawText(NULL, p->name, -1, &p->label_rect, style, text_color);
973                             }
974                         }
975                     }
976                 }
977 
978                 //if (pass2==1)
979                 //    m_d3dx_desktop_font->End();
980             }
981         }
982 
983         m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
984         m_lpDX->m_lpDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
985         m_lpDX->m_lpDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
986 
987         // second, draw icon bitmaps (overtop)
988         if (m_desktop_icon_state >= 2)
989         {
990             int dx = 0;
991             int dy = 0;
992             int iTexNum = 0;
993 
994             while (m_desktop_icons_texture[iTexNum] && iTexNum < MAX_ICON_TEXTURES)
995             {
996                 HELPVERTEX verts[4];
997                 m_lpDX->m_lpDevice->SetVertexShader( NULL );
998                 m_lpDX->m_lpDevice->SetFVF( HELP_VERTEX_FORMAT );
999                 m_lpDX->m_lpDevice->SetTexture(0, m_desktop_icons_texture[iTexNum]);
1000 
1001                 for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
1002                 {
1003                     int icon_tex_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx / (nAcross*nDown));
1004                     int icon_bitmap_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx % (nAcross*nDown));
1005                     if (
1006                         (icon_tex_idx == iTexNum) &&
1007                         (pass==0 || (p->selected && m_desktop_dragging))
1008                        )
1009                     {
1010                         SetRect(&p->icon_rect,
1011                             p->x - icon_dx + dx,
1012                             p->y - icon_dy + dy,
1013                             p->x - icon_dx + dx + m_desktop_icon_size,
1014                             p->y - icon_dy + dy + m_desktop_icon_size);
1015 
1016                         int lookup_x = 0;
1017                         int lookup_y = 0;
1018 
1019                         if (icon_bitmap_idx >= 0)  // if -1, means icon didn't fit in the texture
1020                         {
1021                             lookup_x = icon_bitmap_idx % nAcross;
1022                             lookup_y = icon_bitmap_idx / nAcross;
1023                         }
1024 
1025                         for (int i=0; i<4; i++)
1026                         {
1027                             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 );
1028                             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);
1029                             verts[i].z = 0;
1030                             verts[i].tu = ((lookup_x + i%2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE;
1031                             verts[i].tv = ((lookup_y + i/2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE;
1032                             verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : 0xFFFFFFFF;
1033                             if (pass>0)
1034                             {
1035                                 verts[i].x += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x;
1036                                 verts[i].y -= m_desktop_drag_curpos.y - m_desktop_drag_startpos.y;
1037                                 verts[i].Diffuse &= 0x7FFFFFFF;
1038                             }
1039                         }
1040 
1041                         m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(HELPVERTEX));
1042                     }
1043                 }
1044 
1045                 iTexNum++;
1046             }
1047         }
1048     }
1049 
1050     // finally, draw selection box (if user is dragging one)
1051     if (m_desktop_box)
1052     {
1053         m_lpDX->m_lpDevice->SetVertexShader( NULL );
1054         m_lpDX->m_lpDevice->SetFVF( SIMPLE_VERTEX_FORMAT );
1055         m_lpDX->m_lpDevice->SetTexture(0, NULL);
1056         SIMPLEVERTEX verts[5];
1057         for (int i=0; i<4; i++)
1058         {
1059             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);
1060             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);
1061             verts[i].z = 0;
1062             verts[i].Diffuse = 0x80FFFFFF;
1063         }
1064         verts[4] = verts[0];
1065         m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, 4, verts, sizeof(SIMPLEVERTEX));
1066     }
1067 
1068     m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
1069 	m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
1070     m_lpDX->m_lpDevice->SetTexture(0, NULL);
1071 
1072     LeaveCriticalSection(&m_desktop_cs);
1073 }
1074 
1075 //----------------------------------------------------------------------
1076 
1077 /*
1078 NOTES LOG
1079 
1080 -problem: you can't click on the 1st monitor's desktop & do stuff
1081     -> fixed if you get rid of m_desktop_focuswnd and
1082         don't block WM_MOUSEACTIVATE.
1083     -> but doing this causes a flash when you click on
1084         the real desktop (in multimon setup) of any windows
1085         that are overtop of the fake desktop, since the
1086         fake desktop rises up in the Z order (activates)
1087         and then, next frame, gets pushed back again.
1088     -> so how do we avoid the flash?
1089         by [conditionally] stopping any z-order changes;
1090         intercept & change WM_WINDOWPOSCHANGING messages
1091         so there's no z-change, unless *we* specifically
1092         requested it (in PushWindowToBack()).
1093     -> new problem: right-click context menu won't go away
1094         until you click something.
1095     -> was fixed by making the plugin window a child
1096         of m_hWndDesktopListView.
1097 */