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