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