* Sync up to trunk head (r64829).
[reactos.git] / dll / cpl / desk / background.c
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
15 #define MAX_BACKGROUNDS 100
16
17 #define PLACEMENT_CENTER 0
18 #define PLACEMENT_STRETCH 1
19 #define PLACEMENT_TILE 2
20
21 /* The values in these macros are dependant on the
22 * layout of the monitor image and they must be adjusted
23 * if that image will be changed.
24 */
25 #define MONITOR_LEFT 18
26 #define MONITOR_TOP 18
27 #define MONITOR_RIGHT 168
28 #define MONITOR_BOTTOM 128
29
30 #define MONITOR_WIDTH (MONITOR_RIGHT-MONITOR_LEFT)
31 #define MONITOR_HEIGHT (MONITOR_BOTTOM-MONITOR_TOP)
32
33 typedef struct
34 {
35 BOOL bWallpaper; /* Is this background a wallpaper */
36
37 TCHAR szFilename[MAX_PATH];
38 TCHAR szDisplayName[256];
39
40 } BackgroundItem;
41
42 typedef struct _DATA
43 {
44 BOOL bWallpaperChanged;
45 BOOL bClrBackgroundChanged;
46
47 BackgroundItem backgroundItems[MAX_BACKGROUNDS];
48
49 PDIBITMAP pWallpaperBitmap;
50
51 int placementSelection;
52 int backgroundSelection;
53
54 COLORREF custom_colors[16];
55
56 int listViewItemCount;
57
58 HBITMAP hBitmap;
59 int cxSource;
60 int cySource;
61 } DATA, *PDATA;
62
63 GLOBAL_DATA g_GlobalData;
64
65
66 /* Add the images in the C:\ReactOS directory and the current wallpaper if any */
67 static VOID
68 AddListViewItems(HWND hwndDlg, PDATA pData)
69 {
70 WIN32_FIND_DATA fd;
71 HANDLE hFind;
72 TCHAR szSearchPath[MAX_PATH];
73 TCHAR szFileTypes[MAX_PATH];
74 LV_ITEM listItem;
75 LV_COLUMN dummy;
76 RECT clientRect;
77 HKEY regKey;
78 SHFILEINFO sfi;
79 HIMAGELIST himl;
80 TCHAR wallpaperFilename[MAX_PATH];
81 DWORD bufferSize = sizeof(wallpaperFilename);
82 TCHAR buffer[MAX_PATH];
83 DWORD varType = REG_SZ;
84 LONG result;
85 UINT i = 0;
86 BackgroundItem *backgroundItem = NULL;
87 TCHAR separators[] = TEXT(";");
88 TCHAR *token;
89 HWND hwndBackgroundList;
90 TCHAR *p;
91 HRESULT hr;
92
93 hwndBackgroundList = GetDlgItem(hwndDlg, IDC_BACKGROUND_LIST);
94
95 GetClientRect(hwndBackgroundList, &clientRect);
96
97 /* Add a new column to the list */
98 ZeroMemory(&dummy, sizeof(LV_COLUMN));
99 dummy.mask = LVCF_SUBITEM | LVCF_WIDTH;
100 dummy.iSubItem = 0;
101 dummy.cx = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL);
102 (void)ListView_InsertColumn(hwndBackgroundList, 0, &dummy);
103
104 /* Add the "None" item */
105 backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
106 backgroundItem->bWallpaper = FALSE;
107 LoadString(hApplet,
108 IDS_NONE,
109 backgroundItem->szDisplayName,
110 sizeof(backgroundItem->szDisplayName) / sizeof(TCHAR));
111
112 ZeroMemory(&listItem, sizeof(LV_ITEM));
113 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
114 listItem.state = 0;
115 listItem.pszText = backgroundItem->szDisplayName;
116 listItem.iImage = -1;
117 listItem.iItem = pData->listViewItemCount;
118 listItem.lParam = pData->listViewItemCount;
119
120 (void)ListView_InsertItem(hwndBackgroundList, &listItem);
121 ListView_SetItemState(hwndBackgroundList,
122 pData->listViewItemCount,
123 LVIS_SELECTED,
124 LVIS_SELECTED);
125
126 pData->listViewItemCount++;
127
128 /* Add current wallpaper if any */
129 result = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
130 if (result == ERROR_SUCCESS)
131 {
132 result = RegQueryValueEx(regKey, TEXT("Wallpaper"), 0, &varType, (LPBYTE)wallpaperFilename, &bufferSize);
133 if ((result == ERROR_SUCCESS) && (_tcslen(wallpaperFilename) > 0))
134 {
135 /* Allow environment variables in file name */
136 if (ExpandEnvironmentStrings(wallpaperFilename, buffer, MAX_PATH))
137 {
138 hr = StringCbCopy(wallpaperFilename, sizeof(wallpaperFilename), buffer);
139 if (FAILED(hr))
140 {
141 RegCloseKey(regKey);
142 return;
143 }
144 }
145
146 himl = (HIMAGELIST)SHGetFileInfo(wallpaperFilename,
147 0,
148 &sfi,
149 sizeof(sfi),
150 SHGFI_SYSICONINDEX | SHGFI_SMALLICON |
151 SHGFI_DISPLAYNAME);
152
153 if (himl != NULL)
154 {
155 if (i++ == 0)
156 {
157 (void)ListView_SetImageList(hwndBackgroundList, himl, LVSIL_SMALL);
158 }
159
160 backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
161
162 backgroundItem->bWallpaper = TRUE;
163
164 hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
165 if (FAILED(hr))
166 {
167 RegCloseKey(regKey);
168 return;
169 }
170
171 p = _tcsrchr(backgroundItem->szDisplayName, _T('.'));
172 if (p)
173 *p = (TCHAR)0;
174
175 hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), wallpaperFilename);
176 if (FAILED(hr))
177 {
178 RegCloseKey(regKey);
179 return;
180 }
181
182 ZeroMemory(&listItem, sizeof(LV_ITEM));
183 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
184 listItem.state = 0;
185 listItem.pszText = backgroundItem->szDisplayName;
186 listItem.iImage = sfi.iIcon;
187 listItem.iItem = pData->listViewItemCount;
188 listItem.lParam = pData->listViewItemCount;
189
190 (void)ListView_InsertItem(hwndBackgroundList, &listItem);
191 ListView_SetItemState(hwndBackgroundList,
192 pData->listViewItemCount,
193 LVIS_SELECTED,
194 LVIS_SELECTED);
195
196 pData->listViewItemCount++;
197 }
198 }
199
200 RegCloseKey(regKey);
201 }
202
203 /* Add all the images in the C:\ReactOS directory. */
204
205 LoadString(hApplet, IDS_SUPPORTED_EXT, szFileTypes, sizeof(szFileTypes) / sizeof(TCHAR));
206
207 token = _tcstok(szFileTypes, separators);
208 while (token != NULL)
209 {
210 GetWindowsDirectory(szSearchPath, MAX_PATH);
211
212 hr = StringCbCat(szSearchPath, sizeof(szSearchPath), TEXT("\\"));
213 if (FAILED(hr))
214 return;
215 hr = StringCbCat(szSearchPath, sizeof(szSearchPath), token);
216 if (FAILED(hr))
217 return;
218
219 hFind = FindFirstFile(szSearchPath, &fd);
220 while (hFind != INVALID_HANDLE_VALUE)
221 {
222 TCHAR filename[MAX_PATH];
223
224 GetWindowsDirectory(filename, MAX_PATH);
225
226 hr = StringCbCat(filename, sizeof(filename), TEXT("\\"));
227 if (FAILED(hr))
228 {
229 FindClose(hFind);
230 return;
231 }
232 hr = StringCbCat(filename, sizeof(filename), fd.cFileName);
233 if (FAILED(hr))
234 {
235 FindClose(hFind);
236 return;
237 }
238
239 /* Don't add any hidden bitmaps. Also don't add current wallpaper once more. */
240 if (((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0) && (_tcscmp(wallpaperFilename, filename) != 0))
241 {
242 himl = (HIMAGELIST)SHGetFileInfo(filename,
243 0,
244 &sfi,
245 sizeof(sfi),
246 SHGFI_SYSICONINDEX | SHGFI_SMALLICON |
247 SHGFI_DISPLAYNAME);
248
249 if (himl == NULL)
250 break;
251
252 if (i++ == 0)
253 {
254 (void)ListView_SetImageList(hwndBackgroundList, himl, LVSIL_SMALL);
255 }
256
257 backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
258
259 backgroundItem->bWallpaper = TRUE;
260
261 hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
262 if (FAILED(hr))
263 {
264 FindClose(hFind);
265 return;
266 }
267 p = _tcsrchr(backgroundItem->szDisplayName, _T('.'));
268 if (p)
269 *p = (TCHAR)0;
270 hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), filename);
271 if (FAILED(hr))
272 {
273 FindClose(hFind);
274 return;
275 }
276
277 ZeroMemory(&listItem, sizeof(LV_ITEM));
278 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
279 listItem.pszText = backgroundItem->szDisplayName;
280 listItem.state = 0;
281 listItem.iImage = sfi.iIcon;
282 listItem.iItem = pData->listViewItemCount;
283 listItem.lParam = pData->listViewItemCount;
284
285 (void)ListView_InsertItem(hwndBackgroundList, &listItem);
286
287 pData->listViewItemCount++;
288 }
289
290 if(!FindNextFile(hFind, &fd))
291 break;
292 }
293
294 token = _tcstok(NULL, separators);
295 FindClose(hFind);
296 }
297 }
298
299
300 static VOID
301 InitBackgroundDialog(HWND hwndDlg, PDATA pData)
302 {
303 TCHAR szString[256];
304 HKEY regKey;
305 TCHAR szBuffer[2];
306 DWORD bufferSize = sizeof(szBuffer);
307 DWORD varType = REG_SZ;
308 LONG result;
309 BITMAP bitmap;
310
311 AddListViewItems(hwndDlg, pData);
312
313 LoadString(hApplet, IDS_CENTER, szString, sizeof(szString) / sizeof(TCHAR));
314 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_CENTER, (LPARAM)szString);
315
316 LoadString(hApplet, IDS_STRETCH, szString, sizeof(szString) / sizeof(TCHAR));
317 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_STRETCH, (LPARAM)szString);
318
319 LoadString(hApplet, IDS_TILE, szString, sizeof(szString) / sizeof(TCHAR));
320 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_INSERTSTRING, PLACEMENT_TILE, (LPARAM)szString);
321
322 /* Load the default settings from the registry */
323 result = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
324 if (result != ERROR_SUCCESS)
325 {
326 /* reg key open failed; maybe it does not exist? create it! */
327 DWORD dwDisposition = 0;
328 result = RegCreateKeyEx( HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, NULL, 0, KEY_ALL_ACCESS, NULL,
329 &regKey, &dwDisposition );
330 /* Now the key must be created & opened and regKey points to opened key */
331 /* On error result will not contain ERROR_SUCCESS. I don't know how to handle */
332 /* this case :( */
333 }
334
335 result = RegQueryValueEx(regKey, TEXT("WallpaperStyle"), 0, &varType, (LPBYTE)szBuffer, &bufferSize);
336 if (result == ERROR_SUCCESS)
337 {
338 if (_ttoi(szBuffer) == 0)
339 {
340 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_CENTER, 0);
341 pData->placementSelection = PLACEMENT_CENTER;
342 }
343
344 if (_ttoi(szBuffer) == 2)
345 {
346 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_STRETCH, 0);
347 pData->placementSelection = PLACEMENT_STRETCH;
348 }
349 }
350 else
351 {
352 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_CENTER, 0);
353 pData->placementSelection = PLACEMENT_CENTER;
354 }
355
356 result = RegQueryValueEx(regKey, TEXT("TileWallpaper"), 0, &varType, (LPBYTE)szBuffer, &bufferSize);
357 if (result == ERROR_SUCCESS)
358 {
359 if (_ttoi(szBuffer) == 1)
360 {
361 SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_SETCURSEL, PLACEMENT_TILE, 0);
362 pData->placementSelection = PLACEMENT_TILE;
363 }
364 }
365
366 RegCloseKey(regKey);
367
368 pData->hBitmap = (HBITMAP) LoadImage(hApplet, MAKEINTRESOURCE(IDC_MONITOR), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
369 if (pData->hBitmap != NULL)
370 {
371 GetObject(pData->hBitmap, sizeof(BITMAP), &bitmap);
372
373 pData->cxSource = bitmap.bmWidth;
374 pData->cySource = bitmap.bmHeight;
375 }
376 }
377
378
379 static VOID
380 OnColorButton(HWND hwndDlg, PDATA pData)
381 {
382 /* Load custom colors from Registry */
383 HKEY hKey = NULL;
384 LONG res = ERROR_SUCCESS;
385 CHOOSECOLOR cc;
386
387 res = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Appearance"), 0, NULL, 0,
388 KEY_ALL_ACCESS, NULL, &hKey, NULL);
389 /* Now the key is either created or opened existing, if res == ERROR_SUCCESS */
390 if (res == ERROR_SUCCESS)
391 {
392 /* Key opened */
393 DWORD dwType = REG_BINARY;
394 DWORD cbData = sizeof(pData->custom_colors);
395 res = RegQueryValueEx(hKey, TEXT("CustomColors"), NULL, &dwType,
396 (LPBYTE)pData->custom_colors, &cbData);
397 RegCloseKey(hKey);
398 hKey = NULL;
399 }
400
401 /* Launch ChooseColor() dialog */
402
403 cc.lStructSize = sizeof(CHOOSECOLOR);
404 cc.hwndOwner = hwndDlg;
405 cc.hInstance = NULL;
406 cc.rgbResult = g_GlobalData.desktop_color;
407 cc.lpCustColors = pData->custom_colors;
408 cc.Flags = CC_ANYCOLOR | /* Causes the dialog box to display all available colors in the set of basic colors. */
409 CC_FULLOPEN | /* opens dialog in full size */
410 CC_RGBINIT ; /* init chosen color by rgbResult value */
411 cc.lCustData = 0;
412 cc.lpfnHook = NULL;
413 cc.lpTemplateName = NULL;
414 if (ChooseColor(&cc))
415 {
416 /* Save selected color to var */
417 g_GlobalData.desktop_color = cc.rgbResult;
418 pData->bClrBackgroundChanged = TRUE;
419
420 /* Apply button will be activated */
421 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
422
423 /* Window will be updated :) */
424 InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW), NULL, TRUE);
425
426 /* Save custom colors to reg. To this moment key must be created already. See above */
427 res = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Appearance"), 0,
428 KEY_WRITE, &hKey);
429 if (res == ERROR_SUCCESS)
430 {
431 /* Key opened */
432 RegSetValueEx(hKey, TEXT("CustomColors"), 0, REG_BINARY,
433 (const BYTE *)pData->custom_colors, sizeof(pData->custom_colors));
434 RegCloseKey(hKey);
435 hKey = NULL;
436 }
437 }
438 }
439
440
441 /*
442 * ListView_FindItem() Macro: Searches for a list-view item with the specified
443 * characteristics. Returns the index of the item if successful, or -1 otherwise
444 */
445 static BOOL
446 CheckListViewFilenameExists(HWND hwndList, LPCTSTR tszFileName)
447 {
448 LVFINDINFO lvfi;
449 int retVal;
450
451 lvfi.flags = LVFI_STRING; /* Search item by EXACT string */
452 lvfi.psz = tszFileName; /* String to search */
453
454 /* Other items of this structure are not valid, besacuse flags are not set. */
455 retVal = ListView_FindItem(hwndList, -1, &lvfi);
456 if (retVal != -1)
457 return TRUE; /* item found! */
458
459 return FALSE; /* item not found. */
460 }
461
462
463 static VOID
464 OnBrowseButton(HWND hwndDlg, PDATA pData)
465 {
466 OPENFILENAME ofn;
467 TCHAR filename[MAX_PATH];
468 TCHAR fileTitle[256];
469 TCHAR filter[MAX_PATH];
470 BackgroundItem *backgroundItem = NULL;
471 SHFILEINFO sfi;
472 LV_ITEM listItem;
473 HWND hwndBackgroundList;
474 TCHAR *p;
475 HRESULT hr;
476
477 hwndBackgroundList = GetDlgItem(hwndDlg, IDC_BACKGROUND_LIST);
478
479 ZeroMemory(&ofn, sizeof(OPENFILENAME));
480
481 ofn.lStructSize = sizeof(OPENFILENAME);
482 ofn.hwndOwner = hwndDlg;
483 ofn.lpstrFile = filename;
484
485 LoadString(hApplet, IDS_BACKGROUND_COMDLG_FILTER, filter, sizeof(filter) / sizeof(TCHAR));
486
487 /* Set lpstrFile[0] to '\0' so that GetOpenFileName does not
488 * use the contents of szFile to initialize itself */
489 ofn.lpstrFile[0] = TEXT('\0');
490 ofn.nMaxFile = MAX_PATH;
491 ofn.lpstrFilter = filter;
492 ofn.nFilterIndex = 0;
493 ofn.lpstrFileTitle = fileTitle;
494 ofn.nMaxFileTitle = 256;
495 ofn.lpstrInitialDir = NULL;
496 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
497
498 if (GetOpenFileName(&ofn) == TRUE)
499 {
500 /* Check if there is already a entry that holds this filename */
501 if (CheckListViewFilenameExists(hwndBackgroundList, ofn.lpstrFileTitle) == TRUE)
502 return;
503
504 if (pData->listViewItemCount > (MAX_BACKGROUNDS - 1))
505 return;
506
507 SHGetFileInfo(filename,
508 0,
509 &sfi,
510 sizeof(sfi),
511 SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);
512
513 backgroundItem = &pData->backgroundItems[pData->listViewItemCount];
514
515 backgroundItem->bWallpaper = TRUE;
516
517 hr = StringCbCopy(backgroundItem->szDisplayName, sizeof(backgroundItem->szDisplayName), sfi.szDisplayName);
518 if (FAILED(hr))
519 return;
520 p = _tcsrchr(backgroundItem->szDisplayName, _T('.'));
521 if (p)
522 *p = (TCHAR)0;
523 hr = StringCbCopy(backgroundItem->szFilename, sizeof(backgroundItem->szFilename), filename);
524 if (FAILED(hr))
525 return;
526
527 ZeroMemory(&listItem, sizeof(LV_ITEM));
528 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
529 listItem.state = 0;
530 listItem.pszText = backgroundItem->szDisplayName;
531 listItem.iImage = sfi.iIcon;
532 listItem.iItem = pData->listViewItemCount;
533 listItem.lParam = pData->listViewItemCount;
534
535 (void)ListView_InsertItem(hwndBackgroundList, &listItem);
536 ListView_SetItemState(hwndBackgroundList,
537 pData->listViewItemCount,
538 LVIS_SELECTED,
539 LVIS_SELECTED);
540 SendMessage(hwndBackgroundList, WM_VSCROLL, SB_BOTTOM, 0);
541
542 pData->listViewItemCount++;
543 }
544 }
545
546
547 static VOID
548 ListViewItemChanged(HWND hwndDlg, PDATA pData, int itemIndex)
549 {
550 BackgroundItem *backgroundItem = NULL;
551
552 pData->backgroundSelection = itemIndex;
553 backgroundItem = &pData->backgroundItems[pData->backgroundSelection];
554
555 if (pData->pWallpaperBitmap != NULL)
556 {
557 DibFreeImage(pData->pWallpaperBitmap);
558 pData->pWallpaperBitmap = NULL;
559 }
560
561 if (backgroundItem->bWallpaper == TRUE)
562 {
563 pData->pWallpaperBitmap = DibLoadImage(backgroundItem->szFilename);
564
565 if (pData->pWallpaperBitmap == NULL)
566 return;
567 }
568
569 pData->bWallpaperChanged = TRUE;
570
571 InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW),
572 NULL, TRUE);
573
574 EnableWindow(GetDlgItem(hwndDlg, IDC_PLACEMENT_COMBO),
575 backgroundItem->bWallpaper);
576
577 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
578 }
579
580
581 static VOID
582 DrawBackgroundPreview(LPDRAWITEMSTRUCT draw, PDATA pData)
583 {
584 float scaleX;
585 float scaleY;
586 int scaledWidth;
587 int scaledHeight;
588 int posX, desX;
589 int posY, desY;
590 HBRUSH hBrush;
591 int x;
592 int y;
593 HDC hDC;
594 HGDIOBJ hOldObj;
595 RECT rcItem = {
596 MONITOR_LEFT,
597 MONITOR_TOP,
598 MONITOR_RIGHT,
599 MONITOR_BOTTOM
600 };
601
602 hDC = CreateCompatibleDC(draw->hDC);
603 hOldObj = SelectObject(hDC, pData->hBitmap);
604
605 if (pData->backgroundItems[pData->backgroundSelection].bWallpaper == FALSE)
606 {
607 /* Update desktop background color image */
608 hBrush = CreateSolidBrush(g_GlobalData.desktop_color);
609 FillRect(hDC, &rcItem, hBrush);
610 DeleteObject(hBrush);
611 }
612 else
613 if (pData->pWallpaperBitmap != NULL)
614 {
615 scaleX = ((float)GetSystemMetrics(SM_CXSCREEN) - 1) / (float)MONITOR_WIDTH;
616 scaleY = ((float)GetSystemMetrics(SM_CYSCREEN) - 1) / (float)MONITOR_HEIGHT;
617
618 scaledWidth = (int)(pData->pWallpaperBitmap->width / scaleX);
619 scaledHeight = (int)(pData->pWallpaperBitmap->height / scaleY);
620
621 FillRect(hDC, &rcItem, GetSysColorBrush(COLOR_BACKGROUND));
622
623 SetStretchBltMode(hDC, COLORONCOLOR);
624
625 switch (pData->placementSelection)
626 {
627 case PLACEMENT_CENTER:
628 posX = (MONITOR_WIDTH - scaledWidth + 1) / 2;
629 posY = (MONITOR_HEIGHT - scaledHeight + 1) / 2;
630 desX = 0;
631 desY = 0;
632
633 if (posX < 0) { desX = -posX / 2; posX = 0; }
634 if (posY < 0) { desY = -posY / 2; posY = 0; }
635
636 if (scaledWidth > MONITOR_WIDTH)
637 scaledWidth = MONITOR_WIDTH;
638
639 if (scaledHeight > MONITOR_HEIGHT)
640 scaledHeight = MONITOR_HEIGHT;
641
642 StretchDIBits(hDC,
643 MONITOR_LEFT+posX,
644 MONITOR_TOP+posY,
645 scaledWidth,
646 scaledHeight,
647 desX,
648 desY,
649 pData->pWallpaperBitmap->width - (int)(desX * scaleX),
650 pData->pWallpaperBitmap->height - (int)(desY * scaleY),
651 pData->pWallpaperBitmap->bits,
652 pData->pWallpaperBitmap->info,
653 DIB_RGB_COLORS,
654 SRCCOPY);
655 break;
656
657 case PLACEMENT_STRETCH:
658 StretchDIBits(hDC,
659 MONITOR_LEFT,
660 MONITOR_TOP,
661 MONITOR_WIDTH,
662 MONITOR_HEIGHT,
663 0,
664 0,
665 pData->pWallpaperBitmap->width,
666 pData->pWallpaperBitmap->height,
667 pData->pWallpaperBitmap->bits,
668 pData->pWallpaperBitmap->info,
669 DIB_RGB_COLORS,
670 SRCCOPY);
671 break;
672
673 case PLACEMENT_TILE:
674 for (y = 0; y < MONITOR_HEIGHT; y += scaledHeight)
675 {
676 for (x = 0; x < MONITOR_WIDTH; x += scaledWidth)
677 {
678 if ((MONITOR_WIDTH-x) >= scaledWidth)
679 posX = scaledWidth;
680 else
681 posX = MONITOR_WIDTH-x;
682
683
684 if ((MONITOR_HEIGHT-y) >= scaledHeight)
685 posY = scaledHeight;
686 else
687 posY = MONITOR_HEIGHT-y;
688
689 StretchDIBits(hDC,
690 MONITOR_LEFT + x,
691 MONITOR_TOP + y,
692 posX,
693 posY,
694 0,
695 0,
696 pData->pWallpaperBitmap->width * posX / scaledWidth,
697 pData->pWallpaperBitmap->height * posY / scaledHeight,
698 pData->pWallpaperBitmap->bits,
699 pData->pWallpaperBitmap->info,
700 DIB_RGB_COLORS,
701 SRCCOPY);
702 }
703
704 }
705
706 break;
707 }
708 }
709
710 GdiTransparentBlt(draw->hDC,
711 draw->rcItem.left, draw->rcItem.top,
712 draw->rcItem.right-draw->rcItem.left+1,
713 draw->rcItem.bottom-draw->rcItem.top+1,
714 hDC,
715 0, 0,
716 pData->cxSource, pData->cySource,
717 0xFF00FF);
718
719 SelectObject(hDC, hOldObj);
720 DeleteDC(hDC);
721 }
722
723
724 static VOID
725 SetWallpaper(PDATA pData)
726 {
727 HKEY regKey;
728
729 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
730
731 if (pData->placementSelection == PLACEMENT_TILE)
732 {
733 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("1"), sizeof(TCHAR) * 2);
734 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
735 }
736
737 if (pData->placementSelection == PLACEMENT_CENTER)
738 {
739 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
740 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
741 }
742
743 if (pData->placementSelection == PLACEMENT_STRETCH)
744 {
745 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
746 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("2"), sizeof(TCHAR) * 2);
747 }
748
749 RegCloseKey(regKey);
750
751 if (pData->backgroundItems[pData->backgroundSelection].bWallpaper == TRUE)
752 {
753 SystemParametersInfo(SPI_SETDESKWALLPAPER,
754 0,
755 pData->backgroundItems[pData->backgroundSelection].szFilename,
756 SPIF_UPDATEINIFILE);
757 }
758 else
759 {
760 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*) TEXT(""), SPIF_UPDATEINIFILE);
761 }
762 }
763
764
765 /* Change system color */
766 static VOID
767 SetDesktopBackColor(HWND hwndDlg, DATA *pData)
768 {
769 INT iElement = COLOR_BACKGROUND;
770 HKEY hKey;
771 LONG result;
772 TCHAR clText[16];
773 BYTE red, green, blue;
774 DWORD dwDispostion;
775
776 if( !SetSysColors( 1, &iElement, &g_GlobalData.desktop_color ) )
777 MessageBox(hwndDlg, TEXT("SetSysColor() failed!"), /* these error texts can need internationalization? */
778 TEXT("Error!"), MB_ICONSTOP );
779
780 result = RegCreateKeyEx( HKEY_CURRENT_USER, TEXT("Control Panel\\Colors"), 0, NULL, 0,
781 KEY_ALL_ACCESS, NULL, &hKey, &dwDispostion );
782 if (result != ERROR_SUCCESS)
783 {
784 red = GetRValue(g_GlobalData.desktop_color);
785 green = GetGValue(g_GlobalData.desktop_color);
786 blue = GetBValue(g_GlobalData.desktop_color);
787 /* Format string to be set to registry */
788 StringCbPrintf(clText, sizeof(clText), TEXT("%d %d %d"), red, green, blue);
789 RegSetValueEx(hKey, TEXT("Background"), 0, REG_SZ, (BYTE *)clText,
790 (lstrlen(clText) + 1) * sizeof(TCHAR));
791 RegCloseKey(hKey);
792 }
793 }
794
795 INT_PTR CALLBACK
796 BackgroundPageProc(HWND hwndDlg,
797 UINT uMsg,
798 WPARAM wParam,
799 LPARAM lParam)
800 {
801 PDATA pData;
802
803 pData = (PDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
804
805 switch (uMsg)
806 {
807 case WM_INITDIALOG:
808 pData = (DATA*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DATA));
809 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
810 InitBackgroundDialog(hwndDlg, pData);
811 break;
812
813 case WM_COMMAND:
814 {
815 DWORD controlId = LOWORD(wParam);
816 DWORD command = HIWORD(wParam);
817
818 switch (controlId)
819 {
820 case IDC_COLOR_BUTTON:
821 if (command == BN_CLICKED)
822 OnColorButton(hwndDlg, pData);
823 break;
824
825 case IDC_BROWSE_BUTTON:
826 if (command == BN_CLICKED)
827 OnBrowseButton(hwndDlg, pData);
828 break;
829
830 case IDC_PLACEMENT_COMBO:
831 if (command == CBN_SELCHANGE)
832 {
833 pData->placementSelection = (int)SendDlgItemMessage(hwndDlg, IDC_PLACEMENT_COMBO, CB_GETCURSEL, 0, 0);
834
835 InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUND_PREVIEW), NULL, TRUE);
836
837 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
838 }
839 break;
840 }
841 } break;
842
843 case WM_DRAWITEM:
844 {
845 LPDRAWITEMSTRUCT drawItem;
846 drawItem = (LPDRAWITEMSTRUCT)lParam;
847
848 if (drawItem->CtlID == IDC_BACKGROUND_PREVIEW)
849 {
850 DrawBackgroundPreview(drawItem, pData);
851 }
852
853 }
854 break;
855
856 case WM_NOTIFY:
857 {
858 LPNMHDR lpnm = (LPNMHDR)lParam;
859
860 switch(lpnm->code)
861 {
862 case PSN_APPLY:
863 if(pData->bWallpaperChanged)
864 SetWallpaper(pData);
865 if(pData->bClrBackgroundChanged)
866 SetDesktopBackColor(hwndDlg, pData);
867 SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)_T(""));
868 return TRUE;
869
870 case LVN_ITEMCHANGED:
871 {
872 LPNMLISTVIEW nm = (LPNMLISTVIEW)lParam;
873
874 if ((nm->uNewState & LVIS_SELECTED) == 0)
875 return FALSE;
876
877 ListViewItemChanged(hwndDlg, pData, nm->iItem);
878 }
879 break;
880 }
881 }
882 break;
883
884 case WM_DESTROY:
885 if (pData->pWallpaperBitmap != NULL)
886 DibFreeImage(pData->pWallpaperBitmap);
887
888 DeleteObject(pData->hBitmap);
889 HeapFree(GetProcessHeap(), 0, pData);
890 break;
891 }
892
893 return FALSE;
894 }