Re-apply fixes to CPL accidentally reverted by Magnus's reverting commit
[reactos.git] / reactos / dll / cpl / desk / background.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Display Control Panel
5 * FILE: lib/cpl/desk/background.c
6 * PURPOSE: Background property page
7 *
8 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
9 */
10
11 #include "desk.h"
12
13 #define MAX_BACKGROUNDS 100
14
15 #define PLACEMENT_CENTER 0
16 #define PLACEMENT_STRETCH 1
17 #define PLACEMENT_TILE 2
18
19 typedef struct
20 {
21 BOOL bWallpaper; /* Is this background a wallpaper */
22
23 TCHAR szFilename[MAX_PATH];
24 TCHAR szDisplayName[256];
25
26 } BackgroundItem;
27
28 BackgroundItem g_backgroundItems[MAX_BACKGROUNDS];
29
30 DIBitmap *g_pWallpaperBitmap = NULL;
31
32 int g_placementSelection = 0;
33 int g_backgroundSelection = 0;
34
35 int g_listViewItemCount = 0;
36
37 HWND g_hBackgroundPage = NULL;
38 HWND g_hBackgroundList = NULL;
39 HWND g_hBackgroundPreview = NULL;
40
41 HWND g_hPlacementCombo = NULL;
42 HWND g_hColorButton = NULL;
43
44 HIMAGELIST g_hShellImageList = NULL;
45
46 static HBITMAP hBitmap = NULL;
47 static int cxSource, cySource;
48
49 /* Add the images in the C:\ReactOS directory and the current wallpaper if any */
50 void AddListViewItems()
51 {
52 WIN32_FIND_DATA fd;
53 HANDLE hFind;
54 TCHAR szSearchPath[MAX_PATH];
55 TCHAR szFileTypes[MAX_PATH];
56 LV_ITEM listItem;
57 LV_COLUMN dummy;
58 RECT clientRect;
59 HKEY regKey;
60 SHFILEINFO sfi;
61 HIMAGELIST himl;
62 TCHAR wallpaperFilename[MAX_PATH];
63 DWORD bufferSize = sizeof(wallpaperFilename);
64 DWORD varType = REG_SZ;
65 LONG result;
66 UINT i = 0;
67 BackgroundItem *backgroundItem = NULL;
68 TCHAR separators[] = TEXT(";");
69 TCHAR *token;
70
71 GetClientRect(g_hBackgroundList, &clientRect);
72
73 ZeroMemory(&dummy, sizeof(LV_COLUMN));
74 dummy.mask = LVCF_SUBITEM | LVCF_WIDTH;
75 dummy.iSubItem = 0;
76 dummy.cx = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL);
77
78 (void)ListView_InsertColumn(g_hBackgroundList, 0, &dummy);
79
80 /* Add the "None" item */
81
82 backgroundItem = &g_backgroundItems[g_listViewItemCount];
83
84 backgroundItem->bWallpaper = FALSE;
85
86 LoadString(hApplet,
87 IDS_NONE,
88 backgroundItem->szDisplayName,
89 sizeof(backgroundItem->szDisplayName) / sizeof(TCHAR));
90
91 ZeroMemory(&listItem, sizeof(LV_ITEM));
92 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
93 listItem.state = LVIS_SELECTED;
94 listItem.pszText = backgroundItem->szDisplayName;
95 listItem.iImage = -1;
96 listItem.iItem = g_listViewItemCount;
97 listItem.lParam = g_listViewItemCount;
98
99 (void)ListView_InsertItem(g_hBackgroundList, &listItem);
100 ListView_SetItemState(g_hBackgroundList, g_listViewItemCount, LVIS_SELECTED, LVIS_SELECTED);
101
102 g_listViewItemCount++;
103
104 /* Add current wallpaper if any */
105
106 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
107
108 result = RegQueryValueEx(regKey, TEXT("Wallpaper"), 0, &varType, (LPBYTE)wallpaperFilename, &bufferSize);
109
110 if((result == ERROR_SUCCESS) && (_tcslen(wallpaperFilename) > 0))
111 {
112 himl = (HIMAGELIST)SHGetFileInfo(wallpaperFilename,
113 0,
114 &sfi,
115 sizeof(sfi),
116 SHGFI_SYSICONINDEX | SHGFI_SMALLICON |
117 SHGFI_DISPLAYNAME);
118
119 if(himl != NULL)
120 {
121 if(i++ == 0)
122 {
123 g_hShellImageList = himl;
124 (void)ListView_SetImageList(g_hBackgroundList, himl, LVSIL_SMALL);
125 }
126
127 backgroundItem = &g_backgroundItems[g_listViewItemCount];
128
129 backgroundItem->bWallpaper = TRUE;
130
131 _tcscpy(backgroundItem->szDisplayName, sfi.szDisplayName);
132 _tcscpy(backgroundItem->szFilename, wallpaperFilename);
133
134 ZeroMemory(&listItem, sizeof(LV_ITEM));
135 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
136 listItem.state = LVIS_SELECTED;
137 listItem.pszText = backgroundItem->szDisplayName;
138 listItem.iImage = sfi.iIcon;
139 listItem.iItem = g_listViewItemCount;
140 listItem.lParam = g_listViewItemCount;
141
142 (void)ListView_InsertItem(g_hBackgroundList, &listItem);
143 ListView_SetItemState(g_hBackgroundList, g_listViewItemCount, LVIS_SELECTED, LVIS_SELECTED);
144
145 g_listViewItemCount++;
146 }
147 }
148
149 RegCloseKey(regKey);
150
151 /* Add all the images in the C:\ReactOS directory. */
152
153 LoadString(hApplet, IDS_SUPPORTED_EXT, szFileTypes, sizeof(szFileTypes) / sizeof(TCHAR));
154
155
156 token = _tcstok ( szFileTypes, separators );
157 while ( token != NULL )
158 {
159 GetWindowsDirectory(szSearchPath, MAX_PATH);
160 _tcscat(szSearchPath, TEXT("\\"));
161 _tcscat(szSearchPath, token);
162
163 hFind = FindFirstFile(szSearchPath, &fd);
164 while(hFind != INVALID_HANDLE_VALUE)
165 {
166 /* Don't add any hidden bitmaps */
167 if((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
168 {
169 TCHAR filename[MAX_PATH];
170
171 GetWindowsDirectory(filename, MAX_PATH);
172
173 _tcscat(filename, TEXT("\\"));
174 _tcscat(filename, fd.cFileName);
175
176 himl = (HIMAGELIST)SHGetFileInfo(filename,
177 0,
178 &sfi,
179 sizeof(sfi),
180 SHGFI_SYSICONINDEX | SHGFI_SMALLICON |
181 SHGFI_DISPLAYNAME);
182
183 if(himl == NULL)
184 {
185 break;
186 }
187
188 if(i++ == 0)
189 {
190 g_hShellImageList = himl;
191 (void)ListView_SetImageList(g_hBackgroundList, himl, LVSIL_SMALL);
192 }
193
194 backgroundItem = &g_backgroundItems[g_listViewItemCount];
195
196 backgroundItem->bWallpaper = TRUE;
197
198 _tcscpy(backgroundItem->szDisplayName, sfi.szDisplayName);
199 _tcscpy(backgroundItem->szFilename, filename);
200
201 ZeroMemory(&listItem, sizeof(LV_ITEM));
202 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
203 listItem.pszText = backgroundItem->szDisplayName;
204 listItem.state = 0;
205 listItem.iImage = sfi.iIcon;
206 listItem.iItem = g_listViewItemCount;
207 listItem.lParam = g_listViewItemCount;
208
209 (void)ListView_InsertItem(g_hBackgroundList, &listItem);
210
211 g_listViewItemCount++;
212 }
213
214 if(!FindNextFile(hFind, &fd))
215 hFind = INVALID_HANDLE_VALUE;
216 }
217
218 token = _tcstok ( NULL, separators );
219 }
220
221
222 }
223
224 void InitBackgroundDialog()
225 {
226 TCHAR szString[256];
227 HKEY regKey;
228 TCHAR szBuffer[2];
229 DWORD bufferSize = sizeof(szBuffer);
230 DWORD varType = REG_SZ;
231 LONG result;
232 BITMAP bitmap;
233
234 g_hBackgroundList = GetDlgItem(g_hBackgroundPage, IDC_BACKGROUND_LIST);
235 g_hBackgroundPreview = GetDlgItem(g_hBackgroundPage, IDC_BACKGROUND_PREVIEW);
236 g_hPlacementCombo = GetDlgItem(g_hBackgroundPage, IDC_PLACEMENT_COMBO);
237 g_hColorButton = GetDlgItem(g_hBackgroundPage, IDC_COLOR_BUTTON);
238
239 AddListViewItems();
240
241 LoadString(hApplet, IDS_CENTER, szString, sizeof(szString) / sizeof(TCHAR));
242 SendMessage(g_hPlacementCombo, CB_INSERTSTRING, PLACEMENT_CENTER, (LPARAM)szString);
243
244 LoadString(hApplet, IDS_STRETCH, szString, sizeof(szString) / sizeof(TCHAR));
245 SendMessage(g_hPlacementCombo, CB_INSERTSTRING, PLACEMENT_STRETCH, (LPARAM)szString);
246
247 LoadString(hApplet, IDS_TILE, szString, sizeof(szString) / sizeof(TCHAR));
248 SendMessage(g_hPlacementCombo, CB_INSERTSTRING, PLACEMENT_TILE, (LPARAM)szString);
249
250 /* Load the default settings from the registry */
251 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
252
253 result = RegQueryValueEx(regKey, TEXT("WallpaperStyle"), 0, &varType, (LPBYTE)szBuffer, &bufferSize);
254
255 if(result == ERROR_SUCCESS)
256 {
257 if(_ttoi(szBuffer) == 0)
258 {
259 SendMessage(g_hPlacementCombo, CB_SETCURSEL, PLACEMENT_CENTER, 0);
260 g_placementSelection = PLACEMENT_CENTER;
261 }
262
263 if(_ttoi(szBuffer) == 2)
264 {
265 SendMessage(g_hPlacementCombo, CB_SETCURSEL, PLACEMENT_STRETCH, 0);
266 g_placementSelection = PLACEMENT_STRETCH;
267 }
268 }
269 else
270 {
271 SendMessage(g_hPlacementCombo, CB_SETCURSEL, PLACEMENT_CENTER, 0);
272 g_placementSelection = PLACEMENT_CENTER;
273 }
274
275 result = RegQueryValueEx(regKey, TEXT("TileWallpaper"), 0, &varType, (LPBYTE)szBuffer, &bufferSize);
276
277 if(result == ERROR_SUCCESS)
278 {
279 if(_ttoi(szBuffer) == 1)
280 {
281 SendMessage(g_hPlacementCombo, CB_SETCURSEL, PLACEMENT_TILE, 0);
282 g_placementSelection = PLACEMENT_TILE;
283 }
284 }
285
286 RegCloseKey(regKey);
287
288 hBitmap = LoadImage(hApplet, MAKEINTRESOURCE(IDC_MONITOR), IMAGE_BITMAP, 0, 0, LR_LOADTRANSPARENT);
289 if (hBitmap != NULL)
290 {
291 GetObject(hBitmap, sizeof(BITMAP), &bitmap);
292
293 cxSource = bitmap.bmWidth;
294 cySource = bitmap.bmHeight;
295 }
296 }
297
298 void OnColorButton()
299 {
300 MessageBox(NULL, TEXT("That button doesn't do anything yet"), TEXT("Whoops"), MB_OK);
301 }
302
303 BOOL CheckListBoxFilename(HWND list, TCHAR *filename)
304 {
305 UNREFERENCED_PARAMETER(filename);
306 UNREFERENCED_PARAMETER(list);
307 return FALSE;
308 }
309
310 void OnBrowseButton()
311 {
312 OPENFILENAME ofn;
313 TCHAR filename[MAX_PATH];
314 TCHAR fileTitle[256];
315 TCHAR filter[MAX_PATH];
316 BackgroundItem *backgroundItem = NULL;
317 SHFILEINFO sfi;
318 LV_ITEM listItem;
319
320 ZeroMemory(&ofn, sizeof(OPENFILENAME));
321
322 ofn.lStructSize = sizeof(OPENFILENAME);
323 ofn.hwndOwner = g_hBackgroundPage;
324 ofn.lpstrFile = filename;
325
326 LoadString(hApplet, IDS_BACKGROUND_COMDLG_FILTER, filter, sizeof(filter) / sizeof(TCHAR));
327
328 /* Set lpstrFile[0] to '\0' so that GetOpenFileName does not
329 * use the contents of szFile to initialize itself */
330 ofn.lpstrFile[0] = TEXT('\0');
331 ofn.nMaxFile = MAX_PATH;
332 ofn.lpstrFilter = filter;
333 ofn.nFilterIndex = 0;
334 ofn.lpstrFileTitle = fileTitle;
335 ofn.nMaxFileTitle = 256;
336 ofn.lpstrInitialDir = NULL;
337 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
338
339 if(GetOpenFileName(&ofn) == TRUE)
340 {
341 /* Check if there is already a entry that holds this filename */
342 if(CheckListBoxFilename(g_hBackgroundList, filename) == TRUE)
343 return;
344
345 if(g_listViewItemCount > (MAX_BACKGROUNDS - 1))
346 return;
347
348 SHGetFileInfo(filename,
349 0,
350 &sfi,
351 sizeof(sfi),
352 SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);
353
354 backgroundItem = &g_backgroundItems[g_listViewItemCount];
355
356 backgroundItem->bWallpaper = TRUE;
357
358 _tcscpy(backgroundItem->szDisplayName, sfi.szDisplayName);
359 _tcscpy(backgroundItem->szFilename, filename);
360
361 ZeroMemory(&listItem, sizeof(LV_ITEM));
362 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
363 listItem.state = 0;
364 listItem.pszText = backgroundItem->szDisplayName;
365 listItem.iImage = sfi.iIcon;
366 listItem.iItem = g_listViewItemCount;
367 listItem.lParam = g_listViewItemCount;
368
369 (void)ListView_InsertItem(g_hBackgroundList, &listItem);
370
371 g_listViewItemCount++;
372 }
373 }
374
375 void ListViewItemChanged(int itemIndex)
376 {
377 BackgroundItem *backgroundItem = NULL;
378
379 g_backgroundSelection = itemIndex;
380 backgroundItem = &g_backgroundItems[g_backgroundSelection];
381
382 if(g_pWallpaperBitmap != NULL)
383 {
384 DibFreeImage(g_pWallpaperBitmap);
385 g_pWallpaperBitmap = NULL;
386 }
387
388 if(backgroundItem->bWallpaper == TRUE)
389 {
390 g_pWallpaperBitmap = DibLoadImage(backgroundItem->szFilename);
391
392 if(g_pWallpaperBitmap == NULL)
393 {
394 return;
395 }
396 }
397
398 InvalidateRect(g_hBackgroundPreview, NULL, TRUE);
399
400 EnableWindow(g_hColorButton, (backgroundItem->bWallpaper == FALSE ? TRUE : FALSE));
401 EnableWindow(g_hPlacementCombo, backgroundItem->bWallpaper);
402
403 PropSheet_Changed(GetParent(g_hBackgroundPage), g_hBackgroundPage);
404 }
405
406 void DrawBackgroundPreview(LPDRAWITEMSTRUCT draw)
407 {
408 float scaleX;
409 float scaleY;
410 int scaledWidth;
411 int scaledHeight;
412 int posX;
413 int posY;
414
415 if(g_backgroundItems[g_backgroundSelection].bWallpaper == FALSE)
416 {
417 FillRect(draw->hDC, &draw->rcItem, GetSysColorBrush(COLOR_BACKGROUND));
418 return;
419 }
420
421 if(g_pWallpaperBitmap == NULL)
422 return;
423
424 scaleX = ((float)GetSystemMetrics(SM_CXSCREEN) - 1) / (float)draw->rcItem.right;
425 scaleY = ((float)GetSystemMetrics(SM_CYSCREEN) - 1) / (float)draw->rcItem.bottom;
426
427 scaledWidth = g_pWallpaperBitmap->width / scaleX;
428 scaledHeight = g_pWallpaperBitmap->height / scaleY;
429
430 posX = (draw->rcItem.right / 2) - (scaledWidth / 2);
431 posY = (draw->rcItem.bottom / 2) - (scaledHeight / 2);
432
433 FillRect(draw->hDC, &draw->rcItem, GetSysColorBrush(COLOR_BACKGROUND));
434
435 SetStretchBltMode(draw->hDC, COLORONCOLOR);
436
437 if(g_placementSelection == PLACEMENT_CENTER)
438 {
439 StretchDIBits(draw->hDC,
440 posX,
441 posY,
442 scaledWidth,
443 scaledHeight,
444 0,
445 0,
446 g_pWallpaperBitmap->width,
447 g_pWallpaperBitmap->height,
448 g_pWallpaperBitmap->bits,
449 g_pWallpaperBitmap->info,
450 DIB_RGB_COLORS,
451 SRCCOPY);
452 }
453
454 if(g_placementSelection == PLACEMENT_STRETCH)
455 {
456 StretchDIBits(draw->hDC,
457 0,
458 0,
459 draw->rcItem.right,
460 draw->rcItem.bottom,
461 0,
462 0,
463 g_pWallpaperBitmap->width,
464 g_pWallpaperBitmap->height,
465 g_pWallpaperBitmap->bits,
466 g_pWallpaperBitmap->info,
467 DIB_RGB_COLORS,
468 SRCCOPY);
469 }
470
471 if(g_placementSelection == PLACEMENT_TILE)
472 {
473 int x;
474 int y;
475
476 for(y = 0; y < draw->rcItem.bottom; y += scaledHeight)
477 {
478 for(x = 0; x < draw->rcItem.right; x += scaledWidth)
479 {
480 StretchDIBits(draw->hDC,
481 x,
482 y,
483 scaledWidth,
484 scaledHeight,
485 0,
486 0,
487 g_pWallpaperBitmap->width,
488 g_pWallpaperBitmap->height,
489 g_pWallpaperBitmap->bits,
490 g_pWallpaperBitmap->info,
491 DIB_RGB_COLORS,
492 SRCCOPY);
493 }
494 }
495 }
496 }
497
498 void SetWallpaper()
499 {
500 HKEY regKey;
501
502 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_ALL_ACCESS, &regKey);
503
504 if(g_placementSelection == PLACEMENT_TILE)
505 {
506 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("1"), sizeof(TCHAR) * 2);
507 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
508 }
509
510 if(g_placementSelection == PLACEMENT_CENTER)
511 {
512 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
513 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
514 }
515
516 if(g_placementSelection == PLACEMENT_STRETCH)
517 {
518 RegSetValueEx(regKey, TEXT("TileWallpaper"), 0, REG_SZ, (BYTE *)TEXT("0"), sizeof(TCHAR) * 2);
519 RegSetValueEx(regKey, TEXT("WallpaperStyle"), 0, REG_SZ, (BYTE *)TEXT("2"), sizeof(TCHAR) * 2);
520 }
521
522 RegCloseKey(regKey);
523
524 if(g_backgroundItems[g_backgroundSelection].bWallpaper == TRUE)
525 {
526 SystemParametersInfo(SPI_SETDESKWALLPAPER,
527 0,
528 g_backgroundItems[g_backgroundSelection].szFilename,
529 SPIF_UPDATEINIFILE);
530 }
531 else
532 {
533 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, TEXT(""), SPIF_UPDATEINIFILE);
534 }
535 }
536
537 INT_PTR CALLBACK BackgroundPageProc(HWND hwndDlg,
538 UINT uMsg,
539 WPARAM wParam,
540 LPARAM lParam)
541 {
542 g_hBackgroundPage = hwndDlg;
543
544 switch(uMsg)
545 {
546 case WM_INITDIALOG:
547 {
548 InitBackgroundDialog();
549 } break;
550
551 case WM_COMMAND:
552 {
553 DWORD controlId = LOWORD(wParam);
554 DWORD command = HIWORD(wParam);
555
556 switch(controlId)
557 {
558 case IDC_COLOR_BUTTON:
559 {
560 if(command == BN_CLICKED)
561 OnColorButton();
562
563 } break;
564
565 case IDC_BROWSE_BUTTON:
566 {
567 if(command == BN_CLICKED)
568 OnBrowseButton();
569
570 } break;
571
572 case IDC_PLACEMENT_COMBO:
573 {
574 if(command == CBN_SELCHANGE)
575 {
576 g_placementSelection = (int)SendMessage(g_hPlacementCombo, CB_GETCURSEL, 0, 0);
577
578 InvalidateRect(g_hBackgroundPreview, NULL, TRUE);
579
580 PropSheet_Changed(GetParent(g_hBackgroundPage), g_hBackgroundPage);
581 }
582
583 } break;
584 }
585 } break;
586
587 case WM_PAINT:
588 {
589 PAINTSTRUCT ps;
590 HDC hdc, hdcMem;
591
592 hdc = BeginPaint(hwndDlg, &ps);
593
594 hdcMem = CreateCompatibleDC(hdc);
595 SelectObject(hdcMem, hBitmap);
596
597 TransparentBlt(hdc, 98, 0, cxSource, cySource, hdcMem, 0, 0, cxSource, cySource, 0xFF80FF);
598
599 DeleteDC(hdcMem);
600 EndPaint(hwndDlg, &ps);
601
602 } break;
603
604 case WM_DRAWITEM:
605 {
606 LPDRAWITEMSTRUCT drawItem;
607 drawItem = (LPDRAWITEMSTRUCT)lParam;
608
609 if(drawItem->CtlID == IDC_BACKGROUND_PREVIEW)
610 {
611 DrawBackgroundPreview(drawItem);
612 }
613
614 } break;
615
616 case WM_NOTIFY:
617 {
618 LPNMHDR lpnm = (LPNMHDR)lParam;
619
620 switch(lpnm->code)
621 {
622 case PSN_APPLY:
623 {
624 SetWallpaper();
625
626 return TRUE;
627 } break;
628
629 case LVN_ITEMCHANGED:
630 {
631 LPNMLISTVIEW nm = (LPNMLISTVIEW)lParam;
632
633 if((nm->uNewState & LVIS_SELECTED) == 0)
634 return FALSE;
635
636 ListViewItemChanged(nm->iItem);
637
638 } break;
639
640 default:
641 break;
642 }
643
644 } break;
645
646 case WM_DESTROY:
647 {
648 if(g_pWallpaperBitmap != NULL)
649 DibFreeImage(g_pWallpaperBitmap);
650
651 DeleteObject(hBitmap);
652
653 } break;
654 }
655
656 return FALSE;
657 }
658