[FORMATTING] Standardize win32csr to 4-space indents. Based on a patch by Adam Kachwa...
[reactos.git] / reactos / subsystems / win32 / csrss / win32csr / tuiconsole.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: subsys/csrss/win32csr/tuiconsole.c
6 * PURPOSE: Implementation of text-mode consoles
7 */
8
9 #define NDEBUG
10 #include "w32csr.h"
11 #include <debug.h>
12
13 CRITICAL_SECTION ActiveConsoleLock;
14 static COORD PhysicalConsoleSize;
15 static HANDLE ConsoleDeviceHandle;
16 static PCSRSS_CONSOLE ActiveConsole;
17
18 static BOOL ConsInitialized = FALSE;
19
20 static LRESULT CALLBACK
21 TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
22 {
23 if (msg == WM_ACTIVATE)
24 {
25 if (LOWORD(wParam) != WA_INACTIVE)
26 {
27 SetFocus(hWnd);
28 ConioDrawConsole(ActiveConsole);
29 }
30 }
31 return DefWindowProcW(hWnd, msg, wParam, lParam);
32 }
33
34 static BOOL FASTCALL
35 TuiStartService(LPCWSTR lpServiceName)
36 {
37 SC_HANDLE hSCManager = NULL;
38 SC_HANDLE hService = NULL;
39 BOOL ret = FALSE;
40
41 hSCManager = OpenSCManagerW(NULL, NULL, 0);
42 if (hSCManager == NULL)
43 goto cleanup;
44
45 hService = OpenServiceW(hSCManager, lpServiceName, SERVICE_START);
46 if (hService == NULL)
47 goto cleanup;
48
49 ret = StartServiceW(hService, 0, NULL);
50 if (!ret)
51 goto cleanup;
52
53 ret = TRUE;
54
55 cleanup:
56 if (hSCManager != NULL)
57 CloseServiceHandle(hSCManager);
58 if (hService != NULL)
59 CloseServiceHandle(hService);
60 return ret;
61 }
62
63 static BOOL FASTCALL
64 TuiInit(DWORD OemCP)
65 {
66 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
67 DWORD BytesReturned;
68 WNDCLASSEXW wc;
69 USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
70
71 TuiStartService(L"Blue");
72
73 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", FILE_ALL_ACCESS, 0, NULL,
74 OPEN_EXISTING, 0, NULL);
75 if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
76 {
77 DPRINT1("Failed to open BlueScreen.\n");
78 return FALSE;
79 }
80
81 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT,
82 &OemCP, sizeof(OemCP), NULL, 0,
83 &BytesReturned, NULL))
84 {
85 DPRINT1("Failed to load the font for codepage %d\n", OemCP);
86 /* Let's suppose the font is good enough to continue */
87 }
88
89 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
90 &TextAttribute, sizeof(TextAttribute), NULL, 0,
91 &BytesReturned, NULL))
92 {
93 DPRINT1("Failed to set text attribute\n");
94 }
95
96 ActiveConsole = NULL;
97 InitializeCriticalSection(&ActiveConsoleLock);
98 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
99 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
100 {
101 DPRINT1("Failed to get console info\n");
102 return FALSE;
103 }
104 PhysicalConsoleSize = ScrInfo.dwSize;
105
106 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
107 wc.cbSize = sizeof(WNDCLASSEXW);
108 wc.lpszClassName = L"TuiConsoleWindowClass";
109 wc.lpfnWndProc = TuiConsoleWndProc;
110 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
111 if (RegisterClassExW(&wc) == 0)
112 {
113 DPRINT1("Failed to register console wndproc\n");
114 return FALSE;
115 }
116
117 return TRUE;
118 }
119
120 static VOID WINAPI
121 TuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
122 {
123 Buffer->DefaultAttrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
124 }
125
126 static void FASTCALL
127 TuiCopyRect(char *Dest, PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *Region)
128 {
129 UINT SrcDelta, DestDelta;
130 LONG i;
131 PBYTE Src, SrcEnd;
132
133 Src = ConioCoordToPointer(Buff, Region->Left, Region->Top);
134 SrcDelta = Buff->MaxX * 2;
135 SrcEnd = Buff->Buffer + Buff->MaxY * Buff->MaxX * 2;
136 DestDelta = ConioRectWidth(Region) * 2;
137 for (i = Region->Top; i <= Region->Bottom; i++)
138 {
139 memcpy(Dest, Src, DestDelta);
140 Src += SrcDelta;
141 if (SrcEnd <= Src)
142 {
143 Src -= Buff->MaxY * Buff->MaxX * 2;
144 }
145 Dest += DestDelta;
146 }
147 }
148
149 static VOID WINAPI
150 TuiDrawRegion(PCSRSS_CONSOLE Console, SMALL_RECT *Region)
151 {
152 DWORD BytesReturned;
153 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
154 PCONSOLE_DRAW ConsoleDraw;
155 UINT ConsoleDrawSize;
156
157 if (ActiveConsole != Console)
158 {
159 return;
160 }
161
162 ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
163 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
164 ConsoleDraw = HeapAlloc(Win32CsrApiHeap, 0, ConsoleDrawSize);
165 if (NULL == ConsoleDraw)
166 {
167 DPRINT1("HeapAlloc failed\n");
168 return;
169 }
170 ConsoleDraw->X = Region->Left;
171 ConsoleDraw->Y = Region->Top;
172 ConsoleDraw->SizeX = ConioRectWidth(Region);
173 ConsoleDraw->SizeY = ConioRectHeight(Region);
174 ConsoleDraw->CursorX = Buff->CurrentX;
175 ConsoleDraw->CursorY = Buff->CurrentY;
176
177 TuiCopyRect((char *) (ConsoleDraw + 1), Buff, Region);
178
179 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
180 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
181 {
182 DPRINT1("Failed to draw console\n");
183 HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
184 return;
185 }
186
187 HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
188 }
189
190 static VOID WINAPI
191 TuiWriteStream(PCSRSS_CONSOLE Console, SMALL_RECT *Region, LONG CursorStartX, LONG CursorStartY,
192 UINT ScrolledLines, CHAR *Buffer, UINT Length)
193 {
194 DWORD BytesWritten;
195 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
196
197 if (ActiveConsole->ActiveBuffer != Buff)
198 {
199 return;
200 }
201
202 if (! WriteFile(ConsoleDeviceHandle, Buffer, Length, &BytesWritten, NULL))
203 {
204 DPRINT1("Error writing to BlueScreen\n");
205 }
206 }
207
208 static BOOL WINAPI
209 TuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
210 {
211 DWORD BytesReturned;
212
213 if (ActiveConsole->ActiveBuffer != Buff)
214 {
215 return TRUE;
216 }
217
218 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
219 &Buff->CursorInfo, sizeof(Buff->CursorInfo), NULL, 0,
220 &BytesReturned, NULL))
221 {
222 DPRINT1( "Failed to set cursor info\n" );
223 return FALSE;
224 }
225
226 return TRUE;
227 }
228
229 static BOOL WINAPI
230 TuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
231 {
232 CONSOLE_SCREEN_BUFFER_INFO Info;
233 DWORD BytesReturned;
234
235 if (ActiveConsole->ActiveBuffer != Buff)
236 {
237 return TRUE;
238 }
239
240 Info.dwCursorPosition.X = Buff->CurrentX;
241 Info.dwCursorPosition.Y = Buff->CurrentY;
242 Info.wAttributes = Buff->DefaultAttrib;
243
244 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
245 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
246 &BytesReturned, NULL))
247 {
248 DPRINT1( "Failed to set cursor position\n" );
249 return FALSE;
250 }
251
252 return TRUE;
253 }
254
255 static BOOL WINAPI
256 TuiUpdateScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
257 {
258 return TRUE;
259 }
260
261 static BOOL WINAPI
262 TuiChangeTitle(PCSRSS_CONSOLE Console)
263 {
264 return TRUE;
265 }
266
267 static VOID WINAPI
268 TuiCleanupConsole(PCSRSS_CONSOLE Console)
269 {
270 DestroyWindow(Console->hWindow);
271
272 EnterCriticalSection(&ActiveConsoleLock);
273
274 /* Switch to next console */
275 if (ActiveConsole == Console)
276 {
277 ActiveConsole = Console->Next != Console ? Console->Next : NULL;
278 }
279
280 if (Console->Next != Console)
281 {
282 Console->Prev->Next = Console->Next;
283 Console->Next->Prev = Console->Prev;
284 }
285 LeaveCriticalSection(&ActiveConsoleLock);
286
287 if (NULL != ActiveConsole)
288 {
289 ConioDrawConsole(ActiveConsole);
290 }
291 }
292
293 static BOOL WINAPI
294 TuiChangeIcon(PCSRSS_CONSOLE Console, HICON hWindowIcon)
295 {
296 return TRUE;
297 }
298
299 static NTSTATUS WINAPI
300 TuiResizeBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer, COORD Size)
301 {
302 UNIMPLEMENTED;
303 return STATUS_NOT_IMPLEMENTED;
304 }
305
306 DWORD WINAPI
307 TuiConsoleThread (PVOID Data)
308 {
309 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Data;
310 HWND NewWindow;
311 MSG msg;
312
313 NewWindow = CreateWindowW(L"TuiConsoleWindowClass",
314 Console->Title.Buffer,
315 0,
316 -32000, -32000, 0, 0,
317 NULL, NULL,
318 (HINSTANCE) GetModuleHandleW(NULL),
319 (PVOID) Console);
320 Console->hWindow = NewWindow;
321 if (NULL == NewWindow)
322 {
323 DPRINT1("CSR: Unable to create console window\n");
324 return 1;
325 }
326
327 SetForegroundWindow(Console->hWindow);
328
329 while (TRUE)
330 {
331 GetMessageW(&msg, 0, 0, 0);
332 DispatchMessage(&msg);
333 TranslateMessage(&msg);
334
335 if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
336 msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ||
337 msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
338 {
339 ConioProcessKey(&msg, Console, TRUE);
340 }
341 }
342
343 return 0;
344 }
345
346 static CSRSS_CONSOLE_VTBL TuiVtbl =
347 {
348 TuiInitScreenBuffer,
349 TuiWriteStream,
350 TuiDrawRegion,
351 TuiSetCursorInfo,
352 TuiSetScreenInfo,
353 TuiUpdateScreenInfo,
354 TuiChangeTitle,
355 TuiCleanupConsole,
356 TuiChangeIcon,
357 TuiResizeBuffer,
358 };
359
360 NTSTATUS FASTCALL
361 TuiInitConsole(PCSRSS_CONSOLE Console)
362 {
363 HANDLE ThreadHandle;
364
365 if (! ConsInitialized)
366 {
367 ConsInitialized = TRUE;
368 if (! TuiInit(Console->CodePage))
369 {
370 ConsInitialized = FALSE;
371 return STATUS_UNSUCCESSFUL;
372 }
373 }
374
375 Console->Vtbl = &TuiVtbl;
376 Console->hWindow = NULL;
377 Console->Size = PhysicalConsoleSize;
378 Console->ActiveBuffer->MaxX = PhysicalConsoleSize.X;
379 Console->ActiveBuffer->MaxY = PhysicalConsoleSize.Y;
380
381 ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) TuiConsoleThread,
382 Console, 0, NULL);
383 if (NULL == ThreadHandle)
384 {
385 DPRINT1("CSR: Unable to create console thread\n");
386 return STATUS_UNSUCCESSFUL;
387 }
388 CloseHandle(ThreadHandle);
389
390 EnterCriticalSection(&ActiveConsoleLock);
391 if (NULL != ActiveConsole)
392 {
393 Console->Prev = ActiveConsole;
394 Console->Next = ActiveConsole->Next;
395 ActiveConsole->Next->Prev = Console;
396 ActiveConsole->Next = Console;
397 }
398 else
399 {
400 Console->Prev = Console;
401 Console->Next = Console;
402 }
403 ActiveConsole = Console;
404 LeaveCriticalSection(&ActiveConsoleLock);
405
406 return STATUS_SUCCESS;
407 }
408
409 PCSRSS_CONSOLE FASTCALL
410 TuiGetFocusConsole(VOID)
411 {
412 return ActiveConsole;
413 }
414
415 BOOL FASTCALL
416 TuiSwapConsole(int Next)
417 {
418 static PCSRSS_CONSOLE SwapConsole = NULL; /* console we are thinking about swapping with */
419 DWORD BytesReturned;
420 ANSI_STRING Title;
421 void * Buffer;
422 COORD *pos;
423
424 if (0 != Next)
425 {
426 /* alt-tab, swap consoles */
427 /* move SwapConsole to next console, and print its title */
428 EnterCriticalSection(&ActiveConsoleLock);
429 if (! SwapConsole)
430 {
431 SwapConsole = ActiveConsole;
432 }
433
434 SwapConsole = (0 < Next ? SwapConsole->Next : SwapConsole->Prev);
435 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Title);
436 Title.Length = 0;
437 Buffer = HeapAlloc(Win32CsrApiHeap,
438 0,
439 sizeof(COORD) + Title.MaximumLength);
440 pos = (COORD *)Buffer;
441 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof( COORD ));
442
443 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
444 pos->Y = PhysicalConsoleSize.Y / 2;
445 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
446 /* redraw the console to clear off old title */
447 ConioDrawConsole(ActiveConsole);
448 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
449 NULL, 0, Buffer, sizeof(COORD) + Title.Length,
450 &BytesReturned, NULL))
451 {
452 DPRINT1( "Error writing to console\n" );
453 }
454 HeapFree(Win32CsrApiHeap, 0, Buffer);
455 LeaveCriticalSection(&ActiveConsoleLock);
456
457 return TRUE;
458 }
459 else if (NULL != SwapConsole)
460 {
461 EnterCriticalSection(&ActiveConsoleLock);
462 if (SwapConsole != ActiveConsole)
463 {
464 /* first remove swapconsole from the list */
465 SwapConsole->Prev->Next = SwapConsole->Next;
466 SwapConsole->Next->Prev = SwapConsole->Prev;
467 /* now insert before activeconsole */
468 SwapConsole->Next = ActiveConsole;
469 SwapConsole->Prev = ActiveConsole->Prev;
470 ActiveConsole->Prev->Next = SwapConsole;
471 ActiveConsole->Prev = SwapConsole;
472 }
473 ActiveConsole = SwapConsole;
474 SwapConsole = NULL;
475 ConioDrawConsole(ActiveConsole);
476 LeaveCriticalSection(&ActiveConsoleLock);
477 return TRUE;
478 }
479 else
480 {
481 return FALSE;
482 }
483 }
484
485 /* EOF */