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