xref: /reactos/dll/cpl/console/console.c (revision 38f6fd9d)
1 /*
2  * PROJECT:         ReactOS Console Configuration DLL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/cpl/console/console.c
5  * PURPOSE:         Initialization
6  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 #include "console.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 INT_PTR CALLBACK OptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
16 INT_PTR CALLBACK FontProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
17 INT_PTR CALLBACK LayoutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
18 INT_PTR CALLBACK ColorsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
19 
20 HINSTANCE hApplet = NULL;
21 
22 /* Local copy of the console information */
23 PCONSOLE_STATE_INFO ConInfo = NULL;
24 /* What to do with the console information */
25 static BOOL SetConsoleInfo  = FALSE;
26 static BOOL SaveConsoleInfo = FALSE;
27 
28 static VOID
29 InitPropSheetPage(PROPSHEETPAGEW *psp,
30                   WORD idDlg,
31                   DLGPROC DlgProc)
32 {
33     ZeroMemory(psp, sizeof(*psp));
34     psp->dwSize      = sizeof(*psp);
35     psp->dwFlags     = PSP_DEFAULT;
36     psp->hInstance   = hApplet;
37     psp->pszTemplate = MAKEINTRESOURCEW(idDlg);
38     psp->pfnDlgProc  = DlgProc;
39     psp->lParam      = 0;
40 }
41 
42 static VOID
43 InitDefaultConsoleInfo(PCONSOLE_STATE_INFO pConInfo)
44 {
45     // FIXME: Also retrieve the value of REG_DWORD CurrentPage.
46     ConCfgGetDefaultSettings(pConInfo);
47 }
48 
49 static INT_PTR
50 CALLBACK
51 ApplyProc(HWND hwndDlg,
52           UINT uMsg,
53           WPARAM wParam,
54           LPARAM lParam)
55 {
56     UNREFERENCED_PARAMETER(lParam);
57 
58     switch (uMsg)
59     {
60         case WM_INITDIALOG:
61         {
62             CheckDlgButton(hwndDlg, IDC_RADIO_APPLY_CURRENT, BST_CHECKED);
63             return TRUE;
64         }
65         case WM_COMMAND:
66         {
67             if (LOWORD(wParam) == IDOK)
68             {
69                 if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_APPLY_CURRENT) == BST_CHECKED)
70                     EndDialog(hwndDlg, IDC_RADIO_APPLY_CURRENT);
71                 else
72                     EndDialog(hwndDlg, IDC_RADIO_APPLY_ALL);
73             }
74             else if (LOWORD(wParam) == IDCANCEL)
75             {
76                 EndDialog(hwndDlg, IDCANCEL);
77             }
78             break;
79         }
80         default:
81             break;
82     }
83 
84     return FALSE;
85 }
86 
87 VOID
88 ApplyConsoleInfo(HWND hwndDlg)
89 {
90     static BOOL ConsoleInfoAlreadySaved = FALSE;
91 
92     /*
93      * We already applied all the console properties (and saved if needed).
94      * Nothing more needs to be done.
95      */
96     if (ConsoleInfoAlreadySaved)
97         goto Done;
98 
99     /*
100      * If we are setting the default parameters, just save them,
101      * otherwise display the confirmation & apply dialog.
102      */
103     if (ConInfo->hWnd == NULL)
104     {
105         SetConsoleInfo  = FALSE;
106         SaveConsoleInfo = TRUE;
107     }
108     else
109     {
110         INT_PTR res = DialogBoxW(hApplet, MAKEINTRESOURCEW(IDD_APPLYOPTIONS), hwndDlg, ApplyProc);
111 
112         SetConsoleInfo  = (res != IDCANCEL);
113         SaveConsoleInfo = (res == IDC_RADIO_APPLY_ALL);
114 
115         if (!SetConsoleInfo)
116         {
117             /* Don't destroy when the user presses cancel */
118             SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
119             return;
120         }
121     }
122 
123     /*
124      * We applied all the console properties (and saved if needed).
125      * Set the flag so that if this function is called again, we won't
126      * need to redo everything again.
127      */
128     ConsoleInfoAlreadySaved = TRUE;
129 
130 Done:
131     /* Options have been applied */
132     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
133     return;
134 }
135 
136 static int CALLBACK
137 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
138 {
139     // NOTE: This callback is needed to set large icon correctly.
140     HICON hIcon;
141     switch (uMsg)
142     {
143         case PSCB_INITIALIZED:
144         {
145             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
146             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
147             break;
148         }
149     }
150     return 0;
151 }
152 
153 /* First Applet */
154 static LONG
155 APIENTRY
156 InitApplet(HANDLE hSectionOrWnd)
157 {
158     INT_PTR Result;
159     PCONSOLE_STATE_INFO pSharedInfo = NULL;
160     WCHAR szTitle[MAX_PATH + 1];
161     PROPSHEETPAGEW psp[4];
162     PROPSHEETHEADERW psh;
163     INT i = 0;
164 
165     /*
166      * Because of Windows compatibility, we need to behave the same concerning
167      * information sharing with CONSRV. For some obscure reason the designers
168      * decided to use the CPlApplet hWnd parameter as being either a handle to
169      * the applet's parent caller's window (in case we ask for displaying
170      * the global console settings), or a handle to a shared section holding
171      * a CONSOLE_STATE_INFO structure (they don't use the extra l/wParams).
172      */
173 
174     /*
175      * Try to open the shared section via the handle parameter. If we succeed,
176      * it means we were called by CONSRV for retrieving/setting parameters for
177      * a given console. If we fail, it means we are retrieving/setting default
178      * global parameters (and we were either called by CONSRV or directly by
179      * the user via the Control Panel, etc...)
180      */
181     pSharedInfo = MapViewOfFile(hSectionOrWnd, FILE_MAP_READ, 0, 0, 0);
182     if (pSharedInfo != NULL)
183     {
184         /*
185          * We succeeded. We were called by CONSRV and are retrieving
186          * parameters for a given console.
187          */
188 
189         /* Copy the shared data into our allocated buffer */
190         DPRINT1("pSharedInfo->cbSize == %lu ; sizeof(CONSOLE_STATE_INFO) == %u\n",
191                 pSharedInfo->cbSize, sizeof(CONSOLE_STATE_INFO));
192         ASSERT(pSharedInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
193 
194         /* Allocate a local buffer to hold console information */
195         ConInfo = HeapAlloc(GetProcessHeap(),
196                             HEAP_ZERO_MEMORY,
197                             pSharedInfo->cbSize);
198         if (ConInfo)
199             RtlCopyMemory(ConInfo, pSharedInfo, pSharedInfo->cbSize);
200 
201         /* Close the section */
202         UnmapViewOfFile(pSharedInfo);
203         CloseHandle(hSectionOrWnd);
204 
205         if (!ConInfo) return 0;
206     }
207     else
208     {
209         /*
210          * We failed. We are retrieving the default global parameters.
211          */
212 
213         /* Allocate a local buffer to hold console information */
214         ConInfo = HeapAlloc(GetProcessHeap(),
215                             HEAP_ZERO_MEMORY,
216                             sizeof(CONSOLE_STATE_INFO));
217         if (!ConInfo) return 0;
218 
219         /*
220          * Setting the console window handle to NULL indicates we are
221          * retrieving/setting the default console parameters.
222          */
223         ConInfo->hWnd = NULL;
224         ConInfo->ConsoleTitle[0] = UNICODE_NULL;
225 
226         /* Use defaults */
227         InitDefaultConsoleInfo(ConInfo);
228     }
229 
230     /* Initialize the font support -- additional TrueType fonts cache and current preview font */
231     InitTTFontCache();
232     RefreshFontPreview(&FontPreview, ConInfo);
233 
234     /* Initialize the property sheet structure */
235     ZeroMemory(&psh, sizeof(psh));
236     psh.dwSize = sizeof(psh);
237     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | /* PSH_USEHICON | */ PSH_USEICONID | PSH_NOAPPLYNOW | PSH_USECALLBACK;
238 
239     if (ConInfo->ConsoleTitle[0] != UNICODE_NULL)
240         StringCchPrintfW(szTitle, ARRAYSIZE(szTitle), L"\"%s\"", ConInfo->ConsoleTitle);
241     else
242         StringCchCopyW(szTitle, ARRAYSIZE(szTitle), L"ReactOS Console");
243     psh.pszCaption = szTitle;
244 
245     if (pSharedInfo != NULL)
246     {
247         /* We were started from a console window: this is our parent (or ConInfo->hWnd is NULL) */
248         psh.hwndParent = ConInfo->hWnd;
249     }
250     else
251     {
252         /* We were started in another way (--> default parameters). Caller's window is our parent. */
253         psh.hwndParent = (HWND)hSectionOrWnd;
254     }
255 
256     psh.hInstance = hApplet;
257     // psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
258     psh.pszIcon = MAKEINTRESOURCEW(IDC_CPLICON);
259     psh.nPages = ARRAYSIZE(psp);
260     psh.nStartPage = 0;
261     psh.ppsp = psp;
262     psh.pfnCallback = PropSheetProc;
263 
264     InitPropSheetPage(&psp[i++], IDD_PROPPAGEOPTIONS, OptionsProc);
265     InitPropSheetPage(&psp[i++], IDD_PROPPAGEFONT   , FontProc   );
266     InitPropSheetPage(&psp[i++], IDD_PROPPAGELAYOUT , LayoutProc );
267     InitPropSheetPage(&psp[i++], IDD_PROPPAGECOLORS , ColorsProc );
268 
269     /* Display the property sheet */
270     RegisterWinPrevClass(hApplet);
271     Result = PropertySheetW(&psh);
272     UnRegisterWinPrevClass(hApplet);
273 
274     /* Clear the font support */
275     ResetFontPreview(&FontPreview);
276     ClearTTFontCache();
277 
278     /* Apply the console settings if necessary */
279     if (SetConsoleInfo)
280     {
281         HANDLE hSection;
282 
283         /*
284          * Create a memory section to share with CONSRV, and map it.
285          */
286         hSection = CreateFileMappingW(INVALID_HANDLE_VALUE,
287                                       NULL,
288                                       PAGE_READWRITE,
289                                       0,
290                                       ConInfo->cbSize,
291                                       NULL);
292         if (!hSection)
293         {
294             DPRINT1("Error when creating file mapping, error = %d\n", GetLastError());
295             goto Quit;
296         }
297 
298         pSharedInfo = MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS, 0, 0, 0);
299         if (!pSharedInfo)
300         {
301             DPRINT1("Error when mapping view of file, error = %d\n", GetLastError());
302             CloseHandle(hSection);
303             goto Quit;
304         }
305 
306         /* Copy the console information into the section and unmap it */
307         RtlCopyMemory(pSharedInfo, ConInfo, ConInfo->cbSize);
308         UnmapViewOfFile(pSharedInfo);
309 
310         /*
311          * Signal to CONSRV that it can apply the new settings.
312          *
313          * NOTE: SetConsoleInfo set to TRUE by ApplyConsoleInfo()
314          * *only* when ConInfo->hWnd != NULL and the user did not
315          * press IDCANCEL in the confirmation dialog.
316          */
317         ASSERT(ConInfo->hWnd);
318         SendMessageW(ConInfo->hWnd, WM_SETCONSOLEINFO, (WPARAM)hSection, 0);
319 
320         /* Close the section and return */
321         CloseHandle(hSection);
322     }
323 
324     /* Save the console settings */
325     if (SaveConsoleInfo)
326     {
327         /* Default settings saved when ConInfo->hWnd == NULL */
328         ConCfgWriteUserSettings(ConInfo, ConInfo->hWnd == NULL);
329     }
330 
331 Quit:
332     /* Cleanup */
333     HeapFree(GetProcessHeap(), 0, ConInfo);
334     ConInfo = NULL;
335 
336     return (Result != -1);
337 }
338 
339 /* Control Panel Callback */
340 LONG
341 CALLBACK
342 CPlApplet(HWND hwndCPl,
343           UINT uMsg,
344           LPARAM lParam1,
345           LPARAM lParam2)
346 {
347     switch (uMsg)
348     {
349         case CPL_INIT:
350             return TRUE;
351 
352         case CPL_EXIT:
353             // TODO: Free allocated memory
354             break;
355 
356         case CPL_GETCOUNT:
357             return 1;
358 
359         case CPL_INQUIRE:
360         {
361             CPLINFO *CPlInfo = (CPLINFO*)lParam2;
362             CPlInfo->idIcon  = IDC_CPLICON;
363             CPlInfo->idName  = IDS_CPLNAME;
364             CPlInfo->idInfo  = IDS_CPLDESCRIPTION;
365             break;
366         }
367 
368         case CPL_DBLCLK:
369             InitApplet((HANDLE)hwndCPl);
370             break;
371     }
372 
373     return FALSE;
374 }
375 
376 INT
377 WINAPI
378 DllMain(HINSTANCE hinstDLL,
379         DWORD     dwReason,
380         LPVOID    lpvReserved)
381 {
382     UNREFERENCED_PARAMETER(lpvReserved);
383 
384     switch (dwReason)
385     {
386         case DLL_PROCESS_ATTACH:
387             hApplet = hinstDLL;
388             DisableThreadLibraryCalls(hinstDLL);
389             break;
390     }
391 
392     return TRUE;
393 }
394