* Sync up to trunk head (r60691).
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / guisettings.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/frontends/gui/guisettings.c
5 * PURPOSE: GUI Terminal Front-End Settings Management
6 * PROGRAMMERS: Johannes Anderwald
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "consrv.h"
13 #include "include/conio.h"
14 #include "include/settings.h"
15 #include "guisettings.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 VOID GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData);
22 VOID SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
23
24 /* FUNCTIONS ******************************************************************/
25
26 BOOL
27 GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
28 IN LPCWSTR ConsoleTitle,
29 IN DWORD ProcessId)
30 {
31 /*****************************************************
32 * Adapted from ConSrvReadUserSettings in settings.c *
33 *****************************************************/
34
35 BOOL RetVal = FALSE;
36 HKEY hKey;
37 DWORD dwNumSubKeys = 0;
38 DWORD dwIndex;
39 DWORD dwType;
40 WCHAR szValueName[MAX_PATH];
41 DWORD dwValueName;
42 WCHAR szValue[LF_FACESIZE] = L"\0";
43 DWORD Value;
44 DWORD dwValue;
45
46 if (!ConSrvOpenUserSettings(ProcessId,
47 ConsoleTitle,
48 &hKey, KEY_READ,
49 FALSE))
50 {
51 DPRINT("ConSrvOpenUserSettings failed\n");
52 return FALSE;
53 }
54
55 if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
56 &dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
57 {
58 DPRINT("GuiConsoleReadUserSettings: RegQueryInfoKey failed\n");
59 RegCloseKey(hKey);
60 return FALSE;
61 }
62
63 DPRINT("GuiConsoleReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
64
65 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
66 {
67 dwValue = sizeof(Value);
68 dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
69
70 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
71 {
72 if (dwType == REG_SZ)
73 {
74 /*
75 * Retry in case of string value
76 */
77 dwValue = sizeof(szValue);
78 dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
79 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
80 break;
81 }
82 else
83 {
84 break;
85 }
86 }
87
88 if (!wcscmp(szValueName, L"FaceName"))
89 {
90 SIZE_T Length = min(wcslen(szValue) + 1, LF_FACESIZE); // wcsnlen
91 wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE);
92 TermInfo->FaceName[Length] = L'\0';
93 RetVal = TRUE;
94 }
95 else if (!wcscmp(szValueName, L"FontFamily"))
96 {
97 TermInfo->FontFamily = Value;
98 RetVal = TRUE;
99 }
100 else if (!wcscmp(szValueName, L"FontSize"))
101 {
102 TermInfo->FontSize = Value;
103 RetVal = TRUE;
104 }
105 else if (!wcscmp(szValueName, L"FontWeight"))
106 {
107 TermInfo->FontWeight = Value;
108 RetVal = TRUE;
109 }
110 else if (!wcscmp(szValueName, L"FullScreen"))
111 {
112 TermInfo->FullScreen = Value;
113 RetVal = TRUE;
114 }
115 else if (!wcscmp(szValueName, L"WindowPosition"))
116 {
117 TermInfo->AutoPosition = FALSE;
118 TermInfo->WindowOrigin.x = LOWORD(Value);
119 TermInfo->WindowOrigin.y = HIWORD(Value);
120 RetVal = TRUE;
121 }
122 }
123
124 RegCloseKey(hKey);
125 return RetVal;
126 }
127
128 BOOL
129 GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
130 IN LPCWSTR ConsoleTitle,
131 IN DWORD ProcessId)
132 {
133 /******************************************************
134 * Adapted from ConSrvWriteUserSettings in settings.c *
135 ******************************************************/
136
137 BOOL GlobalSettings = (ConsoleTitle[0] == L'\0');
138 HKEY hKey;
139 DWORD Storage = 0;
140
141 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
142 do { \
143 if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
144 { \
145 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
146 } \
147 else \
148 { \
149 RegDeleteValue(hKey, (SettingName)); \
150 } \
151 } while (0)
152
153 if (!ConSrvOpenUserSettings(ProcessId,
154 ConsoleTitle,
155 &hKey, KEY_WRITE,
156 TRUE))
157 {
158 return FALSE;
159 }
160
161 SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(TermInfo->FaceName) + 1) * sizeof(WCHAR), TermInfo->FaceName, L'\0'); // wcsnlen
162 SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &TermInfo->FontFamily, FF_DONTCARE);
163 SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0);
164 SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE);
165
166 Storage = TermInfo->FullScreen;
167 SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
168
169 if (TermInfo->AutoPosition == FALSE)
170 {
171 Storage = MAKELONG(TermInfo->WindowOrigin.x, TermInfo->WindowOrigin.y);
172 RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
173 }
174 else
175 {
176 RegDeleteValue(hKey, L"WindowPosition");
177 }
178
179 RegCloseKey(hKey);
180 return TRUE;
181 }
182
183 VOID
184 GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
185 IN DWORD ProcessId)
186 {
187 /*******************************************************
188 * Adapted from ConSrvGetDefaultSettings in settings.c *
189 *******************************************************/
190
191 if (TermInfo == NULL) return;
192
193 /*
194 * 1. Load the default values
195 */
196 // wcsncpy(TermInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
197 // TermInfo->FontSize = MAKELONG(12, 8); // 0x0008000C; // font is 8x12
198 // TermInfo->FontSize = MAKELONG(16, 16); // font is 16x16
199 // TermInfo->FontWeight = FW_NORMAL;
200
201 wcsncpy(TermInfo->FaceName, L"Fixedsys", LF_FACESIZE); // HACK: !!
202 // TermInfo->FaceName[0] = L'\0';
203 TermInfo->FontFamily = FF_DONTCARE;
204 TermInfo->FontSize = 0;
205 TermInfo->FontWeight = FW_DONTCARE;
206 TermInfo->UseRasterFonts = TRUE;
207
208 TermInfo->FullScreen = FALSE;
209 TermInfo->ShowWindow = SW_SHOWNORMAL;
210 TermInfo->AutoPosition = TRUE;
211 TermInfo->WindowOrigin.x = 0;
212 TermInfo->WindowOrigin.y = 0;
213
214 /*
215 * 2. Overwrite them with the ones stored in HKCU\Console.
216 * If the HKCU\Console key doesn't exist, create it
217 * and store the default values inside.
218 */
219 if (!GuiConsoleReadUserSettings(TermInfo, L"", ProcessId))
220 {
221 GuiConsoleWriteUserSettings(TermInfo, L"", ProcessId);
222 }
223 }
224
225 VOID
226 GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
227 BOOL Defaults)
228 {
229 NTSTATUS Status;
230 PCONSOLE Console = GuiData->Console;
231 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
232 PCONSOLE_PROCESS_DATA ProcessData;
233 HANDLE hSection = NULL, hClientSection = NULL;
234 LARGE_INTEGER SectionSize;
235 ULONG ViewSize = 0;
236 SIZE_T Length = 0;
237 PCONSOLE_PROPS pSharedInfo = NULL;
238 PGUI_CONSOLE_INFO GuiInfo = NULL;
239
240 DPRINT("GuiConsoleShowConsoleProperties entered\n");
241
242 /*
243 * Create a memory section to share with the applet, and map it.
244 */
245 /* Holds data for console.dll + console info + terminal-specific info */
246 SectionSize.QuadPart = sizeof(CONSOLE_PROPS) + sizeof(GUI_CONSOLE_INFO);
247 Status = NtCreateSection(&hSection,
248 SECTION_ALL_ACCESS,
249 NULL,
250 &SectionSize,
251 PAGE_READWRITE,
252 SEC_COMMIT,
253 NULL);
254 if (!NT_SUCCESS(Status))
255 {
256 DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status);
257 return;
258 }
259
260 Status = NtMapViewOfSection(hSection,
261 NtCurrentProcess(),
262 (PVOID*)&pSharedInfo,
263 0,
264 0,
265 NULL,
266 &ViewSize,
267 ViewUnmap,
268 0,
269 PAGE_READWRITE);
270 if (!NT_SUCCESS(Status))
271 {
272 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status);
273 NtClose(hSection);
274 return;
275 }
276
277
278 /*
279 * Setup the shared console properties structure.
280 */
281
282 /* Header */
283 pSharedInfo->hConsoleWindow = GuiData->hWindow;
284 pSharedInfo->ShowDefaultParams = Defaults;
285
286 /*
287 * We fill-in the fields only if we display
288 * our properties, not the default ones.
289 */
290 if (!Defaults)
291 {
292 /* Console information */
293 pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
294 pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
295 pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup;
296 pSharedInfo->ci.QuickEdit = Console->QuickEdit;
297 pSharedInfo->ci.InsertMode = Console->InsertMode;
298 pSharedInfo->ci.InputBufferSize = 0;
299 pSharedInfo->ci.ScreenBufferSize = ActiveBuffer->ScreenBufferSize;
300 pSharedInfo->ci.ConsoleSize = ActiveBuffer->ViewSize;
301 pSharedInfo->ci.CursorBlinkOn;
302 pSharedInfo->ci.ForceCursorOff;
303 pSharedInfo->ci.CursorSize = ActiveBuffer->CursorInfo.dwSize;
304 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
305 {
306 PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer;
307
308 pSharedInfo->ci.ScreenAttrib = Buffer->ScreenDefaultAttrib;
309 pSharedInfo->ci.PopupAttrib = Buffer->PopupDefaultAttrib;
310 }
311 else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
312 {
313 // PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer;
314 DPRINT1("GuiConsoleShowConsoleProperties - Graphics buffer\n");
315
316 // FIXME: Gather defaults from the registry ?
317 pSharedInfo->ci.ScreenAttrib = DEFAULT_SCREEN_ATTRIB;
318 pSharedInfo->ci.PopupAttrib = DEFAULT_POPUP_ATTRIB ;
319 }
320 pSharedInfo->ci.CodePage;
321
322 /* GUI Information */
323 pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
324 GuiInfo = pSharedInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pSharedInfo + 1);
325 Length = min(wcslen(GuiData->GuiInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
326 wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE);
327 GuiInfo->FaceName[Length] = L'\0';
328 GuiInfo->FontFamily = GuiData->GuiInfo.FontFamily;
329 GuiInfo->FontSize = GuiData->GuiInfo.FontSize;
330 GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
331 GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
332 GuiInfo->FullScreen = GuiData->GuiInfo.FullScreen;
333 /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
334 GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
335 GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin;
336 /* Offsetize */
337 pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)GuiInfo - (ULONG_PTR)pSharedInfo);
338
339 /* Palette */
340 memcpy(pSharedInfo->ci.Colors, Console->Colors, sizeof(Console->Colors));
341
342 /* Title of the console, original one corresponding to the one set by the console leader */
343 Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
344 Console->OriginalTitle.Length / sizeof(WCHAR));
345 wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
346 }
347 else
348 {
349 Length = 0;
350 // FIXME: Load the default parameters from the registry.
351 }
352
353 /* Null-terminate the title */
354 pSharedInfo->ci.ConsoleTitle[Length] = L'\0';
355
356
357 /* Unmap the view */
358 NtUnmapViewOfSection(NtCurrentProcess(), pSharedInfo);
359
360 /* Get the console leader process, our client */
361 ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
362 CONSOLE_PROCESS_DATA,
363 ConsoleLink);
364
365 /* Duplicate the section handle for the client */
366 Status = NtDuplicateObject(NtCurrentProcess(),
367 hSection,
368 ProcessData->Process->ProcessHandle,
369 &hClientSection,
370 0, 0, DUPLICATE_SAME_ACCESS);
371 if (!NT_SUCCESS(Status))
372 {
373 DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status);
374 goto Quit;
375 }
376
377 /* Start the properties dialog */
378 if (ProcessData->PropDispatcher)
379 {
380 _SEH2_TRY
381 {
382 HANDLE Thread = NULL;
383
384 _SEH2_TRY
385 {
386 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
387 ProcessData->PropDispatcher,
388 (PVOID)hClientSection, 0, NULL);
389 if (NULL == Thread)
390 {
391 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
392 }
393 else
394 {
395 DPRINT("ProcessData->PropDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
396 /// WaitForSingleObject(Thread, INFINITE);
397 }
398 }
399 _SEH2_FINALLY
400 {
401 CloseHandle(Thread);
402 }
403 _SEH2_END;
404 }
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
406 {
407 Status = _SEH2_GetExceptionCode();
408 DPRINT1("GuiConsoleShowConsoleProperties - Caught an exception, Status = %08X\n", Status);
409 }
410 _SEH2_END;
411 }
412
413 Quit:
414 /* We have finished, close the section handle */
415 NtClose(hSection);
416 return;
417 }
418
419 NTSTATUS
420 GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
421 HANDLE hClientSection,
422 BOOL SaveSettings)
423 {
424 NTSTATUS Status = STATUS_SUCCESS;
425 PCONSOLE Console = GuiData->Console;
426 PCONSOLE_PROCESS_DATA ProcessData;
427 HANDLE hSection = NULL;
428 ULONG ViewSize = 0;
429 PCONSOLE_PROPS pConInfo = NULL;
430 PCONSOLE_INFO ConInfo = NULL;
431 PTERMINAL_INFO TermInfo = NULL;
432 PGUI_CONSOLE_INFO GuiInfo = NULL;
433
434 /* Get the console leader process, our client */
435 ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
436 CONSOLE_PROCESS_DATA,
437 ConsoleLink);
438
439 /* Duplicate the section handle for ourselves */
440 Status = NtDuplicateObject(ProcessData->Process->ProcessHandle,
441 hClientSection,
442 NtCurrentProcess(),
443 &hSection,
444 0, 0, DUPLICATE_SAME_ACCESS);
445 if (!NT_SUCCESS(Status))
446 {
447 DPRINT1("Error when mapping client handle, Status = %lu\n", Status);
448 return Status;
449 }
450
451 /* Get a view of the shared section */
452 Status = NtMapViewOfSection(hSection,
453 NtCurrentProcess(),
454 (PVOID*)&pConInfo,
455 0,
456 0,
457 NULL,
458 &ViewSize,
459 ViewUnmap,
460 0,
461 PAGE_READONLY);
462 if (!NT_SUCCESS(Status))
463 {
464 DPRINT1("Error when mapping view of file, Status = %lu\n", Status);
465 NtClose(hSection);
466 return Status;
467 }
468
469 _SEH2_TRY
470 {
471 /* Check that the section is well-sized */
472 if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
473 (pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
474 (ViewSize < sizeof(CONSOLE_PROPS) + pConInfo->TerminalInfo.Size) )
475 {
476 DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
477 Status = STATUS_INVALID_VIEW_SIZE;
478 _SEH2_YIELD(goto Quit);
479 }
480
481 // TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
482
483 /* Retrieve terminal informations */
484 ConInfo = &pConInfo->ci;
485 TermInfo = &pConInfo->TerminalInfo;
486 GuiInfo = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo);
487
488 /*
489 * If we don't set the default parameters,
490 * apply them, otherwise just save them.
491 */
492 if (pConInfo->ShowDefaultParams == FALSE)
493 {
494 /* Set the console informations */
495 ConSrvApplyUserSettings(Console, ConInfo);
496
497 /* Set the terminal informations */
498
499 // memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
500
501 /* Move the window to the user's values */
502 GuiData->GuiInfo.AutoPosition = GuiInfo->AutoPosition;
503 GuiData->GuiInfo.WindowOrigin = GuiInfo->WindowOrigin;
504 GuiConsoleMoveWindow(GuiData);
505
506 InvalidateRect(GuiData->hWindow, NULL, TRUE);
507
508 /*
509 * Apply full-screen mode.
510 */
511 if (GuiInfo->FullScreen != GuiData->GuiInfo.FullScreen)
512 {
513 SwitchFullScreen(GuiData, GuiInfo->FullScreen);
514 }
515 }
516
517 /*
518 * Save settings if needed
519 */
520 // FIXME: Do it in the console properties applet ??
521 if (SaveSettings)
522 {
523 DWORD ProcessId = HandleToUlong(ProcessData->Process->ClientId.UniqueProcess);
524 ConSrvWriteUserSettings(ConInfo, ProcessId);
525 GuiConsoleWriteUserSettings(GuiInfo, ConInfo->ConsoleTitle, ProcessId);
526 }
527
528 Status = STATUS_SUCCESS;
529 }
530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
531 {
532 Status = _SEH2_GetExceptionCode();
533 DPRINT1("GuiApplyUserSettings - Caught an exception, Status = %08X\n", Status);
534 }
535 _SEH2_END;
536
537 Quit:
538 /* Finally, close the section and return */
539 NtUnmapViewOfSection(NtCurrentProcess(), pConInfo);
540 NtClose(hSection);
541 return Status;
542 }
543
544 /* EOF */