xref: /reactos/dll/cpl/desk/background.c (revision 769fcd89)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Display Control Panel
4  * FILE:            dll/cpl/desk/background.c
5  * PURPOSE:         Background property page
6  *
7  * PROGRAMMERS:     Trevor McCort (lycan359@gmail.com)
8  *                  Alexey Minnekhanov (minlexx@rambler.ru)
9  */
10 
11 #include "desk.h"
12 
13 #include <shellapi.h>
14 #include <shlwapi.h>
15 
16 #define MAX_BACKGROUNDS     100
17 
18 typedef enum
19 {
20     PLACEMENT_CENTER = 0,
21     PLACEMENT_STRETCH,
22     PLACEMENT_TILE,
23     PLACEMENT_FIT,
24     PLACEMENT_FILL
25 } PLACEMENT;
26 
27 /* The tile placement is stored in different registry
28  * key, but due to a condition in win32k it needs to be
29  * zero when stored in the same key as others.
30  */
31 typedef enum
32 {
33     PLACEMENT_VALUE_CENTER    = 0,
34     PLACEMENT_VALUE_STRETCH   = 2,
35     PLACEMENT_VALUE_TILE      = 0,
36     PLACEMENT_VALUE_FIT       = 6,
37     PLACEMENT_VALUE_FILL      = 10
38 } PLACEMENT_VALUE;
39 
40 typedef struct
41 {
42     BOOL bWallpaper; /* Is this background a wallpaper */
43 
44     TCHAR szFilename[MAX_PATH];
45     TCHAR szDisplayName[256];
46 
47 } BackgroundItem;
48 
49 typedef struct _BACKGROUND_DATA
50 {
51     BOOL bWallpaperChanged;
52     BOOL bClrBackgroundChanged;
53 
54     BackgroundItem backgroundItems[MAX_BACKGROUNDS];
55 
56     PDIBITMAP pWallpaperBitmap;
57 
58     int placementSelection;
59     int backgroundSelection;
60 
61     COLORREF custom_colors[16];
62 
63     int listViewItemCount;
64 
65     ULONG_PTR gdipToken;
66 
67     DESKTOP_DATA desktopData;
68 } BACKGROUND_DATA, *PBACKGROUND_DATA;
69 
70 GLOBAL_DATA g_GlobalData;
71 
72 
73 HRESULT
GdipGetEncoderClsid(PCWSTR MimeType,CLSID * pClsid)74 GdipGetEncoderClsid(PCWSTR MimeType, CLSID *pClsid)
75 {
76     UINT num;
77     UINT size;
78     UINT i;
79     ImageCodecInfo *codecInfo;
80 
81     if (GdipGetImageEncodersSize(&num, &size) != Ok ||
82         size == 0)
83     {
84         return E_FAIL;
85     }
86 
87     codecInfo = HeapAlloc(GetProcessHeap(), 0, size);
88     if (!codecInfo)
89     {
90         return E_OUTOFMEMORY;
91     }
92 
93     if (GdipGetImageEncoders(num, size, codecInfo) != Ok)
94     {
95         HeapFree(GetProcessHeap(), 0, codecInfo);
96         return E_FAIL;
97     }
98 
99     for (i = 0; i < num; i++)
100     {
101         if (!_wcsicmp(codecInfo[i].MimeType, MimeType))
102         {
103             *pClsid = codecInfo[i].Clsid;
104             HeapFree(GetProcessHeap(), 0, codecInfo);
105             return S_OK;
106         }
107     }
108 
109     HeapFree(GetProcessHeap(), 0, codecInfo);
110     return E_FAIL;
111 }
112 
113 
114 LPWSTR
GdipGetSupportedFileExtensions(VOID)115 GdipGetSupportedFileExtensions(VOID)
116 {
117     ImageCodecInfo *codecInfo;
118     UINT num;
119     UINT size;
120     UINT i;
121     LPWSTR lpBuffer = NULL;
122 
123     if (GdipGetImageDecodersSize(&num, &size) != Ok ||
124         size == 0)
125     {
126         return NULL;
127     }
128 
129     codecInfo = HeapAlloc(GetProcessHeap(), 0, size);
130     if (!codecInfo)
131     {
132         return NULL;
133     }
134 
135     if (GdipGetImageDecoders(num, size, codecInfo) != Ok)
136     {
137         HeapFree(GetProcessHeap(), 0, codecInfo);
138         return NULL;
139     }
140 
141     size = 0;
142     for (i = 0; i < num; ++i)
143     {
144         size = size + (UINT)wcslen(codecInfo[i].FilenameExtension) + 1;
145     }
146 
147     size = (size + 1) * sizeof(WCHAR);
148 
149     lpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
150     if (!lpBuffer)
151     {
152         HeapFree(GetProcessHeap(), 0, codecInfo);
153         return NULL;
154     }
155 
156     for (i = 0; i < num; ++i)
157     {
158         StringCbCatW(lpBuffer, size, codecInfo[i].FilenameExtension);
159         if (i < (num - 1))
160         {
161             StringCbCatW(lpBuffer, size, L";");
162         }
163     }
164 
165     HeapFree(GetProcessHeap(), 0, codecInfo);
166 
167     return lpBuffer;
168 }
169 
170 
171 static UINT
AddWallpapersFromDirectory(UINT uCounter,HWND hwndBackgroundList,BackgroundItem * backgroundItem,PBACKGROUND_DATA pData,LPCTSTR wallpaperFilename,LPCTSTR wallpaperDirectory)172 AddWallpapersFromDirectory(UINT uCounter, HWND hwndBackgroundList, BackgroundItem *backgroundItem, PBACKGROUND_DATA pData, LPCTSTR wallpaperFilename, LPCTSTR wallpaperDirectory)
173 {
174     WIN32_FIND_DATA fd;
175     HANDLE hFind;
176     TCHAR szSearchPath[MAX_PATH];
177     LPTSTR szFileTypes = NULL;
178     TCHAR separators[] = TEXT(";");
179     TCHAR *token;
180     HRESULT hr;
181     SHFILEINFO sfi;
182     UINT i = uCounter;
183     LV_ITEM listItem;
184     HIMAGELIST himl;
185 
186     szFileTypes = GdipGetSupportedFileExtensions();
187     if (!szFileTypes)
188     {
189         return i;
190     }
191 
192     himl = ListView_GetImageList(hwndBackgroundList, LVSIL_SMALL);
193 
194     token = _tcstok(szFileTypes, separators);
195     while (token != NULL)
196     {
197         if (!PathCombine(szSearchPath, wallpaperDirectory, token))
198         {
199             HeapFree(GetProcessHeap(), 0, szFileTypes);
200             return i;
201         }
202 
203         hFind = FindFirstFile(szSearchPath, &fd);
204         while (hFind != INVALID_HANDLE_VALUE)
205         {
206             TCHAR filename[MAX_PATH];
207 
208             if (!PathCombine(filename, wallpaperDirectory, fd.cFileName))
209             {
210                 FindClose(hFind);
211                 HeapFree(GetProcessHeap(), 0, szFileTypes);
212                 return i;
213             }
214 
215             /* Don't add any hidden bitmaps. Also don't add current wallpaper once more. */
216             if (((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0) && (_tcsicmp(wallpaperFilename, filename) != 0))
217             {
218                 SHGetFileInfo(filename,
219                               0,
220                               &sfi,
221                               sizeof(sfi),
222                               SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);
223                 sfi.iIcon = ImageList_AddIcon(himl, sfi.hIcon);
224                 i++;
225 
226                 backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
227 
228                 backgroundItem->bWallpaper = TRUE;
229 
230                 hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
231                 if (FAILED(hr))
232                 {
233                     FindClose(hFind);
234                     HeapFree(GetProcessHeap(), 0, szFileTypes);
235                     return i;
236                 }
237 
238                 PathRemoveExtension(backgroundItem->szDisplayName);
239 
240                 hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), filename);
241                 if (FAILED(hr))
242                 {
243                     FindClose(hFind);
244                     HeapFree(GetProcessHeap(), 0, szFileTypes);
245                     return i;
246                 }
247 
248                 ZeroMemory(&listItem, sizeof(LV_ITEM));
249                 listItem.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
250                 listItem.pszText    = backgroundItem->szDisplayName;
251                 listItem.state      = 0;
252                 listItem.iImage     = sfi.iIcon;
253                 listItem.iItem      = pData->listViewItemCount;
254                 listItem.lParam     = pData->listViewItemCount;
255 
256                 (void)ListView_InsertItem(hwndBackgroundList, &listItem);
257 
258                 pData->listViewItemCount++;
259             }
260 
261             if (!FindNextFile(hFind, &fd))
262                 break;
263         }
264 
265         token = _tcstok(NULL, separators);
266         FindClose(hFind);
267     }
268 
269     HeapFree(GetProcessHeap(), 0, szFileTypes);
270 
271     return i;
272 }
273 
274 
275 /* Add the images in the C:\ReactOS, the wallpaper directory and the current wallpaper if any */
276 static VOID
AddListViewItems(HWND hwndDlg,PBACKGROUND_DATA pData)277 AddListViewItems(HWND hwndDlg, PBACKGROUND_DATA pData)
278 {
279     TCHAR szSearchPath[MAX_PATH];
280     LV_ITEM listItem;
281     LV_COLUMN dummy;
282     RECT clientRect;
283     HKEY regKey;
284     SHFILEINFO sfi;
285     HIMAGELIST himl;
286     TCHAR wallpaperFilename[MAX_PATH];
287     TCHAR originalWallpaper[MAX_PATH];
288     DWORD bufferSize = sizeof(wallpaperFilename);
289     TCHAR buffer[MAX_PATH];
290     DWORD varType = REG_SZ;
291     LONG result;
292     UINT i = 0;
293     BackgroundItem *backgroundItem = NULL;
294     HWND hwndBackgroundList;
295     HRESULT hr;
296     HICON hIcon;
297     INT cx, cy;
298     HINSTANCE hShell32;
299 
300     hwndBackgroundList = GetDlgItem(hwndDlg, IDC_BACKGROUND_LIST);
301 
302     GetClientRect(hwndBackgroundList, &clientRect);
303 
304     cx = GetSystemMetrics(SM_CXSMICON);
305     cy = GetSystemMetrics(SM_CYSMICON);
306     himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, 0, 0);
307 
308     /* Load (None) icon */
309 #define IDI_SHELL_NO 200
310     hShell32 = GetModuleHandleW(L"shell32.dll");
311     hIcon = (HICON)LoadImageW(hShell32, MAKEINTRESOURCEW(IDI_SHELL_NO), IMAGE_ICON, cx, cy, 0);
312 #undef IDI_SHELL_NO
313 
314     ListView_SetImageList(hwndBackgroundList, himl, LVSIL_SMALL);
315 
316     /* Add a new column to the list */
317     ZeroMemory(&dummy, sizeof(LV_COLUMN));
318     dummy.mask      = LVCF_SUBITEM | LVCF_WIDTH;
319     dummy.iSubItem  = 0;
320     dummy.cx        = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL);
321     (void)ListView_InsertColumn(hwndBackgroundList, 0, &dummy);
322 
323     /* Add the "None" item */
324     backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
325     backgroundItem->bWallpaper = FALSE;
326     LoadString(hApplet,
327                IDS_NONE,
328                backgroundItem->szDisplayName,
329                sizeof(backgroundItem->szDisplayName) / sizeof(TCHAR));
330 
331     ZeroMemory(&listItem, sizeof(LV_ITEM));
332     listItem.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
333     listItem.state      = 0;
334     listItem.pszText    = backgroundItem->szDisplayName;
335     listItem.iImage     = ImageList_AddIcon(himl, hIcon);
336     listItem.iItem      = pData->listViewItemCount;
337     listItem.lParam     = pData->listViewItemCount;
338     hIcon = NULL;
339 
340     (void)ListView_InsertItem(hwndBackgroundList, &listItem);
341     ListView_SetItemState(hwndBackgroundList,
342                           pData->listViewItemCount,
343                           LVIS_SELECTED,
344                           LVIS_SELECTED);
345 
346     pData->listViewItemCount++;
347 
348     /* Add current wallpaper if any */
349     result = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE, &regKey);
350     if (result == ERROR_SUCCESS)
351     {
352         result = RegQueryValueEx(regKey, TEXT("Wallpaper"), 0, &varType, (LPBYTE)wallpaperFilename, &bufferSize);
353         if ((result == ERROR_SUCCESS) && (_tcslen(wallpaperFilename) > 0))
354         {
355             bufferSize = sizeof(originalWallpaper);
356             result = RegQueryValueEx(regKey, TEXT("OriginalWallpaper"), 0, &varType, (LPBYTE)originalWallpaper, &bufferSize);
357 
358             /* If Wallpaper and OriginalWallpaper are the same, try to retrieve ConvertedWallpaper and use it instead of Wallpaper */
359             if ((result == ERROR_SUCCESS) && (_tcslen(originalWallpaper) > 0) && (_tcsicmp(wallpaperFilename, originalWallpaper) == 0))
360             {
361                 bufferSize = sizeof(originalWallpaper);
362                 result = RegQueryValueEx(regKey, TEXT("ConvertedWallpaper"), 0, &varType, (LPBYTE)originalWallpaper, &bufferSize);
363 
364                 if ((result == ERROR_SUCCESS) && (_tcslen(originalWallpaper) > 0))
365                 {
366                     hr = StringCbCopy(wallpaperFilename, sizeof(wallpaperFilename), originalWallpaper);
367                     if (FAILED(hr))
368                     {
369                         RegCloseKey(regKey);
370                         return;
371                     }
372                 }
373             }
374 
375             /* Allow environment variables in file name */
376             if (ExpandEnvironmentStrings(wallpaperFilename, buffer, MAX_PATH))
377             {
378                 hr = StringCbCopy(wallpaperFilename, sizeof(wallpaperFilename), buffer);
379                 if (FAILED(hr))
380                 {
381                     RegCloseKey(regKey);
382                     return;
383                 }
384             }
385 
386             SHGetFileInfoW(wallpaperFilename,
387                            0,
388                            &sfi,
389                            sizeof(sfi),
390                            SHGFI_ICON | SHGFI_SMALLICON |
391                            SHGFI_DISPLAYNAME);
392             sfi.iIcon = ImageList_AddIcon(himl, sfi.hIcon);
393 
394             i++;
395 
396             backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
397 
398             backgroundItem->bWallpaper = TRUE;
399 
400             hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
401             if (FAILED(hr))
402             {
403                 RegCloseKey(regKey);
404                 return;
405             }
406 
407             PathRemoveExtension(backgroundItem->szDisplayName);
408 
409             hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), wallpaperFilename);
410             if (FAILED(hr))
411             {
412                 RegCloseKey(regKey);
413                 return;
414             }
415 
416             ZeroMemory(&listItem, sizeof(LV_ITEM));
417             listItem.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
418             listItem.state      = 0;
419             listItem.pszText    = backgroundItem->szDisplayName;
420             listItem.iImage     = sfi.iIcon;
421             listItem.iItem      = pData->listViewItemCount;
422             listItem.lParam     = pData->listViewItemCount;
423 
424             (void)ListView_InsertItem(hwndBackgroundList, &listItem);
425             ListView_SetItemState(hwndBackgroundList,
426                                   pData->listViewItemCount,
427                                   LVIS_SELECTED,
428                                   LVIS_SELECTED);
429 
430             pData->listViewItemCount++;
431         }
432 
433         RegCloseKey(regKey);
434     }
435 
436     /* Add all the images in the C:\ReactOS directory. */
437     if (GetWindowsDirectory(szSearchPath, MAX_PATH))
438     {
439         i = AddWallpapersFromDirectory(i, hwndBackgroundList, backgroundItem, pData, wallpaperFilename, szSearchPath);
440     }
441 
442     /* Add all the images in the wallpaper directory. */
443     if (SHRegGetPath(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), TEXT("WallPaperDir"), szSearchPath, 0) == ERROR_SUCCESS)
444     {
445         i = AddWallpapersFromDirectory(i, hwndBackgroundList, backgroundItem, pData, wallpaperFilename, szSearchPath);
446     }
447 }
448 
449 
450 static VOID
InitBackgroundDialog(HWND hwndDlg,PBACKGROUND_DATA pData)451 InitBackgroundDialog(HWND hwndDlg, PBACKGROUND_DATA pData)
452 {
453     TCHAR szString[256];
454     HKEY regKey;
455     TCHAR szBuffer[3];
456     DWORD bufferSize = sizeof(szBuffer);
457 
458     AddListViewItems(hwndDlg, pData);
459 
460     LoadString(hApplet, IDS_CENTER, szString, sizeof(szString) / sizeof(TCHAR));
461     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_CENTER, (LPARAM)szString);
462 
463     LoadString(hApplet, IDS_STRETCH, szString, sizeof(szString) / sizeof(TCHAR));
464     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_STRETCH, (LPARAM)szString);
465 
466     LoadString(hApplet, IDS_TILE, szString, sizeof(szString) / sizeof(TCHAR));
467     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_TILE, (LPARAM)szString);
468 
469     LoadString(hApplet, IDS_FIT, szString, sizeof(szString) / sizeof(TCHAR));
470     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_FIT, (LPARAM)szString);
471 
472     LoadString(hApplet, IDS_FILL, szString, sizeof(szString) / sizeof(TCHAR));
473     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_FILL, (LPARAM)szString);
474 
475     SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_CENTER, 0);
476     pData->placementSelection = PLACEMENT_CENTER;
477 
478     /* Load the default settings from the registry */
479     if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE, &regKey) != ERROR_SUCCESS)
480     {
481         return;
482     }
483 
484     if (RegQueryValueEx(regKey, TEXT("WallpaperStyle"), 0, NULL, (LPBYTE)szBuffer, &bufferSize) == ERROR_SUCCESS)
485     {
486         if (_ttoi(szBuffer) == PLACEMENT_VALUE_CENTER)
487         {
488             SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_CENTER, 0);
489             pData->placementSelection = PLACEMENT_CENTER;
490         }
491 
492         if (_ttoi(szBuffer) == PLACEMENT_VALUE_STRETCH)
493         {
494             SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_STRETCH, 0);
495             pData->placementSelection = PLACEMENT_STRETCH;
496         }
497 
498         if (_ttoi(szBuffer) == PLACEMENT_VALUE_FIT)
499         {
500             SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_FIT, 0);
501             pData->placementSelection = PLACEMENT_FIT;
502         }
503 
504         if (_ttoi(szBuffer) == PLACEMENT_VALUE_FILL)
505         {
506             SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_FILL, 0);
507             pData->placementSelection = PLACEMENT_FILL;
508         }
509     }
510 
511     if (RegQueryValueEx(regKey, TEXT("TileWallpaper"), 0, NULL, (LPBYTE)szBuffer, &bufferSize) == ERROR_SUCCESS)
512     {
513         if (_ttoi(szBuffer) == 1)
514         {
515             SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_TILE, 0);
516             pData->placementSelection = PLACEMENT_TILE;
517         }
518     }
519 
520     RegCloseKey(regKey);
521 }
522 
523 
524 static VOID
OnColorButton(HWND hwndDlg,PBACKGROUND_DATA pData)525 OnColorButton(HWND hwndDlg, PBACKGROUND_DATA pData)
526 {
527     /* Load custom colors from Registry */
528     HKEY hKey = NULL;
529     LONG res = ERROR_SUCCESS;
530     CHOOSECOLOR cc;
531 
532     res = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Appearance"), 0, NULL,
533                          REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hKey, NULL);
534     /* Now the key is either created or opened existing, if res == ERROR_SUCCESS */
535     if (res == ERROR_SUCCESS)
536     {
537         /* Key opened */
538         DWORD dwType = REG_BINARY;
539         DWORD cbData = sizeof(pData->custom_colors);
540         res = RegQueryValueEx(hKey, TEXT("CustomColors"), NULL, &dwType,
541                               (LPBYTE)pData->custom_colors, &cbData);
542         RegCloseKey(hKey);
543         hKey = NULL;
544     }
545 
546     /* Launch ChooseColor() dialog */
547 
548     cc.lStructSize = sizeof(CHOOSECOLOR);
549     cc.hwndOwner = hwndDlg;
550     cc.hInstance = NULL;
551     cc.rgbResult = g_GlobalData.desktop_color;
552     cc.lpCustColors = pData->custom_colors;
553     cc.Flags = CC_ANYCOLOR | /* Causes the dialog box to display all available colors in the set of basic colors.  */
554                CC_FULLOPEN | /* opens dialog in full size */
555                CC_RGBINIT ;  /* init chosen color by rgbResult value */
556     cc.lCustData = 0;
557     cc.lpfnHook = NULL;
558     cc.lpTemplateName = NULL;
559     if (ChooseColor(&cc))
560     {
561         /* Save selected color to var */
562         g_GlobalData.desktop_color = cc.rgbResult;
563         pData->bClrBackgroundChanged = TRUE;
564 
565         /* Apply button will be activated */
566         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
567 
568         /* Window will be updated :) */
569         InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW), NULL, TRUE);
570 
571         /* Save custom colors to reg. To this moment key must be created already. See above */
572         res = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Appearance"), 0,
573                            KEY_SET_VALUE, &hKey);
574         if (res == ERROR_SUCCESS)
575         {
576             /* Key opened */
577             RegSetValueEx(hKey, TEXT("CustomColors"), 0, REG_BINARY,
578                           (LPBYTE)pData->custom_colors, sizeof(pData->custom_colors));
579             RegCloseKey(hKey);
580             hKey = NULL;
581         }
582     }
583 }
584 
585 
586 /*
587  * ListView_FindItem() Macro: Searches for a list-view item with the specified
588  * characteristics. Returns the index of the item if successful, or -1 otherwise
589  */
590 static BOOL
CheckListViewFilenameExists(HWND hwndList,LPCTSTR tszFileName)591 CheckListViewFilenameExists(HWND hwndList, LPCTSTR tszFileName)
592 {
593     LVFINDINFO lvfi;
594     int retVal;
595 
596     lvfi.flags = LVFI_STRING; /* Search item by EXACT string */
597     lvfi.psz   = tszFileName; /* String to search */
598 
599     /* Other items of this structure are not valid, besacuse flags are not set. */
600     retVal = ListView_FindItem(hwndList, -1, &lvfi);
601     if (retVal != -1)
602         return TRUE; /* item found! */
603 
604     return FALSE; /* item not found. */
605 }
606 
607 
608 static VOID
OnBrowseButton(HWND hwndDlg,PBACKGROUND_DATA pData)609 OnBrowseButton(HWND hwndDlg, PBACKGROUND_DATA pData)
610 {
611     OPENFILENAME ofn;
612     TCHAR filename[MAX_PATH];
613     TCHAR fileTitle[256];
614     TCHAR initialDir[MAX_PATH];
615     LPTSTR filter;
616     LPTSTR extensions;
617     BackgroundItem *backgroundItem = NULL;
618     SHFILEINFO sfi;
619     LV_ITEM listItem;
620     HWND hwndBackgroundList;
621     TCHAR *p;
622     HRESULT hr;
623     TCHAR filterdesc[MAX_PATH];
624     TCHAR *c;
625     size_t sizeRemain;
626     SIZE_T buffersize;
627     BOOL success;
628     HIMAGELIST himl;
629 
630     hwndBackgroundList = GetDlgItem(hwndDlg, IDC_BACKGROUND_LIST);
631     himl = ListView_GetImageList(hwndBackgroundList, LVSIL_SMALL);
632     SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, initialDir);
633 
634     ZeroMemory(&ofn, sizeof(OPENFILENAME));
635 
636     ofn.lStructSize = sizeof(OPENFILENAME);
637     ofn.hwndOwner = hwndDlg;
638     ofn.lpstrFile = filename;
639 
640     LoadString(hApplet, IDS_BACKGROUND_COMDLG_FILTER, filterdesc, sizeof(filterdesc) / sizeof(TCHAR));
641 
642     extensions = GdipGetSupportedFileExtensions();
643     if (!extensions)
644     {
645         return;
646     }
647 
648     buffersize = (_tcslen(extensions) * 2 + 6) * sizeof(TCHAR) + sizeof(filterdesc);
649 
650     filter = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize);
651     if (!filter)
652     {
653         HeapFree(GetProcessHeap(), 0, extensions);
654         return;
655     }
656 
657     sizeRemain = buffersize;
658     c = filter;
659 
660     if (FAILED(StringCbPrintfEx(c, sizeRemain, &c, &sizeRemain, 0, L"%ls (%ls)", filterdesc, extensions)))
661     {
662         HeapFree(GetProcessHeap(), 0, extensions);
663         HeapFree(GetProcessHeap(), 0, filter);
664         return;
665     }
666 
667     c++;
668     sizeRemain -= sizeof(*c);
669 
670     if (FAILED(StringCbPrintfEx(c, sizeRemain, &c, &sizeRemain, 0, L"%ls", extensions)))
671     {
672         HeapFree(GetProcessHeap(), 0, extensions);
673         HeapFree(GetProcessHeap(), 0, filter);
674         return;
675     }
676 
677     HeapFree(GetProcessHeap(), 0, extensions);
678 
679     /* Set lpstrFile[0] to '\0' so that GetOpenFileName does not
680      * use the contents of szFile to initialize itself */
681     ofn.lpstrFile[0] = TEXT('\0');
682     ofn.nMaxFile = MAX_PATH;
683     ofn.lpstrFilter = filter;
684     ofn.nFilterIndex = 0;
685     ofn.lpstrFileTitle = fileTitle;
686     ofn.nMaxFileTitle = 256;
687     ofn.lpstrInitialDir = initialDir;
688     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;
689 
690     success = GetOpenFileName(&ofn);
691     HeapFree(GetProcessHeap(), 0, filter);
692 
693     if (success)
694     {
695         /* Check if there is already a entry that holds this filename */
696         if (CheckListViewFilenameExists(hwndBackgroundList, ofn.lpstrFileTitle) != FALSE)
697             return;
698 
699         if (pData->listViewItemCount > (MAX_BACKGROUNDS - 1))
700             return;
701 
702         SHGetFileInfo(filename,
703                       0,
704                       &sfi,
705                       sizeof(sfi),
706                       SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);
707         sfi.iIcon = ImageList_AddIcon(himl, sfi.hIcon);
708 
709         backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
710 
711         backgroundItem->bWallpaper = TRUE;
712 
713         hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
714         if (FAILED(hr))
715             return;
716         p = _tcsrchr(backgroundItem->szDisplayName, _T('.'));
717         if (p)
718             *p = (TCHAR)0;
719         hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), filename);
720         if (FAILED(hr))
721             return;
722 
723         ZeroMemory(&listItem, sizeof(LV_ITEM));
724         listItem.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
725         listItem.state      = 0;
726         listItem.pszText    = backgroundItem->szDisplayName;
727         listItem.iImage     = sfi.iIcon;
728         listItem.iItem      = pData->listViewItemCount;
729         listItem.lParam     = pData->listViewItemCount;
730 
731         (void)ListView_InsertItem(hwndBackgroundList, &listItem);
732         ListView_SetItemState(hwndBackgroundList,
733                               pData->listViewItemCount,
734                               LVIS_SELECTED,
735                               LVIS_SELECTED);
736         SendMessage(hwndBackgroundList, WM_VSCROLL, SB_BOTTOM, 0);
737 
738         pData->listViewItemCount++;
739     }
740 }
741 
742 
743 static VOID
ListViewItemChanged(HWND hwndDlg,PBACKGROUND_DATA pData,int itemIndex)744 ListViewItemChanged(HWND hwndDlg, PBACKGROUND_DATA pData, int itemIndex)
745 {
746     BackgroundItem *backgroundItem = NULL;
747 
748     pData->backgroundSelection = itemIndex;
749     backgroundItem = &pData->backgroundItems[pData->backgroundSelection];
750 
751     if (pData->pWallpaperBitmap != NULL)
752     {
753         DibFreeImage(pData->pWallpaperBitmap);
754         pData->pWallpaperBitmap = NULL;
755     }
756 
757     if (backgroundItem->bWallpaper != FALSE)
758     {
759         pData->pWallpaperBitmap = DibLoadImage(backgroundItem->szFilename);
760 
761         if (pData->pWallpaperBitmap == NULL)
762             return;
763     }
764 
765     pData->bWallpaperChanged = TRUE;
766 
767     InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW),
768                    NULL, TRUE);
769 
770     EnableWindow(GetDlgItem(hwndDlg, IDC_PLACEMENT_COMBO),
771                  backgroundItem->bWallpaper);
772 
773     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
774 }
775 
776 
777 static VOID
DrawBackgroundPreview(LPDRAWITEMSTRUCT draw,PBACKGROUND_DATA pData)778 DrawBackgroundPreview(LPDRAWITEMSTRUCT draw, PBACKGROUND_DATA pData)
779 {
780     float scaleX;
781     float scaleY;
782     int scaledWidth;
783     int scaledHeight;
784     int posX, desX;
785     int posY, desY;
786     int fitFillScaleNum, fitFillScaleDen;
787     int fitFillWidth, fitFillHeight;
788     HBRUSH hBrush;
789     int x;
790     int y;
791     HDC hDC;
792     HGDIOBJ hOldObj;
793     RECT rcItem = {
794         MONITOR_LEFT,
795         MONITOR_TOP,
796         MONITOR_RIGHT,
797         MONITOR_BOTTOM
798     };
799 
800     hDC = CreateCompatibleDC(draw->hDC);
801     hOldObj = SelectObject(hDC, g_GlobalData.hMonitorBitmap);
802 
803     if (pData->backgroundItems[pData->backgroundSelection].bWallpaper == FALSE)
804     {
805         /* Update desktop background color image */
806         hBrush = CreateSolidBrush(g_GlobalData.desktop_color);
807         FillRect(hDC, &rcItem, hBrush);
808         DeleteObject(hBrush);
809     }
810     else
811     if (pData->pWallpaperBitmap != NULL)
812     {
813         scaleX = ((float)GetSystemMetrics(SM_CXSCREEN) - 1) / (float)MONITOR_WIDTH;
814         scaleY = ((float)GetSystemMetrics(SM_CYSCREEN) - 1) / (float)MONITOR_HEIGHT;
815 
816         scaledWidth = (int)(pData->pWallpaperBitmap->width / scaleX);
817         scaledHeight = (int)(pData->pWallpaperBitmap->height / scaleY);
818 
819         FillRect(hDC, &rcItem, GetSysColorBrush(COLOR_BACKGROUND));
820 
821         SetStretchBltMode(hDC, COLORONCOLOR);
822 
823         switch (pData->placementSelection)
824         {
825             case PLACEMENT_CENTER:
826                 posX = (MONITOR_WIDTH - scaledWidth + 1) / 2;
827                 posY = (MONITOR_HEIGHT - scaledHeight + 1) / 2;
828                 desX = 0;
829                 desY = 0;
830 
831                 if (posX < 0) { desX = -posX / 2; posX = 0; }
832                 if (posY < 0) { desY = -posY / 2; posY = 0; }
833 
834                 if (scaledWidth > MONITOR_WIDTH)
835                     scaledWidth = MONITOR_WIDTH;
836 
837                 if (scaledHeight > MONITOR_HEIGHT)
838                     scaledHeight = MONITOR_HEIGHT;
839 
840                 StretchDIBits(hDC,
841                               MONITOR_LEFT+posX,
842                               MONITOR_TOP+posY,
843                               scaledWidth,
844                               scaledHeight,
845                               desX,
846                               desY,
847                               pData->pWallpaperBitmap->width - (int)(desX * scaleX),
848                               pData->pWallpaperBitmap->height - (int)(desY * scaleY),
849                               pData->pWallpaperBitmap->bits,
850                               pData->pWallpaperBitmap->info,
851                               DIB_RGB_COLORS,
852                               SRCCOPY);
853                 break;
854 
855             case PLACEMENT_STRETCH:
856                 StretchDIBits(hDC,
857                               MONITOR_LEFT,
858                               MONITOR_TOP,
859                               MONITOR_WIDTH,
860                               MONITOR_HEIGHT,
861                               0,
862                               0,
863                               pData->pWallpaperBitmap->width,
864                               pData->pWallpaperBitmap->height,
865                               pData->pWallpaperBitmap->bits,
866                               pData->pWallpaperBitmap->info,
867                               DIB_RGB_COLORS,
868                               SRCCOPY);
869                 break;
870 
871             case PLACEMENT_TILE:
872                 for (y = 0; y < MONITOR_HEIGHT; y += scaledHeight)
873                 {
874                     for (x = 0; x < MONITOR_WIDTH; x += scaledWidth)
875                     {
876                         if ((MONITOR_WIDTH-x) >= scaledWidth)
877                             posX = scaledWidth;
878                         else
879                             posX = MONITOR_WIDTH-x;
880 
881 
882                         if ((MONITOR_HEIGHT-y) >= scaledHeight)
883                             posY = scaledHeight;
884                         else
885                             posY = MONITOR_HEIGHT-y;
886 
887                         StretchDIBits(hDC,
888                                       MONITOR_LEFT + x,
889                                       MONITOR_TOP + y,
890                                       posX,
891                                       posY,
892                                       0,
893                                       0,
894                                       pData->pWallpaperBitmap->width * posX / scaledWidth,
895                                       pData->pWallpaperBitmap->height * posY / scaledHeight,
896                                       pData->pWallpaperBitmap->bits,
897                                       pData->pWallpaperBitmap->info,
898                                       DIB_RGB_COLORS,
899                                       SRCCOPY);
900                     }
901 
902                 }
903 
904                 break;
905 
906             case PLACEMENT_FIT:
907                 if ((MONITOR_WIDTH * scaledHeight) <= (MONITOR_HEIGHT * scaledWidth))
908                 {
909                     fitFillScaleNum = MONITOR_WIDTH;
910                     fitFillScaleDen = scaledWidth;
911                 }
912                 else
913                 {
914                     fitFillScaleNum = MONITOR_HEIGHT;
915                     fitFillScaleDen = scaledHeight;
916                 }
917 
918                 fitFillWidth = MulDiv(scaledWidth, fitFillScaleNum, fitFillScaleDen);
919                 fitFillHeight = MulDiv(scaledHeight, fitFillScaleNum, fitFillScaleDen);
920 
921                 posX = (MONITOR_WIDTH - fitFillWidth) / 2;
922                 posY = (MONITOR_HEIGHT - fitFillHeight) / 2;
923 
924                 StretchDIBits(hDC,
925                               MONITOR_LEFT + posX,
926                               MONITOR_TOP + posY,
927                               fitFillWidth,
928                               fitFillHeight,
929                               0,
930                               0,
931                               pData->pWallpaperBitmap->width,
932                               pData->pWallpaperBitmap->height,
933                               pData->pWallpaperBitmap->bits,
934                               pData->pWallpaperBitmap->info,
935                               DIB_RGB_COLORS,
936                               SRCCOPY);
937                 break;
938 
939             case PLACEMENT_FILL:
940                 if ((MONITOR_WIDTH * scaledHeight) > (MONITOR_HEIGHT * scaledWidth))
941                 {
942                     fitFillScaleNum = MONITOR_WIDTH;
943                     fitFillScaleDen = scaledWidth;
944                 }
945                 else
946                 {
947                     fitFillScaleNum = MONITOR_HEIGHT;
948                     fitFillScaleDen = scaledHeight;
949                 }
950 
951                 fitFillWidth = MulDiv(scaledWidth, fitFillScaleNum, fitFillScaleDen);
952                 fitFillHeight = MulDiv(scaledHeight, fitFillScaleNum, fitFillScaleDen);
953 
954                 desX = (((fitFillWidth - MONITOR_WIDTH) * pData->pWallpaperBitmap->width) / (2 * fitFillWidth));
955                 desY = (((fitFillHeight - MONITOR_HEIGHT) * pData->pWallpaperBitmap->height) / (2 * fitFillHeight));
956 
957                 StretchDIBits(hDC,
958                               MONITOR_LEFT,
959                               MONITOR_TOP,
960                               MONITOR_WIDTH,
961                               MONITOR_HEIGHT,
962                               desX,
963                               desY,
964                               (MONITOR_WIDTH * pData->pWallpaperBitmap->width) / fitFillWidth,
965                               (MONITOR_HEIGHT * pData->pWallpaperBitmap->height) / fitFillHeight,
966                               pData->pWallpaperBitmap->bits,
967                               pData->pWallpaperBitmap->info,
968                               DIB_RGB_COLORS,
969                               SRCCOPY);
970                 break;
971         }
972     }
973 
974     GdiTransparentBlt(draw->hDC,
975                       draw->rcItem.left, draw->rcItem.top,
976                       draw->rcItem.right - draw->rcItem.left + 1,
977                       draw->rcItem.bottom - draw->rcItem.top + 1,
978                       hDC,
979                       0, 0,
980                       g_GlobalData.bmMonWidth, g_GlobalData.bmMonHeight,
981                       MONITOR_ALPHA);
982 
983     SelectObject(hDC, hOldObj);
984     DeleteDC(hDC);
985 }
986 
987 
988 static VOID
SetWallpaper(PBACKGROUND_DATA pData)989 SetWallpaper(PBACKGROUND_DATA pData)
990 {
991     HKEY regKey;
992     TCHAR szWallpaper[MAX_PATH];
993     GpImage *image;
994     CLSID  encoderClsid;
995     GUID guidFormat;
996     size_t length = 0;
997     GpStatus status;
998 
999     if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, szWallpaper)))
1000     {
1001         return;
1002     }
1003 
1004     if (FAILED(StringCbCat(szWallpaper, sizeof(szWallpaper), TEXT("\\Wallpaper1.bmp"))))
1005     {
1006         return;
1007     }
1008 
1009     if (RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, NULL,
1010                        REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &regKey, NULL) != ERROR_SUCCESS)
1011     {
1012         return;
1013     }
1014 
1015     if (pData->placementSelection == PLACEMENT_TILE)
1016     {
1017         RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (LPBYTE)TEXT("1"), sizeof(TCHAR) * 2);
1018         RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1019     }
1020 
1021     if (pData->placementSelection == PLACEMENT_CENTER)
1022     {
1023         RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1024         RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1025     }
1026 
1027     if (pData->placementSelection == PLACEMENT_STRETCH)
1028     {
1029         RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1030         RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (LPBYTE)TEXT("2"), sizeof(TCHAR) * 2);
1031     }
1032 
1033     if (pData->placementSelection == PLACEMENT_FIT)
1034     {
1035         RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1036         RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (LPBYTE)TEXT("6"), sizeof(TCHAR) * 2);
1037     }
1038 
1039     if (pData->placementSelection == PLACEMENT_FILL)
1040     {
1041         RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (LPBYTE)TEXT("0"), sizeof(TCHAR) * 2);
1042         RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (LPBYTE)TEXT("10"), sizeof(TCHAR) * 3);
1043     }
1044 
1045     if (pData->backgroundItems[pData->backgroundSelection].bWallpaper != FALSE)
1046     {
1047         GdipLoadImageFromFile(pData->backgroundItems[pData->backgroundSelection].szFilename, &image);
1048         if (!image)
1049         {
1050             RegCloseKey(regKey);
1051             return;
1052         }
1053 
1054         GdipGetImageRawFormat(image, &guidFormat);
1055         if (IsEqualGUID(&guidFormat, &ImageFormatBMP))
1056         {
1057             GdipDisposeImage(image);
1058             RegCloseKey(regKey);
1059             SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pData->backgroundItems[pData->backgroundSelection].szFilename, SPIF_UPDATEINIFILE);
1060             return;
1061         }
1062 
1063         if (FAILED(GdipGetEncoderClsid(L"image/bmp", &encoderClsid)))
1064         {
1065             GdipDisposeImage(image);
1066             RegCloseKey(regKey);
1067             return;
1068         }
1069 
1070         status = GdipSaveImageToFile(image, szWallpaper, &encoderClsid, NULL);
1071 
1072         GdipDisposeImage(image);
1073 
1074         if (status != Ok)
1075         {
1076             RegCloseKey(regKey);
1077             return;
1078         }
1079 
1080         if (SUCCEEDED(StringCchLength(pData->backgroundItems[pData->backgroundSelection].szFilename, MAX_PATH, &length)))
1081         {
1082             RegSetValueEx(regKey,
1083                           TEXT("ConvertedWallpaper"),
1084                           0,
1085                           REG_SZ,
1086                           (LPBYTE)pData->backgroundItems[pData->backgroundSelection].szFilename,
1087                           (DWORD)((length + 1) * sizeof(TCHAR)));
1088         }
1089 
1090         if (SUCCEEDED(StringCchLength(szWallpaper, MAX_PATH, &length)))
1091         {
1092             RegSetValueEx(regKey,
1093                           TEXT("OriginalWallpaper"),
1094                           0,
1095                           REG_SZ,
1096                           (LPBYTE)szWallpaper,
1097                           (DWORD)((length + 1) * sizeof(TCHAR)));
1098         }
1099 
1100         SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_UPDATEINIFILE);
1101     }
1102     else
1103     {
1104         SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*) TEXT(""), SPIF_UPDATEINIFILE);
1105     }
1106 
1107     RegCloseKey(regKey);
1108 }
1109 
1110 
1111 /* Change system color */
1112 static VOID
SetDesktopBackColor(HWND hwndDlg,PBACKGROUND_DATA pData)1113 SetDesktopBackColor(HWND hwndDlg, PBACKGROUND_DATA pData)
1114 {
1115     HKEY hKey;
1116     INT iElement = COLOR_BACKGROUND;
1117     TCHAR clText[16];
1118     BYTE red, green, blue;
1119 
1120     if (!SetSysColors(1, &iElement, &g_GlobalData.desktop_color))
1121     {
1122         /* FIXME: these error texts can need internationalization? */
1123         MessageBox(hwndDlg, TEXT("SetSysColor() failed!"),
1124             TEXT("Error!"), MB_ICONSTOP );
1125     }
1126 
1127     if (RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Colors"), 0, NULL,
1128                        REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS)
1129     {
1130         return;
1131     }
1132 
1133     red   = GetRValue(g_GlobalData.desktop_color);
1134     green = GetGValue(g_GlobalData.desktop_color);
1135     blue  = GetBValue(g_GlobalData.desktop_color);
1136 
1137     /* Format string to be set to registry */
1138     StringCbPrintf(clText, sizeof(clText), TEXT("%d %d %d"), red, green, blue);
1139     RegSetValueEx(hKey, TEXT("Background"), 0, REG_SZ, (LPBYTE)clText,
1140                   (wcslen(clText) + 1) * sizeof(TCHAR));
1141 
1142     RegCloseKey(hKey);
1143 }
1144 
1145 static VOID
OnCustomButton(HWND hwndDlg,PBACKGROUND_DATA pData)1146 OnCustomButton(HWND hwndDlg, PBACKGROUND_DATA pData)
1147 {
1148     HPROPSHEETPAGE hpsp[1] = {0};
1149     PROPSHEETHEADER psh = {sizeof(psh)};
1150     PROPSHEETPAGE psp = {sizeof(psp)};
1151 
1152     psh.dwFlags = PSH_NOAPPLYNOW;
1153     psh.hwndParent = GetParent(hwndDlg);
1154     psh.hInstance = hApplet;
1155     psh.pszCaption = MAKEINTRESOURCE(IDS_DESKTOP_ITEMS);
1156     psh.phpage = hpsp;
1157 
1158     psp.dwFlags = PSP_DEFAULT;
1159     psp.hInstance = hApplet;
1160     psp.pszTemplate = MAKEINTRESOURCE(IDD_DESKTOP_GENERAL);
1161     psp.pfnDlgProc = DesktopPageProc;
1162     psp.lParam = (LPARAM)&pData->desktopData;
1163 
1164     hpsp[0] = CreatePropertySheetPage(&psp);
1165     if (!hpsp[0])
1166         return;
1167 
1168     psh.nPages++;
1169 
1170     if (PropertySheet(&psh) > 0)
1171     {
1172         if (SaveDesktopSettings(&pData->desktopData))
1173             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1174     }
1175 }
1176 
1177 
1178 INT_PTR CALLBACK
BackgroundPageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)1179 BackgroundPageProc(HWND hwndDlg,
1180                    UINT uMsg,
1181                    WPARAM wParam,
1182                    LPARAM lParam)
1183 {
1184     PBACKGROUND_DATA pData;
1185     struct GdiplusStartupInput gdipStartup;
1186 
1187     pData = (PBACKGROUND_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1188 
1189     switch (uMsg)
1190     {
1191         case WM_INITDIALOG:
1192             pData = (PBACKGROUND_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BACKGROUND_DATA));
1193             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
1194             gdipStartup.GdiplusVersion = 1;
1195             gdipStartup.DebugEventCallback = NULL;
1196             gdipStartup.SuppressBackgroundThread = FALSE;
1197             gdipStartup.SuppressExternalCodecs = FALSE;
1198             GdiplusStartup(&pData->gdipToken, &gdipStartup, NULL);
1199             InitBackgroundDialog(hwndDlg, pData);
1200             InitDesktopSettings(&pData->desktopData);
1201             break;
1202 
1203         case WM_COMMAND:
1204             {
1205                 DWORD controlId = LOWORD(wParam);
1206                 DWORD command   = HIWORD(wParam);
1207 
1208                 switch (controlId)
1209                 {
1210                     case IDC_COLOR_BUTTON:
1211                         if (command == BN_CLICKED)
1212                             OnColorButton(hwndDlg, pData);
1213                         break;
1214 
1215                     case IDC_BROWSE_BUTTON:
1216                         if (command == BN_CLICKED)
1217                             OnBrowseButton(hwndDlg, pData);
1218                         break;
1219 
1220                     case IDC_PLACEMENT_COMBO:
1221                         if (command == CBN_SELCHANGE)
1222                         {
1223                             pData->placementSelection = (int)SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_GETCURSEL, 0, 0);
1224 
1225                             InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW), NULL, TRUE);
1226 
1227                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1228                         }
1229                         break;
1230 
1231                     case IDC_DESKTOP_CUSTOM:
1232                         if (command == BN_CLICKED)
1233                             OnCustomButton(hwndDlg, pData);
1234                         break;
1235                 }
1236             } break;
1237 
1238         case WM_DRAWITEM:
1239             {
1240                 LPDRAWITEMSTRUCT drawItem;
1241                 drawItem = (LPDRAWITEMSTRUCT)lParam;
1242 
1243                 if (drawItem->CtlID == IDC_BACKGROUND_PREVIEW)
1244                 {
1245                     DrawBackgroundPreview(drawItem, pData);
1246                 }
1247 
1248             }
1249             break;
1250 
1251         case WM_NOTIFY:
1252             {
1253                 LPNMHDR lpnm = (LPNMHDR)lParam;
1254 
1255                 switch(lpnm->code)
1256                 {
1257                     case PSN_APPLY:
1258                         if (pData->bWallpaperChanged)
1259                             SetWallpaper(pData);
1260                         if (pData->bClrBackgroundChanged)
1261                             SetDesktopBackColor(hwndDlg, pData);
1262                         if (pData->desktopData.bSettingsChanged)
1263                             SetDesktopSettings(&pData->desktopData);
1264                         SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)_T(""));
1265                         return TRUE;
1266 
1267                     case LVN_ITEMCHANGED:
1268                         {
1269                             LPNMLISTVIEW nm = (LPNMLISTVIEW)lParam;
1270 
1271                             if ((nm->uNewState & LVIS_SELECTED) == 0)
1272                                 return FALSE;
1273 
1274                             ListViewItemChanged(hwndDlg, pData, nm->iItem);
1275                         }
1276                         break;
1277                 }
1278             }
1279             break;
1280 
1281         case WM_DESTROY:
1282             if (pData->pWallpaperBitmap != NULL)
1283                 DibFreeImage(pData->pWallpaperBitmap);
1284 
1285             GdiplusShutdown(pData->gdipToken);
1286             HeapFree(GetProcessHeap(), 0, pData);
1287             break;
1288     }
1289 
1290     return FALSE;
1291 }
1292