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
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 * Alexey Minnekhanov (minlexx@rambler.ru)
16 #define MAX_BACKGROUNDS 100
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.
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
40 /* The values in these macros are dependent on the
41 * layout of the monitor image and they must be adjusted
42 * if that image will be changed.
44 #define MONITOR_LEFT 20
46 #define MONITOR_RIGHT 140
47 #define MONITOR_BOTTOM 92
49 #define MONITOR_WIDTH (MONITOR_RIGHT-MONITOR_LEFT)
50 #define MONITOR_HEIGHT (MONITOR_BOTTOM-MONITOR_TOP)
54 BOOL bWallpaper
; /* Is this background a wallpaper */
56 TCHAR szFilename
[MAX_PATH
];
57 TCHAR szDisplayName
[256];
61 typedef struct _BACKGROUND_DATA
63 BOOL bWallpaperChanged
;
64 BOOL bClrBackgroundChanged
;
66 BackgroundItem backgroundItems
[MAX_BACKGROUNDS
];
68 PDIBITMAP pWallpaperBitmap
;
70 int placementSelection
;
71 int backgroundSelection
;
73 COLORREF custom_colors
[16];
75 int listViewItemCount
;
82 } BACKGROUND_DATA
, *PBACKGROUND_DATA
;
84 GLOBAL_DATA g_GlobalData
;
88 GdipGetEncoderClsid(PCWSTR MimeType
, CLSID
*pClsid
)
93 ImageCodecInfo
*codecInfo
;
95 if (GdipGetImageEncodersSize(&num
, &size
) != Ok
||
101 codecInfo
= HeapAlloc(GetProcessHeap(), 0, size
);
104 return E_OUTOFMEMORY
;
107 if (GdipGetImageEncoders(num
, size
, codecInfo
) != Ok
)
109 HeapFree(GetProcessHeap(), 0, codecInfo
);
113 for (i
= 0; i
< num
; i
++)
115 if (!_wcsicmp(codecInfo
[i
].MimeType
, MimeType
))
117 *pClsid
= codecInfo
[i
].Clsid
;
118 HeapFree(GetProcessHeap(), 0, codecInfo
);
123 HeapFree(GetProcessHeap(), 0, codecInfo
);
129 GdipGetSupportedFileExtensions(VOID
)
131 ImageCodecInfo
*codecInfo
;
135 LPWSTR lpBuffer
= NULL
;
137 if (GdipGetImageDecodersSize(&num
, &size
) != Ok
||
143 codecInfo
= HeapAlloc(GetProcessHeap(), 0, size
);
149 if (GdipGetImageDecoders(num
, size
, codecInfo
) != Ok
)
151 HeapFree(GetProcessHeap(), 0, codecInfo
);
156 for (i
= 0; i
< num
; ++i
)
158 size
= size
+ (UINT
)wcslen(codecInfo
[i
].FilenameExtension
) + 1;
161 size
= (size
+ 1) * sizeof(WCHAR
);
163 lpBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
166 HeapFree(GetProcessHeap(), 0, codecInfo
);
170 for (i
= 0; i
< num
; ++i
)
172 StringCbCatW(lpBuffer
, size
, codecInfo
[i
].FilenameExtension
);
175 StringCbCatW(lpBuffer
, size
, L
";");
179 HeapFree(GetProcessHeap(), 0, codecInfo
);
186 AddWallpapersFromDirectory(UINT uCounter
, HWND hwndBackgroundList
, BackgroundItem
*backgroundItem
, PBACKGROUND_DATA pData
, LPCTSTR wallpaperFilename
, LPCTSTR wallpaperDirectory
)
190 TCHAR szSearchPath
[MAX_PATH
];
191 LPTSTR szFileTypes
= NULL
;
192 TCHAR separators
[] = TEXT(";");
200 szFileTypes
= GdipGetSupportedFileExtensions();
206 token
= _tcstok(szFileTypes
, separators
);
207 while (token
!= NULL
)
209 if (!PathCombine(szSearchPath
, wallpaperDirectory
, token
))
211 HeapFree(GetProcessHeap(), 0, szFileTypes
);
215 hFind
= FindFirstFile(szSearchPath
, &fd
);
216 while (hFind
!= INVALID_HANDLE_VALUE
)
218 TCHAR filename
[MAX_PATH
];
220 if (!PathCombine(filename
, wallpaperDirectory
, fd
.cFileName
))
223 HeapFree(GetProcessHeap(), 0, szFileTypes
);
227 /* Don't add any hidden bitmaps. Also don't add current wallpaper once more. */
228 if (((fd
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
) == 0) && (_tcsicmp(wallpaperFilename
, filename
) != 0))
230 himl
= (HIMAGELIST
)SHGetFileInfo(filename
,
234 SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
|
241 (void)ListView_SetImageList(hwndBackgroundList
, himl
, LVSIL_SMALL
);
244 backgroundItem
= &pData
->backgroundItems
[pData
->listViewItemCount
];
246 backgroundItem
->bWallpaper
= TRUE
;
248 hr
= StringCbCopy(backgroundItem
->szDisplayName
, sizeof(backgroundItem
->szDisplayName
), sfi
.szDisplayName
);
252 HeapFree(GetProcessHeap(), 0, szFileTypes
);
256 PathRemoveExtension(backgroundItem
->szDisplayName
);
258 hr
= StringCbCopy(backgroundItem
->szFilename
, sizeof(backgroundItem
->szFilename
), filename
);
262 HeapFree(GetProcessHeap(), 0, szFileTypes
);
266 ZeroMemory(&listItem
, sizeof(LV_ITEM
));
267 listItem
.mask
= LVIF_TEXT
| LVIF_PARAM
| LVIF_STATE
| LVIF_IMAGE
;
268 listItem
.pszText
= backgroundItem
->szDisplayName
;
270 listItem
.iImage
= sfi
.iIcon
;
271 listItem
.iItem
= pData
->listViewItemCount
;
272 listItem
.lParam
= pData
->listViewItemCount
;
274 (void)ListView_InsertItem(hwndBackgroundList
, &listItem
);
276 pData
->listViewItemCount
++;
279 if (!FindNextFile(hFind
, &fd
))
283 token
= _tcstok(NULL
, separators
);
287 HeapFree(GetProcessHeap(), 0, szFileTypes
);
293 /* Add the images in the C:\ReactOS, the wallpaper directory and the current wallpaper if any */
295 AddListViewItems(HWND hwndDlg
, PBACKGROUND_DATA pData
)
297 TCHAR szSearchPath
[MAX_PATH
];
304 TCHAR wallpaperFilename
[MAX_PATH
];
305 TCHAR originalWallpaper
[MAX_PATH
];
306 DWORD bufferSize
= sizeof(wallpaperFilename
);
307 TCHAR buffer
[MAX_PATH
];
308 DWORD varType
= REG_SZ
;
311 BackgroundItem
*backgroundItem
= NULL
;
312 HWND hwndBackgroundList
;
315 hwndBackgroundList
= GetDlgItem(hwndDlg
, IDC_BACKGROUND_LIST
);
317 GetClientRect(hwndBackgroundList
, &clientRect
);
319 /* Add a new column to the list */
320 ZeroMemory(&dummy
, sizeof(LV_COLUMN
));
321 dummy
.mask
= LVCF_SUBITEM
| LVCF_WIDTH
;
323 dummy
.cx
= (clientRect
.right
- clientRect
.left
) - GetSystemMetrics(SM_CXVSCROLL
);
324 (void)ListView_InsertColumn(hwndBackgroundList
, 0, &dummy
);
326 /* Add the "None" item */
327 backgroundItem
= &pData
->backgroundItems
[pData
->listViewItemCount
];
328 backgroundItem
->bWallpaper
= FALSE
;
331 backgroundItem
->szDisplayName
,
332 sizeof(backgroundItem
->szDisplayName
) / sizeof(TCHAR
));
334 ZeroMemory(&listItem
, sizeof(LV_ITEM
));
335 listItem
.mask
= LVIF_TEXT
| LVIF_PARAM
| LVIF_STATE
| LVIF_IMAGE
;
337 listItem
.pszText
= backgroundItem
->szDisplayName
;
338 listItem
.iImage
= -1;
339 listItem
.iItem
= pData
->listViewItemCount
;
340 listItem
.lParam
= pData
->listViewItemCount
;
342 (void)ListView_InsertItem(hwndBackgroundList
, &listItem
);
343 ListView_SetItemState(hwndBackgroundList
,
344 pData
->listViewItemCount
,
348 pData
->listViewItemCount
++;
350 /* Add current wallpaper if any */
351 result
= RegOpenKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE
, ®Key
);
352 if (result
== ERROR_SUCCESS
)
354 result
= RegQueryValueEx(regKey
, TEXT("Wallpaper"), 0, &varType
, (LPBYTE
)wallpaperFilename
, &bufferSize
);
355 if ((result
== ERROR_SUCCESS
) && (_tcslen(wallpaperFilename
) > 0))
357 bufferSize
= sizeof(originalWallpaper
);
358 result
= RegQueryValueEx(regKey
, TEXT("OriginalWallpaper"), 0, &varType
, (LPBYTE
)originalWallpaper
, &bufferSize
);
360 /* If Wallpaper and OriginalWallpaper are the same, try to retrieve ConvertedWallpaper and use it instead of Wallpaper */
361 if ((result
== ERROR_SUCCESS
) && (_tcslen(originalWallpaper
) > 0) && (_tcsicmp(wallpaperFilename
, originalWallpaper
) == 0))
363 bufferSize
= sizeof(originalWallpaper
);
364 result
= RegQueryValueEx(regKey
, TEXT("ConvertedWallpaper"), 0, &varType
, (LPBYTE
)originalWallpaper
, &bufferSize
);
366 if ((result
== ERROR_SUCCESS
) && (_tcslen(originalWallpaper
) > 0))
368 hr
= StringCbCopy(wallpaperFilename
, sizeof(wallpaperFilename
), originalWallpaper
);
377 /* Allow environment variables in file name */
378 if (ExpandEnvironmentStrings(wallpaperFilename
, buffer
, MAX_PATH
))
380 hr
= StringCbCopy(wallpaperFilename
, sizeof(wallpaperFilename
), buffer
);
388 himl
= (HIMAGELIST
)SHGetFileInfo(wallpaperFilename
,
392 SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
|
398 (void)ListView_SetImageList(hwndBackgroundList
, himl
, LVSIL_SMALL
);
401 backgroundItem
= &pData
->backgroundItems
[pData
->listViewItemCount
];
403 backgroundItem
->bWallpaper
= TRUE
;
405 hr
= StringCbCopy(backgroundItem
->szDisplayName
, sizeof(backgroundItem
->szDisplayName
), sfi
.szDisplayName
);
412 PathRemoveExtension(backgroundItem
->szDisplayName
);
414 hr
= StringCbCopy(backgroundItem
->szFilename
, sizeof(backgroundItem
->szFilename
), wallpaperFilename
);
421 ZeroMemory(&listItem
, sizeof(LV_ITEM
));
422 listItem
.mask
= LVIF_TEXT
| LVIF_PARAM
| LVIF_STATE
| LVIF_IMAGE
;
424 listItem
.pszText
= backgroundItem
->szDisplayName
;
425 listItem
.iImage
= sfi
.iIcon
;
426 listItem
.iItem
= pData
->listViewItemCount
;
427 listItem
.lParam
= pData
->listViewItemCount
;
429 (void)ListView_InsertItem(hwndBackgroundList
, &listItem
);
430 ListView_SetItemState(hwndBackgroundList
,
431 pData
->listViewItemCount
,
435 pData
->listViewItemCount
++;
442 /* Add all the images in the C:\ReactOS directory. */
443 if (GetWindowsDirectory(szSearchPath
, MAX_PATH
))
445 i
= AddWallpapersFromDirectory(i
, hwndBackgroundList
, backgroundItem
, pData
, wallpaperFilename
, szSearchPath
);
448 /* Add all the images in the wallpaper directory. */
449 if (SHRegGetPath(HKEY_LOCAL_MACHINE
, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), TEXT("WallPaperDir"), szSearchPath
, 0) == ERROR_SUCCESS
)
451 i
= AddWallpapersFromDirectory(i
, hwndBackgroundList
, backgroundItem
, pData
, wallpaperFilename
, szSearchPath
);
457 InitBackgroundDialog(HWND hwndDlg
, PBACKGROUND_DATA pData
)
462 DWORD bufferSize
= sizeof(szBuffer
);
465 AddListViewItems(hwndDlg
, pData
);
467 LoadString(hApplet
, IDS_CENTER
, szString
, sizeof(szString
) / sizeof(TCHAR
));
468 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_INSERTSTRING
, PLACEMENT_CENTER
, (LPARAM
)szString
);
470 LoadString(hApplet
, IDS_STRETCH
, szString
, sizeof(szString
) / sizeof(TCHAR
));
471 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_INSERTSTRING
, PLACEMENT_STRETCH
, (LPARAM
)szString
);
473 LoadString(hApplet
, IDS_TILE
, szString
, sizeof(szString
) / sizeof(TCHAR
));
474 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_INSERTSTRING
, PLACEMENT_TILE
, (LPARAM
)szString
);
476 LoadString(hApplet
, IDS_FIT
, szString
, sizeof(szString
) / sizeof(TCHAR
));
477 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_INSERTSTRING
, PLACEMENT_FIT
, (LPARAM
)szString
);
479 LoadString(hApplet
, IDS_FILL
, szString
, sizeof(szString
) / sizeof(TCHAR
));
480 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_INSERTSTRING
, PLACEMENT_FILL
, (LPARAM
)szString
);
482 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_CENTER
, 0);
483 pData
->placementSelection
= PLACEMENT_CENTER
;
485 pData
->hBitmap
= (HBITMAP
) LoadImage(hApplet
, MAKEINTRESOURCE(IDC_MONITOR
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
486 if (pData
->hBitmap
!= NULL
)
488 GetObject(pData
->hBitmap
, sizeof(BITMAP
), &bitmap
);
490 pData
->cxSource
= bitmap
.bmWidth
;
491 pData
->cySource
= bitmap
.bmHeight
;
494 /* Load the default settings from the registry */
495 if (RegOpenKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE
, ®Key
) != ERROR_SUCCESS
)
500 if (RegQueryValueEx(regKey
, TEXT("WallpaperStyle"), 0, NULL
, (LPBYTE
)szBuffer
, &bufferSize
) == ERROR_SUCCESS
)
502 if (_ttoi(szBuffer
) == PLACEMENT_VALUE_CENTER
)
504 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_CENTER
, 0);
505 pData
->placementSelection
= PLACEMENT_CENTER
;
508 if (_ttoi(szBuffer
) == PLACEMENT_VALUE_STRETCH
)
510 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_STRETCH
, 0);
511 pData
->placementSelection
= PLACEMENT_STRETCH
;
514 if (_ttoi(szBuffer
) == PLACEMENT_VALUE_FIT
)
516 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_FIT
, 0);
517 pData
->placementSelection
= PLACEMENT_FIT
;
520 if (_ttoi(szBuffer
) == PLACEMENT_VALUE_FILL
)
522 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_FILL
, 0);
523 pData
->placementSelection
= PLACEMENT_FILL
;
527 if (RegQueryValueEx(regKey
, TEXT("TileWallpaper"), 0, NULL
, (LPBYTE
)szBuffer
, &bufferSize
) == ERROR_SUCCESS
)
529 if (_ttoi(szBuffer
) == 1)
531 SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_SETCURSEL
, PLACEMENT_TILE
, 0);
532 pData
->placementSelection
= PLACEMENT_TILE
;
541 OnColorButton(HWND hwndDlg
, PBACKGROUND_DATA pData
)
543 /* Load custom colors from Registry */
545 LONG res
= ERROR_SUCCESS
;
548 res
= RegCreateKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Appearance"), 0, NULL
,
549 REG_OPTION_NON_VOLATILE
, KEY_QUERY_VALUE
, NULL
, &hKey
, NULL
);
550 /* Now the key is either created or opened existing, if res == ERROR_SUCCESS */
551 if (res
== ERROR_SUCCESS
)
554 DWORD dwType
= REG_BINARY
;
555 DWORD cbData
= sizeof(pData
->custom_colors
);
556 res
= RegQueryValueEx(hKey
, TEXT("CustomColors"), NULL
, &dwType
,
557 (LPBYTE
)pData
->custom_colors
, &cbData
);
562 /* Launch ChooseColor() dialog */
564 cc
.lStructSize
= sizeof(CHOOSECOLOR
);
565 cc
.hwndOwner
= hwndDlg
;
567 cc
.rgbResult
= g_GlobalData
.desktop_color
;
568 cc
.lpCustColors
= pData
->custom_colors
;
569 cc
.Flags
= CC_ANYCOLOR
| /* Causes the dialog box to display all available colors in the set of basic colors. */
570 CC_FULLOPEN
| /* opens dialog in full size */
571 CC_RGBINIT
; /* init chosen color by rgbResult value */
574 cc
.lpTemplateName
= NULL
;
575 if (ChooseColor(&cc
))
577 /* Save selected color to var */
578 g_GlobalData
.desktop_color
= cc
.rgbResult
;
579 pData
->bClrBackgroundChanged
= TRUE
;
581 /* Apply button will be activated */
582 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
584 /* Window will be updated :) */
585 InvalidateRect(GetDlgItem(hwndDlg
, IDC_BACKGROUND_PREVIEW
), NULL
, TRUE
);
587 /* Save custom colors to reg. To this moment key must be created already. See above */
588 res
= RegOpenKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Appearance"), 0,
589 KEY_SET_VALUE
, &hKey
);
590 if (res
== ERROR_SUCCESS
)
593 RegSetValueEx(hKey
, TEXT("CustomColors"), 0, REG_BINARY
,
594 (LPBYTE
)pData
->custom_colors
, sizeof(pData
->custom_colors
));
603 * ListView_FindItem() Macro: Searches for a list-view item with the specified
604 * characteristics. Returns the index of the item if successful, or -1 otherwise
607 CheckListViewFilenameExists(HWND hwndList
, LPCTSTR tszFileName
)
612 lvfi
.flags
= LVFI_STRING
; /* Search item by EXACT string */
613 lvfi
.psz
= tszFileName
; /* String to search */
615 /* Other items of this structure are not valid, besacuse flags are not set. */
616 retVal
= ListView_FindItem(hwndList
, -1, &lvfi
);
618 return TRUE
; /* item found! */
620 return FALSE
; /* item not found. */
625 OnBrowseButton(HWND hwndDlg
, PBACKGROUND_DATA pData
)
628 TCHAR filename
[MAX_PATH
];
629 TCHAR fileTitle
[256];
632 BackgroundItem
*backgroundItem
= NULL
;
635 HWND hwndBackgroundList
;
638 TCHAR filterdesc
[MAX_PATH
];
644 hwndBackgroundList
= GetDlgItem(hwndDlg
, IDC_BACKGROUND_LIST
);
646 ZeroMemory(&ofn
, sizeof(OPENFILENAME
));
648 ofn
.lStructSize
= sizeof(OPENFILENAME
);
649 ofn
.hwndOwner
= hwndDlg
;
650 ofn
.lpstrFile
= filename
;
652 LoadString(hApplet
, IDS_BACKGROUND_COMDLG_FILTER
, filterdesc
, sizeof(filterdesc
) / sizeof(TCHAR
));
654 extensions
= GdipGetSupportedFileExtensions();
660 buffersize
= (_tcslen(extensions
) * 2 + 6) * sizeof(TCHAR
) + sizeof(filterdesc
);
662 filter
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buffersize
);
665 HeapFree(GetProcessHeap(), 0, extensions
);
669 sizeRemain
= buffersize
;
672 if (FAILED(StringCbPrintfEx(c
, sizeRemain
, &c
, &sizeRemain
, 0, L
"%ls (%ls)", filterdesc
, extensions
)))
674 HeapFree(GetProcessHeap(), 0, extensions
);
675 HeapFree(GetProcessHeap(), 0, filter
);
680 sizeRemain
-= sizeof(*c
);
682 if (FAILED(StringCbPrintfEx(c
, sizeRemain
, &c
, &sizeRemain
, 0, L
"%ls", extensions
)))
684 HeapFree(GetProcessHeap(), 0, extensions
);
685 HeapFree(GetProcessHeap(), 0, filter
);
689 HeapFree(GetProcessHeap(), 0, extensions
);
691 /* Set lpstrFile[0] to '\0' so that GetOpenFileName does not
692 * use the contents of szFile to initialize itself */
693 ofn
.lpstrFile
[0] = TEXT('\0');
694 ofn
.nMaxFile
= MAX_PATH
;
695 ofn
.lpstrFilter
= filter
;
696 ofn
.nFilterIndex
= 0;
697 ofn
.lpstrFileTitle
= fileTitle
;
698 ofn
.nMaxFileTitle
= 256;
699 ofn
.lpstrInitialDir
= NULL
;
700 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
| OFN_HIDEREADONLY
;
702 success
= GetOpenFileName(&ofn
);
703 HeapFree(GetProcessHeap(), 0, filter
);
707 /* Check if there is already a entry that holds this filename */
708 if (CheckListViewFilenameExists(hwndBackgroundList
, ofn
.lpstrFileTitle
) != FALSE
)
711 if (pData
->listViewItemCount
> (MAX_BACKGROUNDS
- 1))
714 SHGetFileInfo(filename
,
718 SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_DISPLAYNAME
);
720 backgroundItem
= &pData
->backgroundItems
[pData
->listViewItemCount
];
722 backgroundItem
->bWallpaper
= TRUE
;
724 hr
= StringCbCopy(backgroundItem
->szDisplayName
, sizeof(backgroundItem
->szDisplayName
), sfi
.szDisplayName
);
727 p
= _tcsrchr(backgroundItem
->szDisplayName
, _T('.'));
730 hr
= StringCbCopy(backgroundItem
->szFilename
, sizeof(backgroundItem
->szFilename
), filename
);
734 ZeroMemory(&listItem
, sizeof(LV_ITEM
));
735 listItem
.mask
= LVIF_TEXT
| LVIF_PARAM
| LVIF_STATE
| LVIF_IMAGE
;
737 listItem
.pszText
= backgroundItem
->szDisplayName
;
738 listItem
.iImage
= sfi
.iIcon
;
739 listItem
.iItem
= pData
->listViewItemCount
;
740 listItem
.lParam
= pData
->listViewItemCount
;
742 (void)ListView_InsertItem(hwndBackgroundList
, &listItem
);
743 ListView_SetItemState(hwndBackgroundList
,
744 pData
->listViewItemCount
,
747 SendMessage(hwndBackgroundList
, WM_VSCROLL
, SB_BOTTOM
, 0);
749 pData
->listViewItemCount
++;
755 ListViewItemChanged(HWND hwndDlg
, PBACKGROUND_DATA pData
, int itemIndex
)
757 BackgroundItem
*backgroundItem
= NULL
;
759 pData
->backgroundSelection
= itemIndex
;
760 backgroundItem
= &pData
->backgroundItems
[pData
->backgroundSelection
];
762 if (pData
->pWallpaperBitmap
!= NULL
)
764 DibFreeImage(pData
->pWallpaperBitmap
);
765 pData
->pWallpaperBitmap
= NULL
;
768 if (backgroundItem
->bWallpaper
!= FALSE
)
770 pData
->pWallpaperBitmap
= DibLoadImage(backgroundItem
->szFilename
);
772 if (pData
->pWallpaperBitmap
== NULL
)
776 pData
->bWallpaperChanged
= TRUE
;
778 InvalidateRect(GetDlgItem(hwndDlg
, IDC_BACKGROUND_PREVIEW
),
781 EnableWindow(GetDlgItem(hwndDlg
, IDC_PLACEMENT_COMBO
),
782 backgroundItem
->bWallpaper
);
784 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
789 DrawBackgroundPreview(LPDRAWITEMSTRUCT draw
, PBACKGROUND_DATA pData
)
797 int fitFillScaleNum
, fitFillScaleDen
;
798 int fitFillWidth
, fitFillHeight
;
811 hDC
= CreateCompatibleDC(draw
->hDC
);
812 hOldObj
= SelectObject(hDC
, pData
->hBitmap
);
814 if (pData
->backgroundItems
[pData
->backgroundSelection
].bWallpaper
== FALSE
)
816 /* Update desktop background color image */
817 hBrush
= CreateSolidBrush(g_GlobalData
.desktop_color
);
818 FillRect(hDC
, &rcItem
, hBrush
);
819 DeleteObject(hBrush
);
822 if (pData
->pWallpaperBitmap
!= NULL
)
824 scaleX
= ((float)GetSystemMetrics(SM_CXSCREEN
) - 1) / (float)MONITOR_WIDTH
;
825 scaleY
= ((float)GetSystemMetrics(SM_CYSCREEN
) - 1) / (float)MONITOR_HEIGHT
;
827 scaledWidth
= (int)(pData
->pWallpaperBitmap
->width
/ scaleX
);
828 scaledHeight
= (int)(pData
->pWallpaperBitmap
->height
/ scaleY
);
830 FillRect(hDC
, &rcItem
, GetSysColorBrush(COLOR_BACKGROUND
));
832 SetStretchBltMode(hDC
, COLORONCOLOR
);
834 switch (pData
->placementSelection
)
836 case PLACEMENT_CENTER
:
837 posX
= (MONITOR_WIDTH
- scaledWidth
+ 1) / 2;
838 posY
= (MONITOR_HEIGHT
- scaledHeight
+ 1) / 2;
842 if (posX
< 0) { desX
= -posX
/ 2; posX
= 0; }
843 if (posY
< 0) { desY
= -posY
/ 2; posY
= 0; }
845 if (scaledWidth
> MONITOR_WIDTH
)
846 scaledWidth
= MONITOR_WIDTH
;
848 if (scaledHeight
> MONITOR_HEIGHT
)
849 scaledHeight
= MONITOR_HEIGHT
;
858 pData
->pWallpaperBitmap
->width
- (int)(desX
* scaleX
),
859 pData
->pWallpaperBitmap
->height
- (int)(desY
* scaleY
),
860 pData
->pWallpaperBitmap
->bits
,
861 pData
->pWallpaperBitmap
->info
,
866 case PLACEMENT_STRETCH
:
874 pData
->pWallpaperBitmap
->width
,
875 pData
->pWallpaperBitmap
->height
,
876 pData
->pWallpaperBitmap
->bits
,
877 pData
->pWallpaperBitmap
->info
,
883 for (y
= 0; y
< MONITOR_HEIGHT
; y
+= scaledHeight
)
885 for (x
= 0; x
< MONITOR_WIDTH
; x
+= scaledWidth
)
887 if ((MONITOR_WIDTH
-x
) >= scaledWidth
)
890 posX
= MONITOR_WIDTH
-x
;
893 if ((MONITOR_HEIGHT
-y
) >= scaledHeight
)
896 posY
= MONITOR_HEIGHT
-y
;
905 pData
->pWallpaperBitmap
->width
* posX
/ scaledWidth
,
906 pData
->pWallpaperBitmap
->height
* posY
/ scaledHeight
,
907 pData
->pWallpaperBitmap
->bits
,
908 pData
->pWallpaperBitmap
->info
,
918 if ((MONITOR_WIDTH
* scaledHeight
) <= (MONITOR_HEIGHT
* scaledWidth
))
920 fitFillScaleNum
= MONITOR_WIDTH
;
921 fitFillScaleDen
= scaledWidth
;
925 fitFillScaleNum
= MONITOR_HEIGHT
;
926 fitFillScaleDen
= scaledHeight
;
929 fitFillWidth
= MulDiv(scaledWidth
, fitFillScaleNum
, fitFillScaleDen
);
930 fitFillHeight
= MulDiv(scaledHeight
, fitFillScaleNum
, fitFillScaleDen
);
932 posX
= (MONITOR_WIDTH
- fitFillWidth
) / 2;
933 posY
= (MONITOR_HEIGHT
- fitFillHeight
) / 2;
942 pData
->pWallpaperBitmap
->width
,
943 pData
->pWallpaperBitmap
->height
,
944 pData
->pWallpaperBitmap
->bits
,
945 pData
->pWallpaperBitmap
->info
,
951 if ((MONITOR_WIDTH
* scaledHeight
) > (MONITOR_HEIGHT
* scaledWidth
))
953 fitFillScaleNum
= MONITOR_WIDTH
;
954 fitFillScaleDen
= scaledWidth
;
958 fitFillScaleNum
= MONITOR_HEIGHT
;
959 fitFillScaleDen
= scaledHeight
;
962 fitFillWidth
= MulDiv(scaledWidth
, fitFillScaleNum
, fitFillScaleDen
);
963 fitFillHeight
= MulDiv(scaledHeight
, fitFillScaleNum
, fitFillScaleDen
);
965 desX
= (((fitFillWidth
- MONITOR_WIDTH
) * pData
->pWallpaperBitmap
->width
) / (2 * fitFillWidth
));
966 desY
= (((fitFillHeight
- MONITOR_HEIGHT
) * pData
->pWallpaperBitmap
->height
) / (2 * fitFillHeight
));
975 (MONITOR_WIDTH
* pData
->pWallpaperBitmap
->width
) / fitFillWidth
,
976 (MONITOR_HEIGHT
* pData
->pWallpaperBitmap
->height
) / fitFillHeight
,
977 pData
->pWallpaperBitmap
->bits
,
978 pData
->pWallpaperBitmap
->info
,
985 GdiTransparentBlt(draw
->hDC
,
986 draw
->rcItem
.left
, draw
->rcItem
.top
,
987 draw
->rcItem
.right
-draw
->rcItem
.left
+1,
988 draw
->rcItem
.bottom
-draw
->rcItem
.top
+1,
991 pData
->cxSource
, pData
->cySource
,
994 SelectObject(hDC
, hOldObj
);
1000 SetWallpaper(PBACKGROUND_DATA pData
)
1003 TCHAR szWallpaper
[MAX_PATH
];
1010 if (FAILED(SHGetFolderPath(NULL
, CSIDL_LOCAL_APPDATA
| CSIDL_FLAG_CREATE
, NULL
, 0, szWallpaper
)))
1015 if (FAILED(StringCbCat(szWallpaper
, MAX_PATH
, TEXT("\\Wallpaper1.bmp"))))
1020 if (RegCreateKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Desktop"), 0, NULL
,
1021 REG_OPTION_NON_VOLATILE
, KEY_SET_VALUE
, NULL
, ®Key
, NULL
) != ERROR_SUCCESS
)
1026 if (pData
->placementSelection
== PLACEMENT_TILE
)
1028 RegSetValueEx(regKey
, TEXT("TileWallpaper"), 0, REG_SZ
, (LPBYTE
)TEXT("1"), sizeof(TCHAR
) * 2);
1029 RegSetValueEx(regKey
, TEXT("WallpaperStyle"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1032 if (pData
->placementSelection
== PLACEMENT_CENTER
)
1034 RegSetValueEx(regKey
, TEXT("TileWallpaper"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1035 RegSetValueEx(regKey
, TEXT("WallpaperStyle"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1038 if (pData
->placementSelection
== PLACEMENT_STRETCH
)
1040 RegSetValueEx(regKey
, TEXT("TileWallpaper"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1041 RegSetValueEx(regKey
, TEXT("WallpaperStyle"), 0, REG_SZ
, (LPBYTE
)TEXT("2"), sizeof(TCHAR
) * 2);
1044 if (pData
->placementSelection
== PLACEMENT_FIT
)
1046 RegSetValueEx(regKey
, TEXT("TileWallpaper"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1047 RegSetValueEx(regKey
, TEXT("WallpaperStyle"), 0, REG_SZ
, (LPBYTE
)TEXT("6"), sizeof(TCHAR
) * 2);
1050 if (pData
->placementSelection
== PLACEMENT_FILL
)
1052 RegSetValueEx(regKey
, TEXT("TileWallpaper"), 0, REG_SZ
, (LPBYTE
)TEXT("0"), sizeof(TCHAR
) * 2);
1053 RegSetValueEx(regKey
, TEXT("WallpaperStyle"), 0, REG_SZ
, (LPBYTE
)TEXT("10"), sizeof(TCHAR
) * 3);
1056 if (pData
->backgroundItems
[pData
->backgroundSelection
].bWallpaper
!= FALSE
)
1058 GdipLoadImageFromFile(pData
->backgroundItems
[pData
->backgroundSelection
].szFilename
, &image
);
1061 RegCloseKey(regKey
);
1065 GdipGetImageRawFormat(image
, &guidFormat
);
1066 if (IsEqualGUID(&guidFormat
, &ImageFormatBMP
))
1068 GdipDisposeImage(image
);
1069 RegCloseKey(regKey
);
1070 SystemParametersInfo(SPI_SETDESKWALLPAPER
, 0, pData
->backgroundItems
[pData
->backgroundSelection
].szFilename
, SPIF_UPDATEINIFILE
);
1074 if (FAILED(GdipGetEncoderClsid(L
"image/bmp", &encoderClsid
)))
1076 GdipDisposeImage(image
);
1077 RegCloseKey(regKey
);
1081 status
= GdipSaveImageToFile(image
, szWallpaper
, &encoderClsid
, NULL
);
1083 GdipDisposeImage(image
);
1087 RegCloseKey(regKey
);
1091 if (SUCCEEDED(StringCchLength(pData
->backgroundItems
[pData
->backgroundSelection
].szFilename
, MAX_PATH
, &length
)))
1093 RegSetValueEx(regKey
,
1094 TEXT("ConvertedWallpaper"),
1097 (LPBYTE
)pData
->backgroundItems
[pData
->backgroundSelection
].szFilename
,
1098 (DWORD
)((length
+ 1) * sizeof(TCHAR
)));
1101 if (SUCCEEDED(StringCchLength(szWallpaper
, MAX_PATH
, &length
)))
1103 RegSetValueEx(regKey
,
1104 TEXT("OriginalWallpaper"),
1107 (LPBYTE
)szWallpaper
,
1108 (DWORD
)((length
+ 1) * sizeof(TCHAR
)));
1111 SystemParametersInfo(SPI_SETDESKWALLPAPER
, 0, szWallpaper
, SPIF_UPDATEINIFILE
);
1115 SystemParametersInfo(SPI_SETDESKWALLPAPER
, 0, (void*) TEXT(""), SPIF_UPDATEINIFILE
);
1118 RegCloseKey(regKey
);
1122 /* Change system color */
1124 SetDesktopBackColor(HWND hwndDlg
, PBACKGROUND_DATA pData
)
1127 INT iElement
= COLOR_BACKGROUND
;
1129 BYTE red
, green
, blue
;
1131 if (!SetSysColors(1, &iElement
, &g_GlobalData
.desktop_color
))
1133 /* FIXME: these error texts can need internationalization? */
1134 MessageBox(hwndDlg
, TEXT("SetSysColor() failed!"),
1135 TEXT("Error!"), MB_ICONSTOP
);
1138 if (RegCreateKeyEx(HKEY_CURRENT_USER
, TEXT("Control Panel\\Colors"), 0, NULL
,
1139 REG_OPTION_NON_VOLATILE
, KEY_SET_VALUE
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
1144 red
= GetRValue(g_GlobalData
.desktop_color
);
1145 green
= GetGValue(g_GlobalData
.desktop_color
);
1146 blue
= GetBValue(g_GlobalData
.desktop_color
);
1148 /* Format string to be set to registry */
1149 StringCbPrintf(clText
, sizeof(clText
), TEXT("%d %d %d"), red
, green
, blue
);
1150 RegSetValueEx(hKey
, TEXT("Background"), 0, REG_SZ
, (LPBYTE
)clText
,
1151 (wcslen(clText
) + 1) * sizeof(TCHAR
));
1157 BackgroundPageProc(HWND hwndDlg
,
1162 PBACKGROUND_DATA pData
;
1163 struct GdiplusStartupInput gdipStartup
;
1165 pData
= (PBACKGROUND_DATA
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
1170 pData
= (PBACKGROUND_DATA
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BACKGROUND_DATA
));
1171 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pData
);
1172 gdipStartup
.GdiplusVersion
= 1;
1173 gdipStartup
.DebugEventCallback
= NULL
;
1174 gdipStartup
.SuppressBackgroundThread
= FALSE
;
1175 gdipStartup
.SuppressExternalCodecs
= FALSE
;
1176 GdiplusStartup(&pData
->gdipToken
, &gdipStartup
, NULL
);
1177 InitBackgroundDialog(hwndDlg
, pData
);
1182 DWORD controlId
= LOWORD(wParam
);
1183 DWORD command
= HIWORD(wParam
);
1187 case IDC_COLOR_BUTTON
:
1188 if (command
== BN_CLICKED
)
1189 OnColorButton(hwndDlg
, pData
);
1192 case IDC_BROWSE_BUTTON
:
1193 if (command
== BN_CLICKED
)
1194 OnBrowseButton(hwndDlg
, pData
);
1197 case IDC_PLACEMENT_COMBO
:
1198 if (command
== CBN_SELCHANGE
)
1200 pData
->placementSelection
= (int)SendDlgItemMessage(hwndDlg
, IDC_PLACEMENT_COMBO
, CB_GETCURSEL
, 0, 0);
1202 InvalidateRect(GetDlgItem(hwndDlg
, IDC_BACKGROUND_PREVIEW
), NULL
, TRUE
);
1204 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
1212 LPDRAWITEMSTRUCT drawItem
;
1213 drawItem
= (LPDRAWITEMSTRUCT
)lParam
;
1215 if (drawItem
->CtlID
== IDC_BACKGROUND_PREVIEW
)
1217 DrawBackgroundPreview(drawItem
, pData
);
1225 LPNMHDR lpnm
= (LPNMHDR
)lParam
;
1230 if (pData
->bWallpaperChanged
)
1231 SetWallpaper(pData
);
1232 if (pData
->bClrBackgroundChanged
)
1233 SetDesktopBackColor(hwndDlg
, pData
);
1234 SendMessage(HWND_BROADCAST
, WM_SETTINGCHANGE
, 0, (LPARAM
)_T(""));
1237 case LVN_ITEMCHANGED
:
1239 LPNMLISTVIEW nm
= (LPNMLISTVIEW
)lParam
;
1241 if ((nm
->uNewState
& LVIS_SELECTED
) == 0)
1244 ListViewItemChanged(hwndDlg
, pData
, nm
->iItem
);
1252 if (pData
->pWallpaperBitmap
!= NULL
)
1253 DibFreeImage(pData
->pWallpaperBitmap
);
1255 DeleteObject(pData
->hBitmap
);
1256 GdiplusShutdown(pData
->gdipToken
);
1257 HeapFree(GetProcessHeap(), 0, pData
);