Remove debug message
[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 TuiUpdateScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
218 {
219 return TRUE;
220 }
221
222 static BOOL STDCALL
223 TuiChangeTitle(PCSRSS_CONSOLE Console)
224 {
225 return TRUE;
226 }
227
228 static VOID STDCALL
229 TuiCleanupConsole(PCSRSS_CONSOLE Console)
230 {
231 DestroyWindow(Console->hWindow);
232
233 EnterCriticalSection(&ActiveConsoleLock);
234
235 /* Switch to next console */
236 if (ActiveConsole == Console)
237 {
238 ActiveConsole = Console->Next != Console ? Console->Next : NULL;
239 }
240
241 if (Console->Next != Console)
242 {
243 Console->Prev->Next = Console->Next;
244 Console->Next->Prev = Console->Prev;
245 }
246 LeaveCriticalSection(&ActiveConsoleLock);
247
248 if (NULL != ActiveConsole)
249 {
250 ConioDrawConsole(ActiveConsole);
251 }
252 }
253
254 DWORD STDCALL
255 TuiConsoleThread (PVOID Data)
256 {
257 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Data;
258 HWND NewWindow;
259 MSG msg;
260
261 NewWindow = CreateWindowW(L"TuiConsoleWindowClass",
262 Console->Title.Buffer,
263 0,
264 -32000, -32000, 0, 0,
265 NULL, NULL,
266 (HINSTANCE) GetModuleHandleW(NULL),
267 (PVOID) Console);
268 Console->hWindow = NewWindow;
269 if (NULL == NewWindow)
270 {
271 DPRINT1("CSR: Unable to create console window\n");
272 return 1;
273 }
274
275 SetForegroundWindow(Console->hWindow);
276
277 while (TRUE)
278 {
279 GetMessageW(&msg, 0, 0, 0);
280 DispatchMessage(&msg);
281 TranslateMessage(&msg);
282
283 if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
284 msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ||
285 msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
286 {
287 ConioProcessKey(&msg, Console, TRUE);
288 }
289 }
290
291 return 0;
292 }
293
294 static CSRSS_CONSOLE_VTBL TuiVtbl =
295 {
296 TuiInitScreenBuffer,
297 TuiWriteStream,
298 TuiDrawRegion,
299 TuiSetCursorInfo,
300 TuiSetScreenInfo,
301 TuiUpdateScreenInfo,
302 TuiChangeTitle,
303 TuiCleanupConsole
304 };
305
306 NTSTATUS FASTCALL
307 TuiInitConsole(PCSRSS_CONSOLE Console)
308 {
309 HANDLE ThreadHandle;
310
311 if (! ConsInitialized)
312 {
313 ConsInitialized = TRUE;
314 if (! TuiInit())
315 {
316 ConsInitialized = FALSE;
317 return STATUS_UNSUCCESSFUL;
318 }
319 }
320
321 Console->Vtbl = &TuiVtbl;
322 Console->hWindow = NULL;
323 Console->Size = PhysicalConsoleSize;
324 Console->ActiveBuffer->MaxX = PhysicalConsoleSize.X;
325 Console->ActiveBuffer->MaxY = PhysicalConsoleSize.Y;
326
327 ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) TuiConsoleThread,
328 Console, 0, NULL);
329 if (NULL == ThreadHandle)
330 {
331 DPRINT1("CSR: Unable to create console thread\n");
332 return STATUS_UNSUCCESSFUL;
333 }
334 CloseHandle(ThreadHandle);
335
336 EnterCriticalSection(&ActiveConsoleLock);
337 if (NULL != ActiveConsole)
338 {
339 Console->Prev = ActiveConsole;
340 Console->Next = ActiveConsole->Next;
341 ActiveConsole->Next->Prev = Console;
342 ActiveConsole->Next = Console;
343 }
344 else
345 {
346 Console->Prev = Console;
347 Console->Next = Console;
348 }
349 ActiveConsole = Console;
350 LeaveCriticalSection(&ActiveConsoleLock);
351
352 return STATUS_SUCCESS;
353 }
354
355 PCSRSS_CONSOLE FASTCALL
356 TuiGetFocusConsole(VOID)
357 {
358 return ActiveConsole;
359 }
360
361 BOOL FASTCALL
362 TuiSwapConsole(int Next)
363 {
364 static PCSRSS_CONSOLE SwapConsole = NULL; /* console we are thinking about swapping with */
365 DWORD BytesReturned;
366 ANSI_STRING Title;
367 void * Buffer;
368 COORD *pos;
369
370 if (0 != Next)
371 {
372 /* alt-tab, swap consoles */
373 /* move SwapConsole to next console, and print its title */
374 EnterCriticalSection(&ActiveConsoleLock);
375 if (! SwapConsole)
376 {
377 SwapConsole = ActiveConsole;
378 }
379
380 SwapConsole = (0 < Next ? SwapConsole->Next : SwapConsole->Prev);
381 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Title);
382 Title.Length = 0;
383 Buffer = HeapAlloc(Win32CsrApiHeap,
384 0,
385 sizeof(COORD) + Title.MaximumLength);
386 pos = (COORD *)Buffer;
387 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof( COORD ));
388
389 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
390 pos->Y = PhysicalConsoleSize.Y / 2;
391 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
392 /* redraw the console to clear off old title */
393 ConioDrawConsole(ActiveConsole);
394 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
395 NULL, 0, Buffer, sizeof(COORD) + Title.Length,
396 &BytesReturned, NULL))
397 {
398 DPRINT1( "Error writing to console\n" );
399 }
400 HeapFree(Win32CsrApiHeap, 0, Buffer);
401 LeaveCriticalSection(&ActiveConsoleLock);
402
403 return TRUE;
404 }
405 else if (NULL != SwapConsole)
406 {
407 EnterCriticalSection(&ActiveConsoleLock);
408 if (SwapConsole != ActiveConsole)
409 {
410 /* first remove swapconsole from the list */
411 SwapConsole->Prev->Next = SwapConsole->Next;
412 SwapConsole->Next->Prev = SwapConsole->Prev;
413 /* now insert before activeconsole */
414 SwapConsole->Next = ActiveConsole;
415 SwapConsole->Prev = ActiveConsole->Prev;
416 ActiveConsole->Prev->Next = SwapConsole;
417 ActiveConsole->Prev = SwapConsole;
418 }
419 ActiveConsole = SwapConsole;
420 SwapConsole = NULL;
421 ConioDrawConsole(ActiveConsole);
422 LeaveCriticalSection(&ActiveConsoleLock);
423 return TRUE;
424 }
425 else
426 {
427 return FALSE;
428 }
429 }
430
431 /* EOF */