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