[MVDM] hack-fix Clang-CL build
[reactos.git] / subsystems / mvdm / ntvdm / console / video.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/video/console.c
5 * PURPOSE: Console driver for the video subsystem
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 /** HACK!! **/
13 #if 0
14
15 #include "ntvdm.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 #include "emulator.h"
21 #include "svga.h"
22
23 #include "console.h"
24
25 #endif
26 /** HACK!! **/
27
28
29 /* PRIVATE VARIABLES **********************************************************/
30
31 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
32 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
33
34
35 static HANDLE ScreenBufferHandle = NULL;
36 static PVOID OldConsoleFramebuffer = NULL;
37
38
39 /*
40 * Text mode -- we always keep a valid text mode framebuffer
41 * even if we are in graphics mode. This is needed in order
42 * to keep a consistent VGA state. However, each time the VGA
43 * detaches from the console (and reattaches to it later on),
44 * this text mode framebuffer is recreated.
45 */
46 static HANDLE TextConsoleBuffer = NULL;
47 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
48 static COORD TextResolution = {0};
49 /// static PCHAR_CELL TextFramebuffer = NULL;
50
51 /*
52 * Graphics mode
53 */
54 static HANDLE GraphicsConsoleBuffer = NULL;
55 /// static PVOID GraphicsFramebuffer = NULL;
56 static HANDLE ConsoleMutex = NULL;
57 /* DoubleVision support */
58 static BOOLEAN DoubleWidth = FALSE;
59 static BOOLEAN DoubleHeight = FALSE;
60
61
62
63 /*
64 * Activate this line if you want to use the real
65 * RegisterConsoleVDM API of ReactOS/Windows.
66 */
67 // #define USE_REAL_REGISTERCONSOLEVDM
68
69 static HANDLE StartEvent = NULL;
70 static HANDLE EndEvent = NULL;
71 static HANDLE AnotherEvent = NULL;
72
73 /* RegisterConsoleVDM EMULATION ***********************************************/
74
75 #include <ntddvdeo.h>
76
77 #ifdef USE_REAL_REGISTERCONSOLEVDM
78
79 #define __RegisterConsoleVDM RegisterConsoleVDM
80 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
81
82 #else
83
84 /*
85 * This private buffer, per-console, is used by
86 * RegisterConsoleVDM and InvalidateConsoleDIBits.
87 */
88 static COORD VDMBufferSize = {0};
89 static PCHAR_CELL VDMBuffer = NULL;
90
91 static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
92 // for the real RegisterConsoleVDM and
93 // InvalidateConsoleDIBits
94
95 BOOL
96 WINAPI
97 __RegisterConsoleVDM(IN DWORD dwRegisterFlags,
98 IN HANDLE hStartHardwareEvent,
99 IN HANDLE hEndHardwareEvent,
100 IN HANDLE hErrorHardwareEvent,
101 IN DWORD dwUnusedVar,
102 OUT LPDWORD lpVideoStateLength,
103 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
104 IN PVOID lpUnusedBuffer,
105 IN DWORD dwUnusedBufferLength,
106 IN COORD dwVDMBufferSize,
107 OUT PVOID* lpVDMBuffer)
108 {
109 UNREFERENCED_PARAMETER(hErrorHardwareEvent);
110 UNREFERENCED_PARAMETER(dwUnusedVar);
111 UNREFERENCED_PARAMETER(lpVideoStateLength);
112 UNREFERENCED_PARAMETER(lpVideoState);
113 UNREFERENCED_PARAMETER(lpUnusedBuffer);
114 UNREFERENCED_PARAMETER(dwUnusedBufferLength);
115
116 SetLastError(0);
117 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
118
119 if (lpVDMBuffer == NULL) return FALSE;
120
121 if (dwRegisterFlags != 0)
122 {
123 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
124 if (VDMBuffer != NULL) return FALSE;
125
126 VDMBufferSize = dwVDMBufferSize;
127
128 /* HACK: Cache -- to be removed in the real implementation */
129 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
130 HEAP_ZERO_MEMORY,
131 VDMBufferSize.X * VDMBufferSize.Y
132 * sizeof(*CharBuff));
133 ASSERT(CharBuff);
134
135 VDMBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
136 HEAP_ZERO_MEMORY,
137 VDMBufferSize.X * VDMBufferSize.Y
138 * sizeof(*VDMBuffer));
139 *lpVDMBuffer = VDMBuffer;
140 return (VDMBuffer != NULL);
141 }
142 else
143 {
144 /* HACK: Cache -- to be removed in the real implementation */
145 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
146 CharBuff = NULL;
147
148 if (VDMBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer);
149 VDMBuffer = NULL;
150
151 VDMBufferSize.X = VDMBufferSize.Y = 0;
152
153 return TRUE;
154 }
155 }
156
157 BOOL
158 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
159 IN PSMALL_RECT lpRect)
160 {
161 if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
162 {
163 /* HACK: Write the cached data to the console */
164
165 COORD Origin = { lpRect->Left, lpRect->Top };
166 SHORT i, j;
167
168 ASSERT(CharBuff);
169
170 for (i = 0; i < VDMBufferSize.Y; i++)
171 {
172 for (j = 0; j < VDMBufferSize.X; j++)
173 {
174 CharBuff[i * VDMBufferSize.X + j].Char.AsciiChar = VDMBuffer[i * VDMBufferSize.X + j].Char;
175 CharBuff[i * VDMBufferSize.X + j].Attributes = VDMBuffer[i * VDMBufferSize.X + j].Attributes;
176 }
177 }
178
179 WriteConsoleOutputA(hConsoleOutput,
180 CharBuff,
181 VDMBufferSize,
182 Origin,
183 lpRect);
184 }
185
186 return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
187 }
188
189 #endif
190
191
192 /* PRIVATE FUNCTIONS **********************************************************/
193
194
195 /*********/
196 static VOID VgaUpdateTextCursor(VOID);
197 static inline DWORD VgaGetAddressSize(VOID);
198 /*********/
199
200
201
202
203 static VOID ResizeTextConsole(PCOORD Resolution, PSMALL_RECT WindowSize OPTIONAL)
204 {
205 BOOL Success;
206 SMALL_RECT ConRect;
207 SHORT oldWidth, oldHeight;
208
209 /*
210 * Use this trick to effectively resize the console buffer and window,
211 * because:
212 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
213 * is smaller than the current console window size, and:
214 * - SetConsoleWindowInfo fails if the new console window size is larger
215 * than the current console screen buffer size.
216 */
217
218
219 /* Retrieve the latest console information */
220 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
221
222 oldWidth = ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1;
223 oldHeight = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1;
224
225 /*
226 * If the current console window is too large to hold the full contents
227 * of the new screen buffer, resize it first.
228 */
229 if (oldWidth > Resolution->X || oldHeight > Resolution->Y)
230 {
231 //
232 // NOTE: This is not a problem if we move the window back to (0,0)
233 // because when we resize the screen buffer, the window will move back
234 // to where the cursor is. Or, if the screen buffer is not resized,
235 // when we readjust again the window, we will move back to a correct
236 // position. This is what we wanted after all...
237 //
238
239 ConRect.Left = ConRect.Top = 0;
240 ConRect.Right = ConRect.Left + min(oldWidth , Resolution->X) - 1;
241 ConRect.Bottom = ConRect.Top + min(oldHeight, Resolution->Y) - 1;
242
243 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
244 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
245 }
246
247 /* Resize the screen buffer if needed */
248 if (Resolution->X != ConsoleInfo.dwSize.X || Resolution->Y != ConsoleInfo.dwSize.Y)
249 {
250 /*
251 * SetConsoleScreenBufferSize automatically takes into account the current
252 * cursor position when it computes starting which row it should copy text
253 * when resizing the sceenbuffer, and scrolls the console window such that
254 * the cursor is placed in it again. We therefore do not need to care about
255 * the cursor position and do the maths ourselves.
256 */
257 Success = SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
258 if (!Success) DPRINT1("(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
259
260 /*
261 * Setting a new screen buffer size can change other information,
262 * so update the saved console information.
263 */
264 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
265 }
266
267 if (!WindowSize)
268 {
269 ConRect.Left = 0;
270 ConRect.Right = ConRect.Left + Resolution->X - 1;
271 ConRect.Bottom = max(ConsoleInfo.dwCursorPosition.Y, Resolution->Y - 1);
272 ConRect.Top = ConRect.Bottom - Resolution->Y + 1;
273
274 // NOTE: We may take ConsoleInfo.dwMaximumWindowSize into account
275 }
276 else
277 {
278 ConRect.Left = ConRect.Top = 0;
279 ConRect.Right = ConRect.Left + WindowSize->Right - WindowSize->Left;
280 ConRect.Bottom = ConRect.Top + WindowSize->Bottom - WindowSize->Top ;
281 }
282
283 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
284 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(2) failed with error %d\n", GetLastError());
285
286 /* Update the saved console information */
287 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
288 }
289
290 static VOID UpdateCursorPosition(VOID)
291 {
292 /*
293 * Update the cursor position in the VGA registers.
294 */
295 WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
296 ConsoleInfo.dwCursorPosition.X;
297
298 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
299 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
300
301 VgaUpdateTextCursor();
302 }
303
304 static BOOL AttachToConsoleInternal(PCOORD Resolution)
305 {
306 BOOL Success;
307 ULONG Length = 0;
308 PVIDEO_HARDWARE_STATE_HEADER State;
309
310 #ifdef USE_REAL_REGISTERCONSOLEVDM
311 PCHAR_INFO CharBuff = NULL;
312 #endif
313 SHORT i, j;
314 DWORD AddressSize, ScanlineSize;
315 DWORD Address = 0;
316 DWORD CurrentAddr;
317 SMALL_RECT ConRect;
318 COORD Origin = { 0, 0 };
319
320 ASSERT(TextFramebuffer == NULL);
321
322 TextResolution = *Resolution;
323
324 /*
325 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
326 * in the two following APIs:
327 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
328 * SrvVDMConsoleOperation (corresponding Win32 API: VDMConsoleOperation)
329 * to check whether the current process is a VDM process, and fails otherwise
330 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
331 *
332 * It is worth it to notice that also basesrv.dll does the same only for the
333 * BaseSrvIsFirstVDM API...
334 */
335
336 /* Register with the console server */
337 Success =
338 __RegisterConsoleVDM(1,
339 StartEvent,
340 EndEvent,
341 AnotherEvent, // NULL,
342 0,
343 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
344 (PVOID*)&State, // NULL,
345 NULL,
346 0,
347 TextResolution,
348 (PVOID*)&TextFramebuffer);
349 if (!Success)
350 {
351 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
352 EmulatorTerminate();
353 return FALSE;
354 }
355
356 #ifdef USE_REAL_REGISTERCONSOLEVDM
357 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
358 HEAP_ZERO_MEMORY,
359 TextResolution.X * TextResolution.Y
360 * sizeof(*CharBuff));
361 ASSERT(CharBuff);
362 #endif
363
364 /* Resize the console */
365 ResizeTextConsole(Resolution, NULL);
366
367 /* Update the saved console information */
368 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
369
370 /*
371 * Copy console data into VGA memory
372 */
373
374 /* Read the data from the console into the framebuffer... */
375 ConRect.Left = ConRect.Top = 0;
376 ConRect.Right = TextResolution.X;
377 ConRect.Bottom = TextResolution.Y;
378
379 ReadConsoleOutputA(TextConsoleBuffer,
380 CharBuff,
381 TextResolution,
382 Origin,
383 &ConRect);
384
385 /* ... and copy the framebuffer into the VGA memory */
386 AddressSize = VgaGetAddressSize();
387 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
388
389 /* Loop through the scanlines */
390 for (i = 0; i < TextResolution.Y; i++)
391 {
392 /* Loop through the characters */
393 for (j = 0; j < TextResolution.X; j++)
394 {
395 CurrentAddr = LOWORD((Address + j) * AddressSize);
396
397 /* Store the character in plane 0 */
398 VgaMemory[CurrentAddr * VGA_NUM_BANKS] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
399
400 /* Store the attribute in plane 1 */
401 VgaMemory[CurrentAddr * VGA_NUM_BANKS + 1] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
402 }
403
404 /* Move to the next scanline */
405 Address += ScanlineSize;
406 }
407
408 #ifdef USE_REAL_REGISTERCONSOLEVDM
409 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
410 #endif
411
412 UpdateCursorPosition();
413
414 return TRUE;
415 }
416
417 static VOID DetachFromConsoleInternal(VOID)
418 {
419 ULONG dummyLength;
420 PVOID dummyPtr;
421 COORD dummySize = {0};
422
423 /* Deregister with the console server */
424 __RegisterConsoleVDM(0,
425 NULL,
426 NULL,
427 NULL,
428 0,
429 &dummyLength,
430 &dummyPtr,
431 NULL,
432 0,
433 dummySize,
434 &dummyPtr);
435
436 TextFramebuffer = NULL;
437 }
438
439 static VOID SetActiveScreenBuffer(HANDLE ScreenBuffer)
440 {
441 ASSERT(ScreenBuffer);
442
443 /* Set the active buffer and reattach the VDM UI to it */
444 SetConsoleActiveScreenBuffer(ScreenBuffer);
445 ConsoleReattach(ScreenBuffer);
446 }
447
448 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
449 {
450 /*
451 * This function monitors and allows console resizings only if they are triggered by us.
452 * User-driven resizings via the console properties, or programmatical console resizings
453 * made by explicit calls to SetConsoleScreenBufferSize by external applications, are forbidden.
454 * In that case only a console window resize is done in case the size is reduced.
455 * This protection is enabled in CONSRV side when NTVDM registers as a VDM to CONSRV,
456 * but we also implement it there in case we are running in STANDALONE mode without
457 * CONSRV registration.
458 *
459 * The only potential problem we have is that, when this handler is called,
460 * the console is already resized. In case this corresponds to a forbidden resize,
461 * we resize the console back to its original size from inside the handler.
462 * This will trigger a recursive call to the handler, that should be detected.
463 */
464
465 if (CurrResolution.X == ScreenEvent->dwSize.X &&
466 CurrResolution.Y == ScreenEvent->dwSize.Y)
467 {
468 /* Allowed resize, we are OK */
469 return;
470 }
471
472 DPRINT1("ScreenEventHandler - Detected forbidden resize! Reset console screenbuffer size back to (X = %d ; Y = %d)\n", CurrResolution.X, CurrResolution.Y);
473
474 // FIXME: If we're detaching, then stop monitoring for changes!!
475
476 /* Restore the original console size */
477 ResizeTextConsole(&CurrResolution, NULL);
478
479 /* Force refresh of all the screen */
480 NeedsUpdate = TRUE;
481 UpdateRectangle.Left = 0;
482 UpdateRectangle.Top = 0;
483 UpdateRectangle.Right = CurrResolution.X;
484 UpdateRectangle.Bottom = CurrResolution.Y;
485 VgaRefreshDisplay();
486 }
487
488 BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
489 {
490 if (GraphicsConsoleBuffer == NULL) return FALSE;
491 if (Horizontal) *Horizontal = DoubleWidth;
492 if (Vertical) *Vertical = DoubleHeight;
493 return TRUE;
494 }
495
496 BOOL VgaAttachToConsole(VOID)
497 {
498 if (TextResolution.X == 0 || TextResolution.Y == 0)
499 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
500
501 if (TextResolution.X == 0) TextResolution.X = 80;
502 if (TextResolution.Y == 0) TextResolution.Y = 25;
503
504 // DetachFromConsoleInternal();
505
506 /*
507 * AttachToConsoleInternal sets TextResolution
508 * to the new resolution and updates ConsoleInfo.
509 */
510 if (!AttachToConsoleInternal(&TextResolution))
511 {
512 DisplayMessage(L"An unexpected error occurred!\n");
513 EmulatorTerminate();
514 return FALSE;
515 }
516
517 /* Restore the original screen buffer */
518 SetActiveScreenBuffer(ScreenBufferHandle);
519 ScreenBufferHandle = NULL;
520
521 /* Restore the screen state */
522 if (ScreenMode == TEXT_MODE)
523 {
524 /* The text mode framebuffer was recreated */
525 ActiveFramebuffer = TextFramebuffer;
526 }
527 else
528 {
529 /* The graphics mode framebuffer is unchanged */
530 ActiveFramebuffer = OldConsoleFramebuffer;
531 }
532 OldConsoleFramebuffer = NULL;
533
534 return TRUE;
535 }
536
537 VOID VgaDetachFromConsole(VOID)
538 {
539 DetachFromConsoleInternal();
540
541 /* Save the screen state */
542 if (ScreenMode == TEXT_MODE)
543 ScreenBufferHandle = TextConsoleBuffer;
544 else
545 ScreenBufferHandle = GraphicsConsoleBuffer;
546
547 /* Reset the active framebuffer */
548 OldConsoleFramebuffer = ActiveFramebuffer;
549 ActiveFramebuffer = NULL;
550
551 /* Restore the original console size */
552 ResizeTextConsole(&OrgConsoleBufferInfo.dwSize, &OrgConsoleBufferInfo.srWindow);
553
554 /* Restore the original cursor shape */
555 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
556
557 // FIXME: Should we copy back the screen data to the screen buffer??
558 // WriteConsoleOutputA(...);
559
560 // FIXME: Should we change cursor POSITION??
561 // VgaUpdateTextCursor();
562
563 ///* Update the physical cursor */
564 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
565 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
566
567 /* Restore the old text-mode screen buffer */
568 SetActiveScreenBuffer(TextConsoleBuffer);
569 }
570
571
572
573
574 VOID
575 VgaConsoleUpdateTextCursor(BOOL CursorVisible,
576 BYTE CursorStart,
577 BYTE CursorEnd,
578 BYTE TextSize,
579 DWORD ScanlineSize,
580 WORD Location)
581 {
582 COORD Position;
583 CONSOLE_CURSOR_INFO CursorInfo;
584
585 if (CursorStart < CursorEnd)
586 {
587 /* Visible cursor */
588 CursorInfo.bVisible = CursorVisible;
589 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
590 }
591 else
592 {
593 /* Hidden cursor */
594 CursorInfo.bVisible = FALSE;
595 CursorInfo.dwSize = 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
596 }
597
598 /* Find the coordinates of the new position */
599 Position.X = (SHORT)(Location % ScanlineSize);
600 Position.Y = (SHORT)(Location / ScanlineSize);
601
602 DPRINT("VgaConsoleUpdateTextCursor: (X = %d ; Y = %d)\n", Position.X, Position.Y);
603
604 /* Update the physical cursor */
605 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
606 SetConsoleCursorPosition(TextConsoleBuffer, Position);
607 }
608
609 BOOL
610 VgaConsoleCreateGraphicsScreen(// OUT PBYTE* GraphicsFramebuffer,
611 IN PCOORD Resolution,
612 IN HANDLE PaletteHandle)
613 {
614 DWORD i;
615 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
616 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
617 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
618 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
619
620 LONG Width = Resolution->X;
621 LONG Height = Resolution->Y;
622
623 /* Use DoubleVision mode if the resolution is too small */
624 DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
625 if (DoubleWidth) Width *= 2;
626 DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
627 if (DoubleHeight) Height *= 2;
628
629 /* Fill the bitmap info header */
630 RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
631 BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
632 BitmapInfo->bmiHeader.biWidth = Width;
633 BitmapInfo->bmiHeader.biHeight = Height;
634 BitmapInfo->bmiHeader.biBitCount = 8;
635 BitmapInfo->bmiHeader.biPlanes = 1;
636 BitmapInfo->bmiHeader.biCompression = BI_RGB;
637 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
638
639 /* Fill the palette data */
640 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
641
642 /* Fill the console graphics buffer info */
643 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
644 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
645 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
646
647 /* Create the buffer */
648 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
649 FILE_SHARE_READ | FILE_SHARE_WRITE,
650 NULL,
651 CONSOLE_GRAPHICS_BUFFER,
652 &GraphicsBufferInfo);
653 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
654
655 /* Save the framebuffer address and mutex */
656 // *GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
657 GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
658 ConsoleMutex = GraphicsBufferInfo.hMutex;
659
660 /* Clear the framebuffer */
661 // RtlZeroMemory(*GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
662 RtlZeroMemory(GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
663
664 /* Set the graphics mode palette */
665 SetConsolePalette(GraphicsConsoleBuffer,
666 PaletteHandle,
667 SYSPAL_NOSTATIC256);
668
669 /* Set the active buffer */
670 SetActiveScreenBuffer(GraphicsConsoleBuffer);
671
672 return TRUE;
673 }
674
675 VOID VgaConsoleDestroyGraphicsScreen(VOID)
676 {
677 /* Release the console framebuffer mutex */
678 ReleaseMutex(ConsoleMutex);
679
680 /* Switch back to the default console text buffer */
681 // SetActiveScreenBuffer(TextConsoleBuffer);
682
683 /* Cleanup the video data */
684 CloseHandle(ConsoleMutex);
685 ConsoleMutex = NULL;
686 // GraphicsFramebuffer = NULL;
687 CloseHandle(GraphicsConsoleBuffer);
688 GraphicsConsoleBuffer = NULL;
689
690 // /* Reset the active framebuffer */
691 // ActiveFramebuffer = NULL;
692
693 DoubleWidth = FALSE;
694 DoubleHeight = FALSE;
695 }
696
697 BOOL
698 VgaConsoleCreateTextScreen(// OUT PCHAR_CELL* TextFramebuffer,
699 IN PCOORD Resolution,
700 IN HANDLE PaletteHandle)
701 {
702 /* Switch to the text buffer */
703 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
704 SetActiveScreenBuffer(TextConsoleBuffer);
705
706 /* Adjust the text framebuffer if we changed the resolution */
707 if (TextResolution.X != Resolution->X ||
708 TextResolution.Y != Resolution->Y)
709 {
710 DetachFromConsoleInternal();
711
712 /*
713 * AttachToConsoleInternal sets TextResolution
714 * to the new resolution and updates ConsoleInfo.
715 */
716 if (!AttachToConsoleInternal(Resolution))
717 {
718 DisplayMessage(L"An unexpected error occurred!\n");
719 EmulatorTerminate();
720 return FALSE;
721 }
722 }
723 else
724 {
725 UpdateCursorPosition();
726 }
727
728 /*
729 * Set the text mode palette.
730 *
731 * INFORMATION: This call should fail on Windows (and therefore
732 * we get the default palette and our external behaviour is
733 * just like Windows' one), but it should success on ReactOS
734 * (so that we get console palette changes even for text-mode
735 * screen buffers, which is a new feature on ReactOS).
736 */
737 SetConsolePalette(TextConsoleBuffer,
738 PaletteHandle,
739 SYSPAL_NOSTATIC256);
740
741 return TRUE;
742 }
743
744 VOID VgaConsoleDestroyTextScreen(VOID)
745 {
746 }
747
748
749
750 VOID VgaConsoleRepaintScreen(PSMALL_RECT Rect)
751 {
752 HANDLE ConsoleBufferHandle = NULL;
753 SMALL_RECT UpdateRectangle = *Rect;
754
755 /* Check if we are in text or graphics mode */
756 if (ScreenMode == GRAPHICS_MODE)
757 {
758 /* Graphics mode */
759 ConsoleBufferHandle = GraphicsConsoleBuffer;
760
761 /* In DoubleVision mode, scale the update rectangle */
762 if (DoubleWidth)
763 {
764 UpdateRectangle.Left *= 2;
765 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
766 }
767 if (DoubleHeight)
768 {
769 UpdateRectangle.Top *= 2;
770 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
771 }
772 }
773 else
774 {
775 /* Text mode */
776 ConsoleBufferHandle = TextConsoleBuffer;
777 }
778
779 /* Redraw the screen */
780 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
781 }
782
783 BOOLEAN VgaConsoleInitialize(HANDLE TextHandle)
784 {
785 /*
786 * Initialize the console video by saving the default
787 * text-mode console output handle, if it is valid.
788 */
789 if (!IsConsoleHandle(TextHandle)) return FALSE;
790 TextConsoleBuffer = TextHandle;
791
792 /* Save the original cursor and console screen buffer information */
793 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
794 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
795 {
796 TextConsoleBuffer = NULL;
797 return FALSE;
798 }
799 ConsoleInfo = OrgConsoleBufferInfo;
800
801 /* Switch to the text buffer, but do not enter into a text mode */
802 SetActiveScreenBuffer(TextConsoleBuffer);
803
804 return TRUE;
805 }
806
807 VOID VgaConsoleCleanup(VOID)
808 {
809 /* If the console video was not initialized, just return */
810 if (!TextConsoleBuffer)
811 return;
812
813 VgaDetachFromConsole();
814
815 // TODO: We need to initialize those events before using them!
816 CloseHandle(AnotherEvent);
817 CloseHandle(EndEvent);
818 CloseHandle(StartEvent);
819 }