2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Gé van Geldorp
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
21 /* GLOBALS ********************************************************************/
23 static ULONG CurrentConsoleID
= 0;
25 /* Linked list of consoles */
26 static LIST_ENTRY ConsoleList
;
27 static RTL_RESOURCE ListLock
;
29 #define ConDrvLockConsoleListExclusive() \
30 RtlAcquireResourceExclusive(&ListLock, TRUE)
32 #define ConDrvLockConsoleListShared() \
33 RtlAcquireResourceShared(&ListLock, TRUE)
35 #define ConDrvUnlockConsoleList() \
36 RtlReleaseResource(&ListLock)
40 InsertConsole(IN PCONSOLE Console
)
44 /* All went right, so add the console to the list */
45 ConDrvLockConsoleListExclusive();
47 DPRINT1("Insert in the list\n");
48 InsertTailList(&ConsoleList
, &Console
->ListEntry
);
50 // FIXME: Move this code to the caller function!!
51 /* Get a new console ID */
52 _InterlockedExchange((PLONG
)&Console
->ConsoleID
, CurrentConsoleID
);
53 _InterlockedIncrement((PLONG
)&CurrentConsoleID
);
55 /* Unlock the console list and return success */
56 ConDrvUnlockConsoleList();
57 return STATUS_SUCCESS
;
61 RemoveConsole(IN PCONSOLE Console
)
64 if (!Console
) return STATUS_INVALID_PARAMETER
;
66 /* Remove the console from the list */
67 ConDrvLockConsoleListExclusive();
69 RemoveEntryList(&Console
->ListEntry
);
71 /* Unlock the console list and return success */
72 ConDrvUnlockConsoleList();
73 return STATUS_SUCCESS
;
77 /* PRIVATE FUNCTIONS **********************************************************/
80 ConDrvPause(PCONSOLE Console
)
82 if (!Console
->UnpauseEvent
)
83 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
87 ConDrvUnpause(PCONSOLE Console
)
89 if (Console
->UnpauseEvent
)
91 SetEvent(Console
->UnpauseEvent
);
92 CloseHandle(Console
->UnpauseEvent
);
93 Console
->UnpauseEvent
= NULL
;
99 * Console accessibility check helpers
103 ConDrvValidateConsoleState(IN PCONSOLE Console
,
104 IN CONSOLE_STATE ExpectedState
)
106 // if (!Console) return FALSE;
108 /* The console must be locked */
109 // ASSERT(Console_locked);
111 return (Console
->State
== ExpectedState
);
115 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console
,
116 IN CONSOLE_STATE ExpectedState
,
117 IN BOOLEAN LockConsole
)
119 if (!Console
) return FALSE
;
122 * Lock the console to forbid possible console's state changes
123 * (which must be done when the console is already locked).
124 * If we don't want to lock it, it's because the lock is already
125 * held. So there must be no problems.
127 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
129 // ASSERT(Console_locked);
131 /* Check whether the console's state is what we expect */
132 if (!ConDrvValidateConsoleState(Console
, ExpectedState
))
134 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
142 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
145 ConDrvInitConsoleSupport(VOID
)
147 DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
149 /* Initialize the console list and its lock */
150 InitializeListHead(&ConsoleList
);
151 RtlInitializeResource(&ListLock
);
153 /* Should call LoadKeyboardLayout */
156 /* For resetting the terminal - defined in dummyterm.c */
157 VOID
ResetTerminal(IN PCONSOLE Console
);
160 ConDrvInitConsole(OUT PCONSOLE
* NewConsole
,
161 IN PCONSOLE_INFO ConsoleInfo
)
164 // CONSOLE_INFO CapturedConsoleInfo;
165 TEXTMODE_BUFFER_INFO ScreenBufferInfo
;
167 PCONSOLE_SCREEN_BUFFER NewBuffer
;
169 if (NewConsole
== NULL
|| ConsoleInfo
== NULL
)
170 return STATUS_INVALID_PARAMETER
;
175 * Allocate a new console
177 Console
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(*Console
));
180 DPRINT1("Not enough memory for console creation.\n");
181 return STATUS_NO_MEMORY
;
185 * Fix the screen buffer size if needed. The rule is:
186 * ScreenBufferSize >= ConsoleSize
188 if (ConsoleInfo
->ScreenBufferSize
.X
< ConsoleInfo
->ConsoleSize
.X
)
189 ConsoleInfo
->ScreenBufferSize
.X
= ConsoleInfo
->ConsoleSize
.X
;
190 if (ConsoleInfo
->ScreenBufferSize
.Y
< ConsoleInfo
->ConsoleSize
.Y
)
191 ConsoleInfo
->ScreenBufferSize
.Y
= ConsoleInfo
->ConsoleSize
.Y
;
194 * Initialize the console
196 Console
->State
= CONSOLE_INITIALIZING
;
197 Console
->ReferenceCount
= 0;
198 InitializeCriticalSection(&Console
->Lock
);
200 /* Initialize the terminal interface */
201 ResetTerminal(Console
);
203 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
204 Console
->FixedSize
= FALSE
; // Value by default; is reseted by the terminals if needed.
206 /* Initialize the input buffer */
207 Status
= ConDrvInitInputBuffer(Console
, 0 /* ConsoleInfo->InputBufferSize */);
208 if (!NT_SUCCESS(Status
))
210 DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status
);
211 DeleteCriticalSection(&Console
->Lock
);
212 ConsoleFreeHeap(Console
);
216 /* Set-up the code page */
217 Console
->InputCodePage
= Console
->OutputCodePage
= ConsoleInfo
->CodePage
;
219 /* Initialize a new text-mode screen buffer with default settings */
220 ScreenBufferInfo
.ScreenBufferSize
= ConsoleInfo
->ScreenBufferSize
;
221 ScreenBufferInfo
.ScreenAttrib
= ConsoleInfo
->ScreenAttrib
;
222 ScreenBufferInfo
.PopupAttrib
= ConsoleInfo
->PopupAttrib
;
223 ScreenBufferInfo
.IsCursorVisible
= TRUE
;
224 ScreenBufferInfo
.CursorSize
= ConsoleInfo
->CursorSize
;
226 InitializeListHead(&Console
->BufferList
);
227 Status
= ConDrvCreateScreenBuffer(&NewBuffer
,
229 CONSOLE_TEXTMODE_BUFFER
,
231 if (!NT_SUCCESS(Status
))
233 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
234 ConDrvDeinitInputBuffer(Console
);
235 DeleteCriticalSection(&Console
->Lock
);
236 ConsoleFreeHeap(Console
);
239 /* Make the new screen buffer active */
240 Console
->ActiveBuffer
= NewBuffer
;
241 Console
->UnpauseEvent
= NULL
;
243 DPRINT("Console initialized\n");
245 /* All went right, so add the console to the list */
246 Status
= InsertConsole(Console
);
247 if (!NT_SUCCESS(Status
))
250 ConDrvDeleteConsole(Console
);
254 /* The initialization is finished */
255 DPRINT("Change state\n");
256 Console
->State
= CONSOLE_RUNNING
;
258 /* Return the newly created console to the caller and a success code too */
259 *NewConsole
= Console
;
260 return STATUS_SUCCESS
;
264 ConDrvRegisterTerminal(IN PCONSOLE Console
,
265 IN PTERMINAL Terminal
)
269 if (Console
== NULL
|| Terminal
== NULL
)
270 return STATUS_INVALID_PARAMETER
;
272 /* FIXME: Lock the console before ?? */
275 * Attach the terminal to the console. Use now the TermIFace of the console,
276 * and not the user-defined temporary Terminal pointer.
278 Console
->TermIFace
= *Terminal
;
279 Console
->TermIFace
.Console
= Console
;
281 /* Initialize the terminal AFTER having attached it to the console */
282 DPRINT("Finish initialization of terminal\n");
283 Status
= Console
->TermIFace
.Vtbl
->InitTerminal(&Console
->TermIFace
, Console
);
284 if (!NT_SUCCESS(Status
))
286 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status
);
288 /* We failed, detach the terminal from the console */
289 Terminal
->Console
= NULL
; // For the caller
290 ResetTerminal(Console
);
295 /* Copy buffer contents to screen */
297 // ConioDrawConsole(Console);
298 DPRINT("Console drawn\n");
300 DPRINT("Terminal initialization done\n");
301 return STATUS_SUCCESS
;
305 ConDrvDeregisterTerminal(IN PCONSOLE Console
)
307 if (Console
== NULL
) return STATUS_INVALID_PARAMETER
;
309 /* FIXME: Lock the console before ?? */
311 /* Deinitialize the terminal BEFORE detaching it from the console */
312 Console
->TermIFace
.Vtbl
->DeinitTerminal(&Console
->TermIFace
/*, Console*/);
315 * Detach the terminal from the console:
316 * reinitialize the terminal interface.
318 ResetTerminal(Console
);
320 DPRINT("Terminal unregistered\n");
321 return STATUS_SUCCESS
;
325 ConDrvDeleteConsole(IN PCONSOLE Console
)
327 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console
);
330 * Forbid validation of any console by other threads
331 * during the deletion of this console.
333 ConDrvLockConsoleListExclusive();
336 * If the console is already being destroyed, i.e. not running
337 * or finishing to be initialized, just return.
339 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
) &&
340 !ConDrvValidateConsoleUnsafe(Console
, CONSOLE_INITIALIZING
, TRUE
))
342 /* Unlock the console list and return */
343 ConDrvUnlockConsoleList();
348 * We are about to be destroyed. Signal it to other people
349 * so that they can terminate what they are doing, and that
350 * they cannot longer validate the console.
352 Console
->State
= CONSOLE_TERMINATING
;
355 * Allow other threads to finish their job: basically, unlock
356 * all other calls to EnterCriticalSection(&Console->Lock); by
357 * ConDrvValidateConsoleUnsafe functions so that they just see
358 * that we are not in CONSOLE_RUNNING state anymore, or unlock
359 * other concurrent calls to ConDrvDeleteConsole so that they
360 * can see that we are in fact already deleting the console.
362 LeaveCriticalSection(&Console
->Lock
);
363 ConDrvUnlockConsoleList();
365 /* FIXME: Send a terminate message to all the processes owning this console */
367 /* Deregister the terminal */
368 DPRINT("Deregister terminal\n");
369 ConDrvDeregisterTerminal(Console
);
370 DPRINT("Terminal deregistered\n");
373 * Check that the console is in terminating state before continuing
374 * (the cleanup code must not change the state of the console...
375 * ...unless to cancel console deletion ?).
378 ConDrvLockConsoleListExclusive();
380 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
382 ConDrvUnlockConsoleList();
386 /* We are now in destruction */
387 Console
->State
= CONSOLE_IN_DESTRUCTION
;
389 /* We really delete the console. Reset the count to be sure. */
390 Console
->ReferenceCount
= 0;
392 /* Remove the console from the list */
393 RemoveConsole(Console
);
395 /* Delete the last screen buffer */
396 ConDrvDeleteScreenBuffer(Console
->ActiveBuffer
);
397 Console
->ActiveBuffer
= NULL
;
398 if (!IsListEmpty(&Console
->BufferList
))
400 /***ConDrvUnlockConsoleList();***/
401 ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE
);
404 /* Deinitialize the input buffer */
405 ConDrvDeinitInputBuffer(Console
);
407 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
409 DPRINT("ConDrvDeleteConsole - Unlocking\n");
410 LeaveCriticalSection(&Console
->Lock
);
411 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
412 DeleteCriticalSection(&Console
->Lock
);
413 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
415 ConsoleFreeHeap(Console
);
416 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
418 /* Unlock the console list and return */
419 ConDrvUnlockConsoleList();
423 /* PUBLIC DRIVER APIS *********************************************************/
426 ConDrvGetConsoleMode(IN PCONSOLE Console
,
427 IN PCONSOLE_IO_OBJECT Object
,
428 OUT PULONG ConsoleMode
)
430 NTSTATUS Status
= STATUS_SUCCESS
;
432 if (Console
== NULL
|| Object
== NULL
|| ConsoleMode
== NULL
)
433 return STATUS_INVALID_PARAMETER
;
436 ASSERT(Console
== Object
->Console
);
438 /*** FIXME: */ *ConsoleMode
= 0; /***/
440 if (INPUT_BUFFER
== Object
->Type
)
442 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
443 *ConsoleMode
= InputBuffer
->Mode
;
445 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
447 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
448 *ConsoleMode
= Buffer
->Mode
;
452 Status
= STATUS_INVALID_HANDLE
;
459 ConDrvSetConsoleMode(IN PCONSOLE Console
,
460 IN PCONSOLE_IO_OBJECT Object
,
461 IN ULONG ConsoleMode
)
463 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
464 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
466 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
468 NTSTATUS Status
= STATUS_SUCCESS
;
470 if (Console
== NULL
|| Object
== NULL
)
471 return STATUS_INVALID_PARAMETER
;
474 ASSERT(Console
== Object
->Console
);
476 if (INPUT_BUFFER
== Object
->Type
)
478 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
480 /* Only the presence of valid mode flags is allowed */
481 if (ConsoleMode
& ~CONSOLE_VALID_INPUT_MODES
)
483 Status
= STATUS_INVALID_PARAMETER
;
487 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
490 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
492 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
494 /* Only the presence of valid mode flags is allowed */
495 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
497 Status
= STATUS_INVALID_PARAMETER
;
501 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
506 Status
= STATUS_INVALID_HANDLE
;
513 ConDrvGetConsoleCP(IN PCONSOLE Console
,
517 if (Console
== NULL
|| CodePage
== NULL
)
518 return STATUS_INVALID_PARAMETER
;
520 *CodePage
= (OutputCP
? Console
->OutputCodePage
: Console
->InputCodePage
);
522 return STATUS_SUCCESS
;
526 ConDrvSetConsoleCP(IN PCONSOLE Console
,
530 if (Console
== NULL
|| !IsValidCodePage(CodePage
))
531 return STATUS_INVALID_PARAMETER
;
534 Console
->OutputCodePage
= CodePage
;
536 Console
->InputCodePage
= CodePage
;
538 return STATUS_SUCCESS
;