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         /* 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 PCONSOLE Console,
81                          IN HANDLE ProcessHandle OPTIONAL,
82                          IN ULONG BufferType,
83                          IN PVOID ScreenBufferInfo)
84 {
85     NTSTATUS Status = STATUS_SUCCESS;
86 
87     if ( Console == NULL || Buffer == NULL ||
88         (BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) )
89     {
90         return STATUS_INVALID_PARAMETER;
91     }
92 
93     /* Use the current process if ProcessHandle is NULL */
94     if (ProcessHandle == NULL)
95         ProcessHandle = NtCurrentProcess();
96 
97     if (BufferType == CONSOLE_TEXTMODE_BUFFER)
98     {
99         Status = TEXTMODE_BUFFER_Initialize(Buffer, Console, ProcessHandle,
100                                             (PTEXTMODE_BUFFER_INFO)ScreenBufferInfo);
101     }
102     else if (BufferType == CONSOLE_GRAPHICS_BUFFER)
103     {
104         Status = GRAPHICS_BUFFER_Initialize(Buffer, Console, ProcessHandle,
105                                             (PGRAPHICS_BUFFER_INFO)ScreenBufferInfo);
106     }
107     else
108     {
109         /* Never ever go there!! */
110         ASSERT(FALSE);
111     }
112 
113     /* Insert the newly created screen buffer into the list, if succeeded */
114     if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
115 
116     return Status;
117 }
118 
119 static VOID
120 ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
121 
122 VOID NTAPI
123 ConDrvDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
124 {
125     PCONSOLE Console = Buffer->Header.Console;
126     PCONSOLE_SCREEN_BUFFER NewBuffer;
127 
128     /*
129      * We should notify temporarily the frontend because we are susceptible
130      * to delete the screen buffer it is using (which may be different from
131      * the active screen buffer in some cases), and because, if it actually
132      * uses the active screen buffer, we are going to nullify its pointer to
133      * change it.
134      */
135     TermReleaseScreenBuffer(Console, Buffer);
136 
137     RemoveEntryList(&Buffer->ListEntry);
138     if (Buffer == Console->ActiveBuffer)
139     {
140         /* Delete active buffer; switch to most recently created */
141         if (!IsListEmpty(&Console->BufferList))
142         {
143             NewBuffer = CONTAINING_RECORD(Console->BufferList.Flink,
144                                           CONSOLE_SCREEN_BUFFER,
145                                           ListEntry);
146 
147             /* Tie console to new buffer and signal the change to the frontend */
148             ConioSetActiveScreenBuffer(NewBuffer);
149         }
150         else
151         {
152             Console->ActiveBuffer = NULL;
153             // InterlockedExchangePointer(&Console->ActiveBuffer, NULL);
154         }
155     }
156 
157     CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
158 }
159 
160 static VOID
161 ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
162 {
163     PCONSOLE Console = Buffer->Header.Console;
164     Console->ActiveBuffer = Buffer;
165     // InterlockedExchangePointer(&Console->ActiveBuffer, Buffer);
166     TermSetActiveScreenBuffer(Console);
167 }
168 
169 NTSTATUS NTAPI
170 ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
171                                    IN PCONSOLE_SCREEN_BUFFER Buffer)
172 {
173     if (Console == NULL || Buffer == NULL)
174         return STATUS_INVALID_PARAMETER;
175 
176     /* Validity check */
177     ASSERT(Console == Buffer->Header.Console);
178 
179     if (Buffer == Console->ActiveBuffer) return STATUS_SUCCESS;
180 
181     /* If old buffer has no handles, it's now unreferenced */
182     if (Console->ActiveBuffer->Header.ReferenceCount == 0)
183     {
184         ConDrvDeleteScreenBuffer(Console->ActiveBuffer);
185     }
186 
187     /* Tie console to new buffer and signal the change to the frontend */
188     ConioSetActiveScreenBuffer(Buffer);
189 
190     return STATUS_SUCCESS;
191 }
192 
193 PCONSOLE_SCREEN_BUFFER
194 ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
195 {
196     return (Console ? Console->ActiveBuffer : NULL);
197 }
198 
199 /* PUBLIC DRIVER APIS *********************************************************/
200 
201 NTSTATUS NTAPI
202 ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
203                            IN PCONSOLE_SCREEN_BUFFER Buffer,
204                            IN PSMALL_RECT Region)
205 {
206     if (Console == NULL || Buffer == NULL || Region == NULL)
207         return STATUS_INVALID_PARAMETER;
208 
209     /* Validity check */
210     ASSERT(Console == Buffer->Header.Console);
211 
212     /* If the output buffer is the current one, redraw the correct portion of the screen */
213     if (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region);
214 
215     return STATUS_SUCCESS;
216 }
217 
218 NTSTATUS NTAPI
219 ConDrvSetConsolePalette(IN PCONSOLE Console,
220                         // IN PGRAPHICS_SCREEN_BUFFER Buffer,
221                         IN PCONSOLE_SCREEN_BUFFER Buffer,
222                         IN HPALETTE PaletteHandle,
223                         IN UINT PaletteUsage)
224 {
225     BOOL Success;
226 
227     /*
228      * Parameters validation
229      */
230     if (Console == NULL || Buffer == NULL)
231         return STATUS_INVALID_PARAMETER;
232 
233     if ( PaletteUsage != SYSPAL_STATIC   &&
234          PaletteUsage != SYSPAL_NOSTATIC &&
235          PaletteUsage != SYSPAL_NOSTATIC256 )
236     {
237         return STATUS_INVALID_PARAMETER;
238     }
239 
240     /* Validity check */
241     ASSERT(Console == Buffer->Header.Console);
242 
243     /* Change the palette */
244     Success = TermSetPalette(Console, PaletteHandle, PaletteUsage);
245     if (Success)
246     {
247         /* Free the old palette handle if there was already one set */
248         if ( Buffer->PaletteHandle != NULL &&
249              Buffer->PaletteHandle != PaletteHandle )
250         {
251             DeleteObject(Buffer->PaletteHandle);
252         }
253 
254         /* Save the new palette in the screen buffer */
255         Buffer->PaletteHandle = PaletteHandle;
256         Buffer->PaletteUsage  = PaletteUsage;
257     }
258 
259     return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
260 }
261 
262 NTSTATUS NTAPI
263 ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
264                            IN PTEXTMODE_SCREEN_BUFFER Buffer,
265                            OUT PCONSOLE_CURSOR_INFO CursorInfo)
266 {
267     if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
268         return STATUS_INVALID_PARAMETER;
269 
270     /* Validity check */
271     ASSERT(Console == Buffer->Header.Console);
272 
273     *CursorInfo = Buffer->CursorInfo;
274     // CursorInfo->bVisible = Buffer->CursorInfo.bVisible;
275     // CursorInfo->dwSize   = Buffer->CursorInfo.dwSize;
276 
277     return STATUS_SUCCESS;
278 }
279 
280 NTSTATUS NTAPI
281 ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
282                            IN PTEXTMODE_SCREEN_BUFFER Buffer,
283                            IN PCONSOLE_CURSOR_INFO CursorInfo)
284 {
285     ULONG Size;
286     BOOLEAN Visible, Success = TRUE;
287 
288     if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
289         return STATUS_INVALID_PARAMETER;
290 
291     /* Validity check */
292     ASSERT(Console == Buffer->Header.Console);
293 
294     Size    = min(max(CursorInfo->dwSize, 1), 100);
295     Visible = CursorInfo->bVisible;
296 
297     if ( (Size != Buffer->CursorInfo.dwSize)         ||
298          (Visible && !Buffer->CursorInfo.bVisible)   ||
299          (!Visible && Buffer->CursorInfo.bVisible) )
300     {
301         Buffer->CursorInfo.dwSize   = Size;
302         Buffer->CursorInfo.bVisible = Visible;
303 
304         Success = TermSetCursorInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer);
305     }
306 
307     return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
308 }
309 
310 NTSTATUS NTAPI
311 ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
312                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
313                                IN PCOORD Position)
314 {
315     SHORT OldCursorX, OldCursorY;
316 
317     if (Console == NULL || Buffer == NULL || Position == NULL)
318         return STATUS_INVALID_PARAMETER;
319 
320     /* Validity check */
321     ASSERT(Console == Buffer->Header.Console);
322 
323     if ( Position->X < 0 || Position->X >= Buffer->ScreenBufferSize.X ||
324          Position->Y < 0 || Position->Y >= Buffer->ScreenBufferSize.Y )
325     {
326         return STATUS_INVALID_PARAMETER;
327     }
328 
329     OldCursorX = Buffer->CursorPosition.X;
330     OldCursorY = Buffer->CursorPosition.Y;
331     Buffer->CursorPosition = *Position;
332     // Buffer->CursorPosition.X = Position->X;
333     // Buffer->CursorPosition.Y = Position->Y;
334     if ( ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer) &&
335          (!TermSetScreenInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer, OldCursorX, OldCursorY)) )
336     {
337         return STATUS_UNSUCCESSFUL;
338     }
339 
340     return STATUS_SUCCESS;
341 }
342 
343 /* EOF */
344