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 DPRINT("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
)
84 NtCreateEvent(&Console
->UnpauseEvent
, EVENT_ALL_ACCESS
,
85 NULL
, NotificationEvent
, FALSE
);
90 ConDrvUnpause(PCONSOLE Console
)
92 if (Console
->UnpauseEvent
)
94 NtSetEvent(Console
->UnpauseEvent
, NULL
);
95 NtClose(Console
->UnpauseEvent
);
96 Console
->UnpauseEvent
= NULL
;
102 * Console accessibility check helpers
106 ConDrvValidateConsoleState(IN PCONSOLE Console
,
107 IN CONSOLE_STATE ExpectedState
)
109 // if (!Console) return FALSE;
111 /* The console must be locked */
112 // ASSERT(Console_locked);
114 return (Console
->State
== ExpectedState
);
118 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console
,
119 IN CONSOLE_STATE ExpectedState
,
120 IN BOOLEAN LockConsole
)
122 if (!Console
) return FALSE
;
125 * Lock the console to forbid possible console's state changes
126 * (which must be done when the console is already locked).
127 * If we don't want to lock it, it's because the lock is already
128 * held. So there must be no problems.
130 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
132 // ASSERT(Console_locked);
134 /* Check whether the console's state is what we expect */
135 if (!ConDrvValidateConsoleState(Console
, ExpectedState
))
137 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
145 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
148 ConDrvInitConsoleSupport(VOID
)
150 DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
152 /* Initialize the console list and its lock */
153 InitializeListHead(&ConsoleList
);
154 RtlInitializeResource(&ListLock
);
156 /* Should call LoadKeyboardLayout */
159 /* For resetting the terminal - defined in dummyterm.c */
160 VOID
ResetTerminal(IN PCONSOLE Console
);
163 ConDrvInitConsole(OUT PCONSOLE
* NewConsole
,
164 IN PCONSOLE_INFO ConsoleInfo
)
167 // CONSOLE_INFO CapturedConsoleInfo;
168 TEXTMODE_BUFFER_INFO ScreenBufferInfo
;
170 PCONSOLE_SCREEN_BUFFER NewBuffer
;
172 if (NewConsole
== NULL
|| ConsoleInfo
== NULL
)
173 return STATUS_INVALID_PARAMETER
;
178 * Allocate a new console
180 Console
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(*Console
));
183 DPRINT1("Not enough memory for console creation.\n");
184 return STATUS_NO_MEMORY
;
188 * Fix the screen buffer size if needed. The rule is:
189 * ScreenBufferSize >= ConsoleSize
191 if (ConsoleInfo
->ScreenBufferSize
.X
< ConsoleInfo
->ConsoleSize
.X
)
192 ConsoleInfo
->ScreenBufferSize
.X
= ConsoleInfo
->ConsoleSize
.X
;
193 if (ConsoleInfo
->ScreenBufferSize
.Y
< ConsoleInfo
->ConsoleSize
.Y
)
194 ConsoleInfo
->ScreenBufferSize
.Y
= ConsoleInfo
->ConsoleSize
.Y
;
197 * Initialize the console
199 Console
->State
= CONSOLE_INITIALIZING
;
200 Console
->ReferenceCount
= 0;
201 InitializeCriticalSection(&Console
->Lock
);
203 /* Initialize the terminal interface */
204 ResetTerminal(Console
);
206 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
207 Console
->FixedSize
= FALSE
; // Value by default; is reseted by the terminals if needed.
209 /* Initialize the input buffer */
210 Status
= ConDrvInitInputBuffer(Console
, 0 /* ConsoleInfo->InputBufferSize */);
211 if (!NT_SUCCESS(Status
))
213 DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status
);
214 DeleteCriticalSection(&Console
->Lock
);
215 ConsoleFreeHeap(Console
);
219 /* Set-up the code page */
220 Console
->InputCodePage
= Console
->OutputCodePage
= ConsoleInfo
->CodePage
;
222 /* Initialize a new text-mode screen buffer with default settings */
223 ScreenBufferInfo
.ScreenBufferSize
= ConsoleInfo
->ScreenBufferSize
;
224 ScreenBufferInfo
.ScreenAttrib
= ConsoleInfo
->ScreenAttrib
;
225 ScreenBufferInfo
.PopupAttrib
= ConsoleInfo
->PopupAttrib
;
226 ScreenBufferInfo
.IsCursorVisible
= TRUE
;
227 ScreenBufferInfo
.CursorSize
= ConsoleInfo
->CursorSize
;
229 InitializeListHead(&Console
->BufferList
);
230 Status
= ConDrvCreateScreenBuffer(&NewBuffer
,
232 CONSOLE_TEXTMODE_BUFFER
,
234 if (!NT_SUCCESS(Status
))
236 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
237 ConDrvDeinitInputBuffer(Console
);
238 DeleteCriticalSection(&Console
->Lock
);
239 ConsoleFreeHeap(Console
);
242 /* Make the new screen buffer active */
243 Console
->ActiveBuffer
= NewBuffer
;
244 Console
->UnpauseEvent
= NULL
;
246 DPRINT("Console initialized\n");
248 /* All went right, so add the console to the list */
249 Status
= InsertConsole(Console
);
250 if (!NT_SUCCESS(Status
))
253 ConDrvDeleteConsole(Console
);
257 /* The initialization is finished */
258 DPRINT("Change state\n");
259 Console
->State
= CONSOLE_RUNNING
;
261 /* Return the newly created console to the caller and a success code too */
262 *NewConsole
= Console
;
263 return STATUS_SUCCESS
;
267 ConDrvRegisterTerminal(IN PCONSOLE Console
,
268 IN PTERMINAL Terminal
)
272 if (Console
== NULL
|| Terminal
== NULL
)
273 return STATUS_INVALID_PARAMETER
;
275 /* FIXME: Lock the console before ?? */
278 * Attach the terminal to the console. Use now the TermIFace of the console,
279 * and not the user-defined temporary Terminal pointer.
281 Console
->TermIFace
= *Terminal
;
282 Console
->TermIFace
.Console
= Console
;
284 /* Initialize the terminal AFTER having attached it to the console */
285 DPRINT("Finish initialization of terminal\n");
286 Status
= Console
->TermIFace
.Vtbl
->InitTerminal(&Console
->TermIFace
, Console
);
287 if (!NT_SUCCESS(Status
))
289 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status
);
291 /* We failed, detach the terminal from the console */
292 Terminal
->Console
= NULL
; // For the caller
293 ResetTerminal(Console
);
298 /* Copy buffer contents to screen */
300 // ConioDrawConsole(Console);
301 DPRINT("Console drawn\n");
303 DPRINT("Terminal initialization done\n");
304 return STATUS_SUCCESS
;
308 ConDrvDeregisterTerminal(IN PCONSOLE Console
)
310 if (Console
== NULL
) return STATUS_INVALID_PARAMETER
;
312 /* FIXME: Lock the console before ?? */
314 /* Deinitialize the terminal BEFORE detaching it from the console */
315 Console
->TermIFace
.Vtbl
->DeinitTerminal(&Console
->TermIFace
/*, Console*/);
318 * Detach the terminal from the console:
319 * reinitialize the terminal interface.
321 ResetTerminal(Console
);
323 DPRINT("Terminal unregistered\n");
324 return STATUS_SUCCESS
;
328 ConDrvDeleteConsole(IN PCONSOLE Console
)
330 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console
);
333 * Forbid validation of any console by other threads
334 * during the deletion of this console.
336 ConDrvLockConsoleListExclusive();
339 * If the console is already being destroyed, i.e. not running
340 * or finishing to be initialized, just return.
342 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
) &&
343 !ConDrvValidateConsoleUnsafe(Console
, CONSOLE_INITIALIZING
, TRUE
))
345 /* Unlock the console list and return */
346 ConDrvUnlockConsoleList();
351 * We are about to be destroyed. Signal it to other people
352 * so that they can terminate what they are doing, and that
353 * they cannot longer validate the console.
355 Console
->State
= CONSOLE_TERMINATING
;
358 * Allow other threads to finish their job: basically, unlock
359 * all other calls to EnterCriticalSection(&Console->Lock); by
360 * ConDrvValidateConsoleUnsafe functions so that they just see
361 * that we are not in CONSOLE_RUNNING state anymore, or unlock
362 * other concurrent calls to ConDrvDeleteConsole so that they
363 * can see that we are in fact already deleting the console.
365 LeaveCriticalSection(&Console
->Lock
);
366 ConDrvUnlockConsoleList();
368 /* FIXME: Send a terminate message to all the processes owning this console */
370 /* Deregister the terminal */
371 DPRINT("Deregister terminal\n");
372 ConDrvDeregisterTerminal(Console
);
373 DPRINT("Terminal deregistered\n");
376 * Check that the console is in terminating state before continuing
377 * (the cleanup code must not change the state of the console...
378 * ...unless to cancel console deletion ?).
381 ConDrvLockConsoleListExclusive();
383 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
385 ConDrvUnlockConsoleList();
389 /* We are now in destruction */
390 Console
->State
= CONSOLE_IN_DESTRUCTION
;
392 /* We really delete the console. Reset the count to be sure. */
393 Console
->ReferenceCount
= 0;
395 /* Remove the console from the list */
396 RemoveConsole(Console
);
398 /* Delete the last screen buffer */
399 ConDrvDeleteScreenBuffer(Console
->ActiveBuffer
);
400 Console
->ActiveBuffer
= NULL
;
401 if (!IsListEmpty(&Console
->BufferList
))
403 /***ConDrvUnlockConsoleList();***/
404 ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE
);
407 /* Deinitialize the input buffer */
408 ConDrvDeinitInputBuffer(Console
);
410 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
412 DPRINT("ConDrvDeleteConsole - Unlocking\n");
413 LeaveCriticalSection(&Console
->Lock
);
414 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
415 DeleteCriticalSection(&Console
->Lock
);
416 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
418 ConsoleFreeHeap(Console
);
419 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
421 /* Unlock the console list and return */
422 ConDrvUnlockConsoleList();
426 /* PUBLIC DRIVER APIS *********************************************************/
429 ConDrvGetConsoleMode(IN PCONSOLE Console
,
430 IN PCONSOLE_IO_OBJECT Object
,
431 OUT PULONG ConsoleMode
)
433 NTSTATUS Status
= STATUS_SUCCESS
;
435 if (Console
== NULL
|| Object
== NULL
|| ConsoleMode
== NULL
)
436 return STATUS_INVALID_PARAMETER
;
439 ASSERT(Console
== Object
->Console
);
441 /*** FIXME: */ *ConsoleMode
= 0; /***/
443 if (INPUT_BUFFER
== Object
->Type
)
445 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
446 *ConsoleMode
= InputBuffer
->Mode
;
448 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
450 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
451 *ConsoleMode
= Buffer
->Mode
;
455 Status
= STATUS_INVALID_HANDLE
;
462 ConDrvSetConsoleMode(IN PCONSOLE Console
,
463 IN PCONSOLE_IO_OBJECT Object
,
464 IN ULONG ConsoleMode
)
466 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
467 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
469 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
471 NTSTATUS Status
= STATUS_SUCCESS
;
473 if (Console
== NULL
|| Object
== NULL
)
474 return STATUS_INVALID_PARAMETER
;
477 ASSERT(Console
== Object
->Console
);
479 if (INPUT_BUFFER
== Object
->Type
)
481 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
483 /* Only the presence of valid mode flags is allowed */
484 if (ConsoleMode
& ~CONSOLE_VALID_INPUT_MODES
)
486 Status
= STATUS_INVALID_PARAMETER
;
490 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
493 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
495 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
497 /* Only the presence of valid mode flags is allowed */
498 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
500 Status
= STATUS_INVALID_PARAMETER
;
504 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
509 Status
= STATUS_INVALID_HANDLE
;
516 ConDrvGetConsoleCP(IN PCONSOLE Console
,
520 if (Console
== NULL
|| CodePage
== NULL
)
521 return STATUS_INVALID_PARAMETER
;
523 *CodePage
= (OutputCP
? Console
->OutputCodePage
: Console
->InputCodePage
);
525 return STATUS_SUCCESS
;
529 ConDrvSetConsoleCP(IN PCONSOLE Console
,
533 if (Console
== NULL
|| !IsValidCodePage(CodePage
))
534 return STATUS_INVALID_PARAMETER
;
537 Console
->OutputCodePage
= CodePage
;
539 Console
->InputCodePage
= CodePage
;
541 return STATUS_SUCCESS
;