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