06a7da9d656a018c2364192948d7463293d10b7b
[reactos.git] / win32ss / user / winsrv / consrv / condrv / conoutput.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/conoutput.c
5 * PURPOSE: General Console Output Functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* PRIVATE FUNCTIONS **********************************************************/
18
19 NTSTATUS
20 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
21 IN PCONSOLE Console,
22 IN HANDLE ProcessHandle,
23 IN PTEXTMODE_BUFFER_INFO TextModeInfo);
24 NTSTATUS
25 GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
26 IN PCONSOLE Console,
27 IN HANDLE ProcessHandle,
28 IN PGRAPHICS_BUFFER_INFO GraphicsInfo);
29
30 VOID
31 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
32 VOID
33 GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
34
35
36 NTSTATUS
37 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
38 IN PCONSOLE Console,
39 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl,
40 IN SIZE_T Size)
41 {
42 if (Buffer == NULL || Console == NULL)
43 return STATUS_INVALID_PARAMETER;
44
45 *Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, max(sizeof(CONSOLE_SCREEN_BUFFER), Size));
46 if (*Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES;
47
48 /* Initialize the header with the default type */
49 ConSrvInitObject(&(*Buffer)->Header, SCREEN_BUFFER, Console);
50 (*Buffer)->Vtbl = Vtbl;
51 return STATUS_SUCCESS;
52 }
53
54 VOID
55 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
56 {
57 if (Buffer->Header.Type == TEXTMODE_BUFFER)
58 {
59 TEXTMODE_BUFFER_Destroy(Buffer);
60 }
61 else if (Buffer->Header.Type == GRAPHICS_BUFFER)
62 {
63 GRAPHICS_BUFFER_Destroy(Buffer);
64 }
65 else if (Buffer->Header.Type == SCREEN_BUFFER)
66 {
67 // TODO: Free Buffer->Data
68
69 /* Free the palette handle */
70 if (Buffer->PaletteHandle != NULL) DeleteObject(Buffer->PaletteHandle);
71
72 /* Free the screen buffer memory */
73 ConsoleFreeHeap(Buffer);
74 }
75 // else
76 // do_nothing;
77 }
78
79 // ConDrvCreateConsoleScreenBuffer
80 NTSTATUS
81 ConDrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
82 IN PCONSOLE Console,
83 IN HANDLE ProcessHandle OPTIONAL,
84 IN ULONG BufferType,
85 IN PVOID ScreenBufferInfo)
86 {
87 NTSTATUS Status = STATUS_SUCCESS;
88
89 if ( Console == NULL || Buffer == NULL ||
90 (BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) )
91 {
92 return STATUS_INVALID_PARAMETER;
93 }
94
95 /* Use the current process if ProcessHandle is NULL */
96 if (ProcessHandle == NULL)
97 ProcessHandle = NtCurrentProcess();
98
99 if (BufferType == CONSOLE_TEXTMODE_BUFFER)
100 {
101 Status = TEXTMODE_BUFFER_Initialize(Buffer, Console, ProcessHandle,
102 (PTEXTMODE_BUFFER_INFO)ScreenBufferInfo);
103 }
104 else if (BufferType == CONSOLE_GRAPHICS_BUFFER)
105 {
106 Status = GRAPHICS_BUFFER_Initialize(Buffer, Console, ProcessHandle,
107 (PGRAPHICS_BUFFER_INFO)ScreenBufferInfo);
108 }
109 else
110 {
111 /* Never ever go there!! */
112 ASSERT(FALSE);
113 }
114
115 /* Insert the newly created screen buffer into the list, if succeeded */
116 if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
117
118 return Status;
119 }
120
121 static VOID
122 ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
123
124 VOID NTAPI
125 ConDrvDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
126 {
127 PCONSOLE Console = Buffer->Header.Console;
128 PCONSOLE_SCREEN_BUFFER NewBuffer;
129
130 /*
131 * We should notify temporarily the frontend because we are susceptible
132 * to delete the screen buffer it is using (which may be different from
133 * the active screen buffer in some cases), and because, if it actually
134 * uses the active screen buffer, we are going to nullify its pointer to
135 * change it.
136 */
137 TermReleaseScreenBuffer(Console, Buffer);
138
139 RemoveEntryList(&Buffer->ListEntry);
140 if (Buffer == Console->ActiveBuffer)
141 {
142 /* Delete active buffer; switch to most recently created */
143 if (!IsListEmpty(&Console->BufferList))
144 {
145 NewBuffer = CONTAINING_RECORD(Console->BufferList.Flink,
146 CONSOLE_SCREEN_BUFFER,
147 ListEntry);
148
149 /* Tie console to new buffer and signal the change to the frontend */
150 ConioSetActiveScreenBuffer(NewBuffer);
151 }
152 else
153 {
154 Console->ActiveBuffer = NULL;
155 // InterlockedExchangePointer(&Console->ActiveBuffer, NULL);
156 }
157 }
158
159 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
160 }
161
162 VOID
163 ConioDrawConsole(PCONSOLE Console)
164 {
165 SMALL_RECT Region;
166 PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
167
168 if (ActiveBuffer)
169 {
170 ConioInitRect(&Region, 0, 0,
171 ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1);
172 TermDrawRegion(Console, &Region);
173 }
174 }
175
176 static VOID
177 ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
178 {
179 PCONSOLE Console = Buffer->Header.Console;
180 Console->ActiveBuffer = Buffer;
181 // InterlockedExchangePointer(&Console->ActiveBuffer, Buffer);
182 TermSetActiveScreenBuffer(Console);
183 }
184
185 NTSTATUS NTAPI
186 ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
187 IN PCONSOLE_SCREEN_BUFFER Buffer)
188 {
189 if (Console == NULL || Buffer == NULL)
190 return STATUS_INVALID_PARAMETER;
191
192 /* Validity check */
193 ASSERT(Console == Buffer->Header.Console);
194
195 if (Buffer == Console->ActiveBuffer) return STATUS_SUCCESS;
196
197 /* If old buffer has no handles, it's now unreferenced */
198 if (Console->ActiveBuffer->Header.ReferenceCount == 0)
199 {
200 ConDrvDeleteScreenBuffer(Console->ActiveBuffer);
201 }
202
203 /* Tie console to new buffer and signal the change to the frontend */
204 ConioSetActiveScreenBuffer(Buffer);
205
206 return STATUS_SUCCESS;
207 }
208
209 PCONSOLE_SCREEN_BUFFER
210 ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
211 {
212 return (Console ? Console->ActiveBuffer : NULL);
213 }
214
215 /* PUBLIC DRIVER APIS *********************************************************/
216
217 NTSTATUS NTAPI
218 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
219 IN PTEXTMODE_SCREEN_BUFFER Buffer,
220 IN PCHAR_CELL CharInfo/*Buffer*/,
221 IN COORD CharInfoSize,
222 IN OUT PSMALL_RECT WriteRegion,
223 IN BOOLEAN DrawRegion);
224 NTSTATUS NTAPI
225 ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
226 IN PCONSOLE_SCREEN_BUFFER Buffer,
227 IN PSMALL_RECT Region)
228 {
229 if (Console == NULL || Buffer == NULL || Region == NULL)
230 return STATUS_INVALID_PARAMETER;
231
232 /* Validity check */
233 ASSERT(Console == Buffer->Header.Console);
234
235 /* In text-mode only, draw the VDM buffer if present */
236 if (GetType(Buffer) == TEXTMODE_BUFFER)
237 {
238 PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
239
240 /*Status =*/ ConDrvWriteConsoleOutputVDM(Buffer->Header.Console,
241 TextBuffer,
242 Console->VDMBuffer,
243 Console->VDMBufferSize,
244 Region,
245 FALSE);
246 }
247
248 /* If the output buffer is the current one, redraw the correct portion of the screen */
249 if (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region);
250
251 return STATUS_SUCCESS;
252 }
253
254 NTSTATUS NTAPI
255 ConDrvSetConsolePalette(IN PCONSOLE Console,
256 // IN PGRAPHICS_SCREEN_BUFFER Buffer,
257 IN PCONSOLE_SCREEN_BUFFER Buffer,
258 IN HPALETTE PaletteHandle,
259 IN UINT PaletteUsage)
260 {
261 BOOL Success;
262
263 /*
264 * Parameters validation
265 */
266 if (Console == NULL || Buffer == NULL)
267 return STATUS_INVALID_PARAMETER;
268
269 if ( PaletteUsage != SYSPAL_STATIC &&
270 PaletteUsage != SYSPAL_NOSTATIC &&
271 PaletteUsage != SYSPAL_NOSTATIC256 )
272 {
273 return STATUS_INVALID_PARAMETER;
274 }
275
276 /* Validity check */
277 ASSERT(Console == Buffer->Header.Console);
278
279 /* Change the palette */
280 Success = TermSetPalette(Console, PaletteHandle, PaletteUsage);
281 if (Success)
282 {
283 /* Free the old palette handle if there was already one set */
284 if ( Buffer->PaletteHandle != NULL &&
285 Buffer->PaletteHandle != PaletteHandle )
286 {
287 DeleteObject(Buffer->PaletteHandle);
288 }
289
290 /* Save the new palette in the screen buffer */
291 Buffer->PaletteHandle = PaletteHandle;
292 Buffer->PaletteUsage = PaletteUsage;
293 }
294
295 return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
296 }
297
298 NTSTATUS NTAPI
299 ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
300 IN PTEXTMODE_SCREEN_BUFFER Buffer,
301 OUT PCONSOLE_CURSOR_INFO CursorInfo)
302 {
303 if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
304 return STATUS_INVALID_PARAMETER;
305
306 /* Validity check */
307 ASSERT(Console == Buffer->Header.Console);
308
309 *CursorInfo = Buffer->CursorInfo;
310 // CursorInfo->bVisible = Buffer->CursorInfo.bVisible;
311 // CursorInfo->dwSize = Buffer->CursorInfo.dwSize;
312
313 return STATUS_SUCCESS;
314 }
315
316 NTSTATUS NTAPI
317 ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
318 IN PTEXTMODE_SCREEN_BUFFER Buffer,
319 IN PCONSOLE_CURSOR_INFO CursorInfo)
320 {
321 ULONG Size;
322 BOOLEAN Visible, Success = TRUE;
323
324 if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
325 return STATUS_INVALID_PARAMETER;
326
327 /* Validity check */
328 ASSERT(Console == Buffer->Header.Console);
329
330 Size = min(max(CursorInfo->dwSize, 1), 100);
331 Visible = CursorInfo->bVisible;
332
333 if ( (Size != Buffer->CursorInfo.dwSize) ||
334 (Visible && !Buffer->CursorInfo.bVisible) ||
335 (!Visible && Buffer->CursorInfo.bVisible) )
336 {
337 Buffer->CursorInfo.dwSize = Size;
338 Buffer->CursorInfo.bVisible = Visible;
339
340 Success = TermSetCursorInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer);
341 }
342
343 return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
344 }
345
346 NTSTATUS NTAPI
347 ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
348 IN PTEXTMODE_SCREEN_BUFFER Buffer,
349 IN PCOORD Position)
350 {
351 SHORT OldCursorX, OldCursorY;
352
353 if (Console == NULL || Buffer == NULL || Position == NULL)
354 return STATUS_INVALID_PARAMETER;
355
356 /* Validity check */
357 ASSERT(Console == Buffer->Header.Console);
358
359 if ( Position->X < 0 || Position->X >= Buffer->ScreenBufferSize.X ||
360 Position->Y < 0 || Position->Y >= Buffer->ScreenBufferSize.Y )
361 {
362 return STATUS_INVALID_PARAMETER;
363 }
364
365 OldCursorX = Buffer->CursorPosition.X;
366 OldCursorY = Buffer->CursorPosition.Y;
367 Buffer->CursorPosition = *Position;
368 // Buffer->CursorPosition.X = Position->X;
369 // Buffer->CursorPosition.Y = Position->Y;
370 if ( ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer) &&
371 (!TermSetScreenInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer, OldCursorX, OldCursorY)) )
372 {
373 return STATUS_UNSUCCESSFUL;
374 }
375
376 return STATUS_SUCCESS;
377 }
378
379 /* EOF */