- Don't use STATIC
[reactos.git] / reactos / subsys / 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 BOOL FASTCALL
22 TuiInit(VOID)
23 {
24 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
25 DWORD BytesReturned;
26
27 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", FILE_ALL_ACCESS, 0, NULL,
28 OPEN_EXISTING, 0, NULL);
29 if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
30 {
31 DPRINT1("Failed to open BlueScreen.\n");
32 return FALSE;
33 }
34
35 ActiveConsole = NULL;
36 InitializeCriticalSection(&ActiveConsoleLock);
37 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
38 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
39 {
40 DPRINT1("Failed to get console info\n");
41 return FALSE;
42 }
43 PhysicalConsoleSize = ScrInfo.dwSize;
44
45 return TRUE;
46 }
47
48 static VOID STDCALL
49 TuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
50 {
51 Buffer->DefaultAttrib = 0x17;
52 }
53
54 static void FASTCALL
55 TuiCopyRect(char *Dest, PCSRSS_SCREEN_BUFFER Buff, RECT *Region)
56 {
57 UINT SrcDelta, DestDelta;
58 LONG i;
59 PBYTE Src, SrcEnd;
60
61 Src = Buff->Buffer + (((Region->top + Buff->ShowY) % Buff->MaxY) * Buff->MaxX
62 + Region->left + Buff->ShowX) * 2;
63 SrcDelta = Buff->MaxX * 2;
64 SrcEnd = Buff->Buffer + Buff->MaxY * Buff->MaxX * 2;
65 DestDelta = ConioRectWidth(Region) * 2;
66 for (i = Region->top; i <= Region->bottom; i++)
67 {
68 memcpy(Dest, Src, DestDelta);
69 Src += SrcDelta;
70 if (SrcEnd <= Src)
71 {
72 Src -= Buff->MaxY * Buff->MaxX * 2;
73 }
74 Dest += DestDelta;
75 }
76 }
77
78 static VOID STDCALL
79 TuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
80 {
81 DWORD BytesReturned;
82 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
83 LONG CursorX, CursorY;
84 PCONSOLE_DRAW ConsoleDraw;
85 UINT ConsoleDrawSize;
86
87 if (ActiveConsole != Console)
88 {
89 return;
90 }
91
92 ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
93 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
94 ConsoleDraw = HeapAlloc(Win32CsrApiHeap, 0, ConsoleDrawSize);
95 if (NULL == ConsoleDraw)
96 {
97 DPRINT1("HeapAlloc failed\n");
98 return;
99 }
100 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &CursorX, &CursorY);
101 ConsoleDraw->X = Region->left;
102 ConsoleDraw->Y = Region->top;
103 ConsoleDraw->SizeX = ConioRectWidth(Region);
104 ConsoleDraw->SizeY = ConioRectHeight(Region);
105 ConsoleDraw->CursorX = CursorX;
106 ConsoleDraw->CursorY = CursorY;
107
108 TuiCopyRect((char *) (ConsoleDraw + 1), Buff, Region);
109
110 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
111 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
112 {
113 DPRINT1("Failed to draw console\n");
114 HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
115 return;
116 }
117
118 HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
119 }
120
121 static VOID STDCALL
122 TuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, LONG CursorStartX, LONG CursorStartY,
123 UINT ScrolledLines, CHAR *Buffer, UINT Length)
124 {
125 DWORD BytesWritten;
126 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
127
128 if (ActiveConsole->ActiveBuffer != Buff)
129 {
130 return;
131 }
132
133 if (! WriteFile(ConsoleDeviceHandle, Buffer, Length, &BytesWritten, NULL))
134 {
135 DPRINT1("Error writing to BlueScreen\n");
136 }
137 }
138
139 static BOOL STDCALL
140 TuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
141 {
142 DWORD BytesReturned;
143
144 if (ActiveConsole->ActiveBuffer != Buff)
145 {
146 return TRUE;
147 }
148
149 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
150 &Buff->CursorInfo, sizeof(Buff->CursorInfo), NULL, 0,
151 &BytesReturned, NULL))
152 {
153 DPRINT1( "Failed to set cursor info\n" );
154 return FALSE;
155 }
156
157 return TRUE;
158 }
159
160 static BOOL STDCALL
161 TuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
162 {
163 CONSOLE_SCREEN_BUFFER_INFO Info;
164 LONG CursorX, CursorY;
165 DWORD BytesReturned;
166
167 if (ActiveConsole->ActiveBuffer != Buff)
168 {
169 return TRUE;
170 }
171
172 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &CursorX, &CursorY);
173 Info.dwCursorPosition.X = CursorX;
174 Info.dwCursorPosition.Y = CursorY;
175 Info.wAttributes = Buff->DefaultAttrib;
176
177 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
178 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
179 &BytesReturned, NULL))
180 {
181 DPRINT1( "Failed to set cursor position\n" );
182 return FALSE;
183 }
184
185 return TRUE;
186 }
187
188 static BOOL STDCALL
189 TuiChangeTitle(PCSRSS_CONSOLE Console)
190 {
191 return TRUE;
192 }
193
194 static VOID STDCALL
195 TuiCleanupConsole(PCSRSS_CONSOLE Console)
196 {
197 EnterCriticalSection(&ActiveConsoleLock);
198
199 /* Switch to next console */
200 if (ActiveConsole == Console)
201 {
202 ActiveConsole = Console->Next != Console ? Console->Next : NULL;
203 }
204
205 if (Console->Next != Console)
206 {
207 Console->Prev->Next = Console->Next;
208 Console->Next->Prev = Console->Prev;
209 }
210 LeaveCriticalSection(&ActiveConsoleLock);
211
212 if (NULL != ActiveConsole)
213 {
214 ConioDrawConsole(ActiveConsole);
215 }
216 }
217
218 static CSRSS_CONSOLE_VTBL TuiVtbl =
219 {
220 TuiInitScreenBuffer,
221 TuiWriteStream,
222 TuiDrawRegion,
223 TuiSetCursorInfo,
224 TuiSetScreenInfo,
225 TuiChangeTitle,
226 TuiCleanupConsole
227 };
228
229 NTSTATUS FASTCALL
230 TuiInitConsole(PCSRSS_CONSOLE Console)
231 {
232 if (! ConsInitialized)
233 {
234 ConsInitialized = TRUE;
235 if (! TuiInit())
236 {
237 ConsInitialized = FALSE;
238 return STATUS_UNSUCCESSFUL;
239 }
240 }
241
242 Console->Vtbl = &TuiVtbl;
243 Console->hWindow = (HWND) NULL;
244 Console->Size = PhysicalConsoleSize;
245
246 EnterCriticalSection(&ActiveConsoleLock);
247 if (NULL != ActiveConsole)
248 {
249 Console->Prev = ActiveConsole;
250 Console->Next = ActiveConsole->Next;
251 ActiveConsole->Next->Prev = Console;
252 ActiveConsole->Next = Console;
253 }
254 else
255 {
256 Console->Prev = Console;
257 Console->Next = Console;
258 }
259 ActiveConsole = Console;
260 LeaveCriticalSection(&ActiveConsoleLock);
261
262 return STATUS_SUCCESS;
263 }
264
265 PCSRSS_CONSOLE FASTCALL
266 TuiGetFocusConsole(VOID)
267 {
268 return ActiveConsole;
269 }
270
271 BOOL FASTCALL
272 TuiSwapConsole(int Next)
273 {
274 static PCSRSS_CONSOLE SwapConsole = NULL; /* console we are thinking about swapping with */
275 DWORD BytesReturned;
276 ANSI_STRING Title;
277 void * Buffer;
278 COORD *pos;
279
280 if (0 != Next)
281 {
282 /* alt-tab, swap consoles */
283 /* move SwapConsole to next console, and print its title */
284 EnterCriticalSection(&ActiveConsoleLock);
285 if (! SwapConsole)
286 {
287 SwapConsole = ActiveConsole;
288 }
289
290 SwapConsole = (0 < Next ? SwapConsole->Next : SwapConsole->Prev);
291 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Title);
292 Title.Length = 0;
293 Buffer = HeapAlloc(Win32CsrApiHeap,
294 0,
295 sizeof(COORD) + Title.MaximumLength);
296 pos = (COORD *)Buffer;
297 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof( COORD ));
298
299 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
300 pos->Y = PhysicalConsoleSize.Y / 2;
301 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
302 /* redraw the console to clear off old title */
303 ConioDrawConsole(ActiveConsole);
304 if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
305 NULL, 0, Buffer, sizeof(COORD) + Title.Length,
306 &BytesReturned, NULL))
307 {
308 DPRINT1( "Error writing to console\n" );
309 }
310 HeapFree(Win32CsrApiHeap, 0, Buffer);
311 LeaveCriticalSection(&ActiveConsoleLock);
312
313 return TRUE;
314 }
315 else if (NULL != SwapConsole)
316 {
317 EnterCriticalSection(&ActiveConsoleLock);
318 if (SwapConsole != ActiveConsole)
319 {
320 /* first remove swapconsole from the list */
321 SwapConsole->Prev->Next = SwapConsole->Next;
322 SwapConsole->Next->Prev = SwapConsole->Prev;
323 /* now insert before activeconsole */
324 SwapConsole->Next = ActiveConsole;
325 SwapConsole->Prev = ActiveConsole->Prev;
326 ActiveConsole->Prev->Next = SwapConsole;
327 ActiveConsole->Prev = SwapConsole;
328 }
329 ActiveConsole = SwapConsole;
330 SwapConsole = NULL;
331 ConioDrawConsole(ActiveConsole);
332 LeaveCriticalSection(&ActiveConsoleLock);
333 return TRUE;
334 }
335 else
336 {
337 return FALSE;
338 }
339 }
340
341 /* EOF */