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