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