2362ae6a84c7058bcdfe360493e929b4f3d1cd43
[reactos.git] / win32ss / user / consrv / guisettings.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/guisettings.c
5 * PURPOSE: GUI terminal emulator settings management
6 * PROGRAMMERS: Hermes Belusca - Maito
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13 #include "settings.h"
14 #include "guiconsole.h"
15 #include "guisettings.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 VOID GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData);
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 wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE);
90 RetVal = TRUE;
91 }
92 else if (!wcscmp(szValueName, L"FontFamily"))
93 {
94 TermInfo->FontFamily = Value;
95 RetVal = TRUE;
96 }
97 else if (!wcscmp(szValueName, L"FontSize"))
98 {
99 TermInfo->FontSize = Value;
100 RetVal = TRUE;
101 }
102 else if (!wcscmp(szValueName, L"FontWeight"))
103 {
104 TermInfo->FontWeight = Value;
105 RetVal = TRUE;
106 }
107 else if (!wcscmp(szValueName, L"WindowPosition"))
108 {
109 TermInfo->AutoPosition = FALSE;
110 TermInfo->WindowOrigin.x = LOWORD(Value);
111 TermInfo->WindowOrigin.y = HIWORD(Value);
112 RetVal = TRUE;
113 }
114 }
115
116 RegCloseKey(hKey);
117 return RetVal;
118 }
119
120 BOOL
121 GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
122 IN LPCWSTR ConsoleTitle,
123 IN DWORD ProcessId)
124 {
125 /******************************************************
126 * Adapted from ConSrvWriteUserSettings in settings.c *
127 ******************************************************/
128
129 BOOL GlobalSettings = (ConsoleTitle[0] == L'\0');
130 HKEY hKey;
131 DWORD Storage = 0;
132
133 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
134 do { \
135 if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
136 { \
137 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
138 } \
139 else \
140 { \
141 RegDeleteValue(hKey, (SettingName)); \
142 } \
143 } while (0)
144
145 if (!ConSrvOpenUserSettings(ProcessId,
146 ConsoleTitle,
147 &hKey, KEY_WRITE,
148 TRUE))
149 {
150 return FALSE;
151 }
152
153 SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(TermInfo->FaceName) + 1) * sizeof(WCHAR), TermInfo->FaceName, L'\0');
154 SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &TermInfo->FontFamily, FF_DONTCARE);
155 SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0);
156 SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE);
157
158 if (TermInfo->AutoPosition == FALSE)
159 {
160 Storage = MAKELONG(TermInfo->WindowOrigin.x, TermInfo->WindowOrigin.y);
161 RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
162 }
163 else
164 {
165 RegDeleteValue(hKey, L"WindowPosition");
166 }
167
168 RegCloseKey(hKey);
169 return TRUE;
170 }
171
172 VOID
173 GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
174 IN DWORD ProcessId)
175 {
176 /*******************************************************
177 * Adapted from ConSrvGetDefaultSettings in settings.c *
178 *******************************************************/
179
180 if (TermInfo == NULL) return;
181
182 /*
183 * 1. Load the default values
184 */
185 // wcsncpy(TermInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
186 // TermInfo->FontSize = MAKELONG(12, 8); // 0x0008000C; // font is 8x12
187 // TermInfo->FontSize = MAKELONG(16, 16); // font is 16x16
188 // TermInfo->FontWeight = FW_NORMAL;
189
190 wcsncpy(TermInfo->FaceName, L"Fixedsys", LF_FACESIZE); // HACK: !!
191 // TermInfo->FaceName[0] = L'\0';
192 TermInfo->FontFamily = FF_DONTCARE;
193 TermInfo->FontSize = 0;
194 TermInfo->FontWeight = FW_DONTCARE;
195 TermInfo->UseRasterFonts = TRUE;
196
197 TermInfo->ShowWindow = SW_SHOWNORMAL;
198 TermInfo->AutoPosition = TRUE;
199 TermInfo->WindowOrigin = (POINT){0, 0};
200
201 /*
202 * 2. Overwrite them with the ones stored in HKCU\Console.
203 * If the HKCU\Console key doesn't exist, create it
204 * and store the default values inside.
205 */
206 if (!GuiConsoleReadUserSettings(TermInfo, L"", ProcessId))
207 {
208 GuiConsoleWriteUserSettings(TermInfo, L"", ProcessId);
209 }
210 }
211
212 VOID
213 GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
214 BOOL Defaults)
215 {
216 NTSTATUS Status;
217 PCONSOLE Console = GuiData->Console;
218 PCONSOLE_PROCESS_DATA ProcessData;
219 HANDLE hSection = NULL, hClientSection = NULL;
220 LARGE_INTEGER SectionSize;
221 ULONG ViewSize = 0;
222 SIZE_T Length = 0;
223 PCONSOLE_PROPS pSharedInfo = NULL;
224 PGUI_CONSOLE_INFO GuiInfo = NULL;
225
226 DPRINT("GuiConsoleShowConsoleProperties entered\n");
227
228 /*
229 * Create a memory section to share with the applet, and map it.
230 */
231 /* Holds data for console.dll + console info + terminal-specific info */
232 SectionSize.QuadPart = sizeof(CONSOLE_PROPS) + sizeof(GUI_CONSOLE_INFO);
233 Status = NtCreateSection(&hSection,
234 SECTION_ALL_ACCESS,
235 NULL,
236 &SectionSize,
237 PAGE_READWRITE,
238 SEC_COMMIT,
239 NULL);
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status);
243 return;
244 }
245
246 Status = NtMapViewOfSection(hSection,
247 NtCurrentProcess(),
248 (PVOID*)&pSharedInfo,
249 0,
250 0,
251 NULL,
252 &ViewSize,
253 ViewUnmap,
254 0,
255 PAGE_READWRITE);
256 if (!NT_SUCCESS(Status))
257 {
258 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status);
259 NtClose(hSection);
260 return;
261 }
262
263
264 /*
265 * Setup the shared console properties structure.
266 */
267
268 /* Header */
269 pSharedInfo->hConsoleWindow = GuiData->hWindow;
270 pSharedInfo->ShowDefaultParams = Defaults;
271
272 /* Console information */
273 pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
274 pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
275 pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup;
276 pSharedInfo->ci.FullScreen = Console->FullScreen;
277 pSharedInfo->ci.QuickEdit = Console->QuickEdit;
278 pSharedInfo->ci.InsertMode = Console->InsertMode;
279 pSharedInfo->ci.InputBufferSize = 0;
280 pSharedInfo->ci.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
281 pSharedInfo->ci.ConsoleSize = Console->ConsoleSize;
282 pSharedInfo->ci.CursorBlinkOn;
283 pSharedInfo->ci.ForceCursorOff;
284 pSharedInfo->ci.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
285 pSharedInfo->ci.ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
286 pSharedInfo->ci.PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib;
287 pSharedInfo->ci.CodePage;
288
289 /* GUI Information */
290 pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
291 GuiInfo = pSharedInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pSharedInfo + 1);
292 wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE);
293 GuiInfo->FontSize = (DWORD)GuiData->GuiInfo.FontSize;
294 GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
295 GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
296 /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
297 GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
298 GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin;
299 /* Offsetize */
300 pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)GuiInfo - (ULONG_PTR)pSharedInfo);
301
302 /* Palette */
303 memcpy(pSharedInfo->ci.Colors, Console->Colors, sizeof(Console->Colors));
304
305 /* Title of the console, original one corresponding to the one set by the console leader */
306 Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
307 Console->OriginalTitle.Length / sizeof(WCHAR));
308 wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
309 pSharedInfo->ci.ConsoleTitle[Length] = L'\0';
310
311
312 /* Unmap the view */
313 NtUnmapViewOfSection(NtCurrentProcess(), pSharedInfo);
314
315 /* Get the console leader process, our client */
316 ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
317 CONSOLE_PROCESS_DATA,
318 ConsoleLink);
319
320 /* Duplicate the section handle for the client */
321 Status = NtDuplicateObject(NtCurrentProcess(),
322 hSection,
323 ProcessData->Process->ProcessHandle,
324 &hClientSection,
325 0, 0, DUPLICATE_SAME_ACCESS);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status);
329 NtClose(hSection);
330 return;
331 }
332
333 /* Start the properties dialog */
334 if (ProcessData->PropDispatcher)
335 {
336 HANDLE Thread;
337
338 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
339 ProcessData->PropDispatcher,
340 (PVOID)hClientSection, 0, NULL);
341 if (NULL == Thread)
342 {
343 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
344 return;
345 }
346
347 DPRINT1("We succeeded at creating ProcessData->PropDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
348 /// WaitForSingleObject(Thread, INFINITE);
349 CloseHandle(Thread);
350 }
351
352 /* We have finished, close the section handle */
353 NtClose(hSection);
354 return;
355 }
356
357 NTSTATUS
358 GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
359 HANDLE hClientSection,
360 BOOL SaveSettings)
361 {
362 NTSTATUS Status = STATUS_SUCCESS;
363 PCONSOLE Console = GuiData->Console;
364 PCONSOLE_PROCESS_DATA ProcessData;
365 HANDLE hSection = NULL;
366 ULONG ViewSize = 0;
367 PCONSOLE_PROPS pConInfo = NULL;
368 PCONSOLE_INFO ConInfo = NULL;
369 PTERMINAL_INFO TermInfo = NULL;
370 PGUI_CONSOLE_INFO GuiInfo = NULL;
371
372 /// LOCK /// EnterCriticalSection(&Console->Lock);
373
374 /* Get the console leader process, our client */
375 ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
376 CONSOLE_PROCESS_DATA,
377 ConsoleLink);
378
379 /* Duplicate the section handle for ourselves */
380 Status = NtDuplicateObject(ProcessData->Process->ProcessHandle,
381 hClientSection,
382 NtCurrentProcess(),
383 &hSection,
384 0, 0, DUPLICATE_SAME_ACCESS);
385 if (!NT_SUCCESS(Status))
386 {
387 DPRINT1("Error when mapping client handle, Status = %lu\n", Status);
388 return Status;
389 }
390
391 /* Get a view of the shared section */
392 Status = NtMapViewOfSection(hSection,
393 NtCurrentProcess(),
394 (PVOID*)&pConInfo,
395 0,
396 0,
397 NULL,
398 &ViewSize,
399 ViewUnmap,
400 0,
401 PAGE_READONLY);
402 if (!NT_SUCCESS(Status))
403 {
404 DPRINT1("Error when mapping view of file, Status = %lu\n", Status);
405 NtClose(hSection);
406 return Status;
407 }
408
409 /* Check that the section is well-sized */
410 if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
411 (pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
412 (ViewSize < sizeof(CONSOLE_PROPS) + pConInfo->TerminalInfo.Size) )
413 {
414 DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
415 Status = STATUS_INVALID_VIEW_SIZE;
416 goto Quit;
417 }
418
419 // TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
420
421 /* Set the console informations */
422 ConInfo = &pConInfo->ci;
423 ConSrvApplyUserSettings(Console, ConInfo);
424
425 /* Set the terminal informations - De-offsetization of the pointer */
426 TermInfo = &pConInfo->TerminalInfo;
427 GuiInfo = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo);
428
429 // memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
430
431 /* Move the window to the user's values */
432 GuiData->GuiInfo.AutoPosition = GuiInfo->AutoPosition;
433 GuiData->GuiInfo.WindowOrigin = GuiInfo->WindowOrigin;
434 GuiConsoleMoveWindow(GuiData);
435
436 InvalidateRect(GuiData->hWindow, NULL, TRUE);
437
438
439 /*
440 * Save settings if needed
441 */
442
443 // FIXME: Do it in the console properties applet ??
444 if (SaveSettings)
445 {
446 DWORD ProcessId = HandleToUlong(ProcessData->Process->ClientId.UniqueProcess);
447 ConSrvWriteUserSettings(ConInfo, ProcessId);
448 GuiConsoleWriteUserSettings(GuiInfo, ConInfo->ConsoleTitle, ProcessId);
449 }
450
451 Status = STATUS_SUCCESS;
452
453 /// LOCK /// LeaveCriticalSection(&Console->Lock);
454
455 Quit:
456 /* Finally, close the section and return */
457 NtUnmapViewOfSection(NtCurrentProcess(), pConInfo);
458 NtClose(hSection);
459 return Status;
460 }
461
462 /* EOF */