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 */