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