[CPL] Properly set display icons of control panel applets (#1129)
[reactos.git] / dll / cpl / desk / desk.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Display Control Panel
4 * FILE: dll/cpl/desk/desk.c
5 * PURPOSE: ReactOS Display Control Panel
6 *
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 */
9
10 #include "desk.h"
11 #include <shellapi.h>
12 #include <cplext.h>
13 #include <debug.h>
14
15 #define NUM_APPLETS (1)
16
17 static LONG APIENTRY DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam);
18
19 INT_PTR CALLBACK BackgroundPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
20 INT_PTR CALLBACK ScreenSaverPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
21 INT_PTR CALLBACK AppearancePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
22 INT_PTR CALLBACK SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
23 UINT CALLBACK SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);
24
25 HINSTANCE hApplet = 0;
26 HWND hCPLWindow;
27
28 /* Applets */
29 APPLET Applets[NUM_APPLETS] =
30 {
31 {
32 IDC_DESK_ICON,
33 IDS_CPLNAME,
34 IDS_CPLDESCRIPTION,
35 DisplayApplet
36 }
37 };
38
39 HMENU
40 LoadPopupMenu(IN HINSTANCE hInstance,
41 IN LPCTSTR lpMenuName)
42 {
43 HMENU hMenu, hSubMenu = NULL;
44
45 hMenu = LoadMenu(hInstance,
46 lpMenuName);
47
48 if (hMenu != NULL)
49 {
50 hSubMenu = GetSubMenu(hMenu,
51 0);
52 if (hSubMenu != NULL &&
53 !RemoveMenu(hMenu,
54 0,
55 MF_BYPOSITION))
56 {
57 hSubMenu = NULL;
58 }
59
60 DestroyMenu(hMenu);
61 }
62
63 return hSubMenu;
64 }
65
66 static BOOL CALLBACK
67 DisplayAppletPropSheetAddPage(HPROPSHEETPAGE hpage, LPARAM lParam)
68 {
69 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam;
70 if (ppsh != NULL && ppsh->nPages < MAX_DESK_PAGES)
71 {
72 ppsh->phpage[ppsh->nPages++] = hpage;
73 return TRUE;
74 }
75
76 return FALSE;
77 }
78
79 static BOOL
80 InitPropSheetPage(PROPSHEETHEADER *ppsh, WORD idDlg, DLGPROC DlgProc, LPFNPSPCALLBACK pfnCallback)
81 {
82 HPROPSHEETPAGE hPage;
83 PROPSHEETPAGE psp;
84
85 if (ppsh->nPages < MAX_DESK_PAGES)
86 {
87 ZeroMemory(&psp, sizeof(psp));
88 psp.dwSize = sizeof(psp);
89 psp.dwFlags = PSP_DEFAULT;
90 if (pfnCallback != NULL)
91 psp.dwFlags |= PSP_USECALLBACK;
92 psp.hInstance = hApplet;
93 psp.pszTemplate = MAKEINTRESOURCE(idDlg);
94 psp.pfnDlgProc = DlgProc;
95 psp.pfnCallback = pfnCallback;
96
97 hPage = CreatePropertySheetPage(&psp);
98 if (hPage != NULL)
99 {
100 return DisplayAppletPropSheetAddPage(hPage, (LPARAM)ppsh);
101 }
102 }
103
104 return FALSE;
105 }
106
107 static const struct
108 {
109 WORD idDlg;
110 DLGPROC DlgProc;
111 LPFNPSPCALLBACK Callback;
112 LPWSTR Name;
113 } PropPages[] =
114 {
115 { IDD_BACKGROUND, BackgroundPageProc, NULL, L"Desktop" },
116 { IDD_SCREENSAVER, ScreenSaverPageProc, NULL, L"Screen Saver" },
117 { IDD_APPEARANCE, AppearancePageProc, NULL, L"Appearance" },
118 { IDD_SETTINGS, SettingsPageProc, SettingsPageCallbackProc, L"Settings" },
119 };
120
121 static int CALLBACK
122 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
123 {
124 // NOTE: This callback is needed to set large icon correctly.
125 HICON hIcon;
126 switch (uMsg)
127 {
128 case PSCB_INITIALIZED:
129 {
130 hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_DESK_ICON));
131 SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
132 break;
133 }
134 }
135 return 0;
136 }
137
138 /* Display Applet */
139 static LONG APIENTRY
140 DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam)
141 {
142 HPROPSHEETPAGE hpsp[MAX_DESK_PAGES];
143 PROPSHEETHEADER psh;
144 HPSXA hpsxa = NULL;
145 TCHAR Caption[1024];
146 UINT i;
147 LPWSTR *argv = NULL;
148 LPCWSTR pwszSelectedTab = NULL;
149 LPCWSTR pwszFile = NULL;
150 LPCWSTR pwszAction = NULL;
151
152 UNREFERENCED_PARAMETER(wParam);
153
154 hCPLWindow = hwnd;
155
156 if (uMsg == CPL_STARTWPARMSW && lParam)
157 {
158 int argc;
159 int i;
160
161 #if 0
162 argv = CommandLineToArgvW((LPCWSTR)lParam, &argc);
163 #else
164 argv = CommandLineToArgvW(GetCommandLineW(), &argc);
165 #endif
166
167 if (argv && argc)
168 {
169 for (i = 0; i<argc; i++)
170 {
171 #if 0
172 if (argv[i][0] == L'@')
173 pwszSelectedTab = &argv[i][1];
174 #else
175 if (wcsncmp(argv[i], L"desk,@", 6) == 0)
176 pwszSelectedTab = &argv[i][6];
177 #endif
178 else if (wcsncmp(argv[i], L"/Action:", 8) == 0)
179 pwszAction = &argv[i][8];
180 else if (wcsncmp(argv[i], L"/file:", 6) == 0)
181 pwszFile = &argv[i][6];
182 }
183 }
184 }
185
186 if(pwszAction && wcsncmp(pwszAction, L"ActivateMSTheme", 15) == 0)
187 {
188 ActivateThemeFile(pwszFile);
189 goto cleanup;
190 }
191
192 g_GlobalData.pwszFile = pwszFile;
193 g_GlobalData.pwszAction = pwszAction;
194 g_GlobalData.desktop_color = GetSysColor(COLOR_DESKTOP);
195
196 LoadString(hApplet, IDS_CPLNAME, Caption, sizeof(Caption) / sizeof(TCHAR));
197
198 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
199 psh.dwSize = sizeof(PROPSHEETHEADER);
200 psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE | PSH_USEICONID;
201 psh.hwndParent = hCPLWindow;
202 psh.hInstance = hApplet;
203 psh.pszIcon = MAKEINTRESOURCEW(IDC_DESK_ICON);
204 psh.pszCaption = Caption;
205 psh.nPages = 0;
206 psh.nStartPage = 0;
207 psh.phpage = hpsp;
208 psh.pfnCallback = PropSheetProc;
209
210 /* Allow shell extensions to replace the background page */
211 hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), MAX_DESK_PAGES - psh.nPages);
212
213 for (i = 0; i != sizeof(PropPages) / sizeof(PropPages[0]); i++)
214 {
215 if (pwszSelectedTab && wcsicmp(pwszSelectedTab, PropPages[i].Name) == 0)
216 psh.nStartPage = i;
217
218 /* Override the background page if requested by a shell extension */
219 if (PropPages[i].idDlg == IDD_BACKGROUND && hpsxa != NULL &&
220 SHReplaceFromPropSheetExtArray(hpsxa, CPLPAGE_DISPLAY_BACKGROUND, DisplayAppletPropSheetAddPage, (LPARAM)&psh) != 0)
221 {
222 /* The shell extension added one or more pages to replace the background page.
223 Don't create the built-in page anymore! */
224 continue;
225 }
226
227 InitPropSheetPage(&psh, PropPages[i].idDlg, PropPages[i].DlgProc, PropPages[i].Callback);
228 }
229
230 /* NOTE: Don't call SHAddFromPropSheetExtArray here because this applet only allows
231 replacing the background page but not extending the applet by more pages */
232
233 PropertySheet(&psh);
234
235 cleanup:
236 if (hpsxa != NULL)
237 SHDestroyPropSheetExtArray(hpsxa);
238
239 if (argv)
240 LocalFree(argv);
241
242 return TRUE;
243 }
244
245
246 /* Control Panel Callback */
247 LONG CALLBACK
248 CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
249 {
250 int i = (int)lParam1;
251
252 switch (uMsg)
253 {
254 case CPL_INIT:
255 return TRUE;
256
257 case CPL_GETCOUNT:
258 return NUM_APPLETS;
259
260 case CPL_INQUIRE:
261 {
262 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
263 CPlInfo->lData = 0;
264 CPlInfo->idIcon = Applets[i].idIcon;
265 CPlInfo->idName = Applets[i].idName;
266 CPlInfo->idInfo = Applets[i].idDescription;
267 }
268 break;
269
270 case CPL_DBLCLK:
271 Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2);
272 break;
273 case CPL_STARTWPARMSW:
274 return Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2);
275 }
276
277 return FALSE;
278 }
279
280 void
281 WINAPI
282 InstallScreenSaverW(
283 IN HWND hWindow,
284 IN HANDLE hInstance,
285 IN LPCWSTR pszFile,
286 IN UINT nCmdShow)
287 {
288 WCHAR pszSystemDir[MAX_PATH];
289 WCHAR pszDrive[3];
290 WCHAR pszPath[MAX_PATH];
291 WCHAR pszFilename[MAX_PATH];
292 WCHAR pszExt[MAX_PATH];
293 LPWSTR pszOutName;
294 UINT uCompressionType=FILE_COMPRESSION_NONE;
295 DWORD dwSourceSize;
296 DWORD dwTargetSize;
297 DWORD rc;
298
299 if (!pszFile)
300 {
301 DPRINT("InstallScreenSaver() null file\n");
302 SetLastError(ERROR_INVALID_PARAMETER);
303 return;
304 }
305 DPRINT("InstallScreenSaver() Installing screensaver %ls\n", pszFile);
306
307 rc = SetupGetFileCompressionInfoW(pszFile, &pszOutName, &dwSourceSize, &dwTargetSize, &uCompressionType);
308 if (ERROR_SUCCESS != rc)
309 {
310 DPRINT("InstallScreenSaver() SetupGetFileCompressionInfo failed with error 0x%lx\n", rc);
311 SetLastError(rc);
312 return;
313 }
314 if (!GetSystemDirectoryW((LPWSTR)pszSystemDir, sizeof(pszSystemDir)/sizeof(WCHAR)))
315 {
316 MyFree(pszOutName);
317 DPRINT("InstallScreenSaver() GetSystemDirectory failed with error 0x%lx\n", GetLastError());
318 return;
319 }
320 _wsplitpath(pszOutName, pszDrive, pszPath, pszFilename, pszExt);
321 MyFree(pszOutName);
322 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), L"\\");
323 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszFilename);
324 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszExt);
325 rc = SetupDecompressOrCopyFileW(pszFile, pszSystemDir, &uCompressionType);
326 DPRINT("InstallScreenSaver() Copying to %ls, compression type %d return 0x%lx\n", pszFile, uCompressionType, rc);
327 }
328
329 void
330 WINAPI
331 InstallScreenSaverA(
332 IN HWND hWindow,
333 IN HANDLE hInstance,
334 IN LPCSTR pszFile,
335 IN UINT nCmdShow)
336 {
337 LPWSTR lpwString;
338
339 if (!pszFile)
340 {
341 DPRINT("InstallScreenSaver() null file\n");
342 SetLastError(ERROR_INVALID_PARAMETER);
343 return;
344 }
345 DPRINT("InstallScreenSaver() Install from file %s\n", pszFile);
346 lpwString = pSetupMultiByteToUnicode(pszFile, 0);
347 if (!lpwString)
348 {
349 DPRINT("InstallScreenSaver() not enough memory to convert string to unicode\n");
350 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
351 return;
352 }
353 InstallScreenSaverW(hWindow, hInstance, lpwString, nCmdShow);
354 MyFree(lpwString);
355 }
356
357 BOOL WINAPI
358 DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpvReserved)
359 {
360 UNREFERENCED_PARAMETER(lpvReserved);
361
362 switch (dwReason)
363 {
364 case DLL_PROCESS_ATTACH:
365 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
366 RegisterPreviewControl(hInstDLL);
367 // case DLL_THREAD_ATTACH:
368 hApplet = hInstDLL;
369 break;
370
371 case DLL_PROCESS_DETACH:
372 UnregisterPreviewControl(hInstDLL);
373 CoUninitialize();
374 break;
375 }
376
377 return TRUE;
378 }