3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This file produces the graphics abstration of GOP. It is called by
19 WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.
20 This file just does graphics.
27 DWORD mTlsIndex
= TLS_OUT_OF_INDEXES
;
28 DWORD mTlsIndexUseCount
= 0; // lets us know when we can free mTlsIndex.
31 WinNtGopConvertParamToEfiKeyShiftState (
32 IN GRAPHICS_PRIVATE_DATA
*Private
,
40 // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish
41 // left and right Ctrl, and Shift key.
42 // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.
43 // Therefor, we can not set the correct Shift state here.
46 if ((*lParam
& GOP_EXTENDED_KEY
) == GOP_EXTENDED_KEY
) {
47 Private
->RightShift
= Flag
;
49 Private
->LeftShift
= Flag
;
54 Private
->LeftShift
= Flag
;
58 Private
->RightShift
= Flag
;
62 if ((*lParam
& GOP_EXTENDED_KEY
) == GOP_EXTENDED_KEY
) {
63 Private
->RightCtrl
= Flag
;
65 Private
->LeftCtrl
= Flag
;
70 Private
->LeftCtrl
= Flag
;
74 Private
->RightCtrl
= Flag
;
78 Private
->LeftLogo
= Flag
;
82 Private
->RightLogo
= Flag
;
89 // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,
90 // so SySReq shift state is not supported here.
93 Private
->SysReq
= Flag
;
99 if ((*lParam
& GOP_EXTENDED_KEY
) == GOP_EXTENDED_KEY
) {
100 Private
->RightAlt
= Flag
;
102 Private
->LeftAlt
= Flag
;
112 WinNtGopConvertParamToEfiKey (
113 IN GRAPHICS_PRIVATE_DATA
*Private
,
116 IN EFI_INPUT_KEY
*Key
122 case VK_HOME
: Key
->ScanCode
= SCAN_HOME
; Flag
= TRUE
; break;
123 case VK_END
: Key
->ScanCode
= SCAN_END
; Flag
= TRUE
; break;
124 case VK_LEFT
: Key
->ScanCode
= SCAN_LEFT
; Flag
= TRUE
; break;
125 case VK_RIGHT
: Key
->ScanCode
= SCAN_RIGHT
; Flag
= TRUE
; break;
126 case VK_UP
: Key
->ScanCode
= SCAN_UP
; Flag
= TRUE
; break;
127 case VK_DOWN
: Key
->ScanCode
= SCAN_DOWN
; Flag
= TRUE
; break;
128 case VK_DELETE
: Key
->ScanCode
= SCAN_DELETE
; Flag
= TRUE
; break;
129 case VK_INSERT
: Key
->ScanCode
= SCAN_INSERT
; Flag
= TRUE
; break;
130 case VK_PRIOR
: Key
->ScanCode
= SCAN_PAGE_UP
; Flag
= TRUE
; break;
131 case VK_NEXT
: Key
->ScanCode
= SCAN_PAGE_DOWN
; Flag
= TRUE
; break;
132 case VK_ESCAPE
: Key
->ScanCode
= SCAN_ESC
; Flag
= TRUE
; break;
134 case VK_F1
: Key
->ScanCode
= SCAN_F1
; Flag
= TRUE
; break;
135 case VK_F2
: Key
->ScanCode
= SCAN_F2
; Flag
= TRUE
; break;
136 case VK_F3
: Key
->ScanCode
= SCAN_F3
; Flag
= TRUE
; break;
137 case VK_F4
: Key
->ScanCode
= SCAN_F4
; Flag
= TRUE
; break;
138 case VK_F5
: Key
->ScanCode
= SCAN_F5
; Flag
= TRUE
; break;
139 case VK_F6
: Key
->ScanCode
= SCAN_F6
; Flag
= TRUE
; break;
140 case VK_F7
: Key
->ScanCode
= SCAN_F7
; Flag
= TRUE
; break;
141 case VK_F8
: Key
->ScanCode
= SCAN_F8
; Flag
= TRUE
; break;
142 case VK_F9
: Key
->ScanCode
= SCAN_F9
; Flag
= TRUE
; break;
143 case VK_F11
: Key
->ScanCode
= SCAN_F11
; Flag
= TRUE
; break;
144 case VK_F12
: Key
->ScanCode
= SCAN_F12
; Flag
= TRUE
; break;
146 case VK_F13
: Key
->ScanCode
= SCAN_F13
; Flag
= TRUE
; break;
147 case VK_F14
: Key
->ScanCode
= SCAN_F14
; Flag
= TRUE
; break;
148 case VK_F15
: Key
->ScanCode
= SCAN_F15
; Flag
= TRUE
; break;
149 case VK_F16
: Key
->ScanCode
= SCAN_F16
; Flag
= TRUE
; break;
150 case VK_F17
: Key
->ScanCode
= SCAN_F17
; Flag
= TRUE
; break;
151 case VK_F18
: Key
->ScanCode
= SCAN_F18
; Flag
= TRUE
; break;
152 case VK_F19
: Key
->ScanCode
= SCAN_F19
; Flag
= TRUE
; break;
153 case VK_F20
: Key
->ScanCode
= SCAN_F20
; Flag
= TRUE
; break;
154 case VK_F21
: Key
->ScanCode
= SCAN_F21
; Flag
= TRUE
; break;
155 case VK_F22
: Key
->ScanCode
= SCAN_F22
; Flag
= TRUE
; break;
156 case VK_F23
: Key
->ScanCode
= SCAN_F23
; Flag
= TRUE
; break;
157 case VK_F24
: Key
->ScanCode
= SCAN_F24
; Flag
= TRUE
; break;
158 case VK_PAUSE
: Key
->ScanCode
= SCAN_PAUSE
; Flag
= TRUE
; break;
164 Private
->NumLock
= (BOOLEAN
)(!Private
->NumLock
);
168 Private
->ScrollLock
= (BOOLEAN
)(!Private
->ScrollLock
);
172 Private
->CapsLock
= (BOOLEAN
)(!Private
->CapsLock
);
177 return (WinNtGopConvertParamToEfiKeyShiftState (Private
, wParam
, lParam
, TRUE
)) == TRUE
? TRUE
: Flag
;
182 // GOP Protocol Member Functions
186 Change the resolution and resize of the window
191 IN EMU_GRAPHICS_WINDOW_PROTOCOL
*GraphicsIo
,
197 GRAPHICS_PRIVATE_DATA
*Private
;
199 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*NewFillLine
;
201 Private
= GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo
);
202 Private
->Width
= Width
;
203 Private
->Height
= Height
;
207 // Free the old buffer. We do not save the content of the old buffer since the
208 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
209 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()
211 if (Private
->VirtualScreenInfo
!= NULL
) {
212 HeapFree (GetProcessHeap (), 0, Private
->VirtualScreenInfo
);
216 // Allocate DIB frame buffer directly from NT for performance enhancement
217 // This buffer is the virtual screen/frame buffer. This buffer is not the
218 // same a a frame buffer. The first row of this buffer will be the bottom
219 // line of the image. This is an artifact of the way we draw to the screen.
221 Size
= Private
->Width
* Private
->Height
* sizeof (RGBQUAD
) + sizeof (BITMAPV4HEADER
);
222 Private
->VirtualScreenInfo
= HeapAlloc (
229 // Update the virtual screen info data structure
231 Private
->VirtualScreenInfo
->bV4Size
= sizeof (BITMAPV4HEADER
);
232 Private
->VirtualScreenInfo
->bV4Width
= Private
->Width
;
233 Private
->VirtualScreenInfo
->bV4Height
= Private
->Height
;
234 Private
->VirtualScreenInfo
->bV4Planes
= 1;
235 Private
->VirtualScreenInfo
->bV4BitCount
= 32;
239 Private
->VirtualScreenInfo
->bV4V4Compression
= BI_RGB
;
242 // The rest of the allocated memory block is the virtual screen buffer
244 Private
->VirtualScreen
= (RGBQUAD
*)(Private
->VirtualScreenInfo
+ 1);
247 // Use the AdjuctWindowRect fuction to calculate the real width and height
248 // of the new window including the border and caption
252 Rect
.right
= Private
->Width
;
253 Rect
.bottom
= Private
->Height
;
255 AdjustWindowRect (&Rect
, WS_OVERLAPPEDWINDOW
, 0);
257 Width
= Rect
.right
- Rect
.left
;
258 Height
= Rect
.bottom
- Rect
.top
;
261 // Retrieve the original window position information
263 GetWindowRect (Private
->WindowHandle
, &Rect
);
266 // Adjust the window size
268 MoveWindow (Private
->WindowHandle
, Rect
.left
, Rect
.top
, (INT32
)Width
, (INT32
)Height
, TRUE
);
270 NewFillLine
= AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
) * Private
->Width
);
271 if (NewFillLine
== NULL
) {
272 return EFI_DEVICE_ERROR
;
275 if (Private
->FillLine
!= NULL
) {
276 FreePool (Private
->FillLine
);
279 Private
->FillLine
= NewFillLine
;
284 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
285 onto the graphics screen starting a location (X, Y). (0, 0) is defined as
286 the upper left hand side of the screen. (X, Y) can be outside of the
287 current screen geometry and the BltBuffer will be cliped when it is
288 displayed. X and Y can be negative or positive. If Width or Height is
289 bigger than the current video screen the image will be clipped.
291 @param This Protocol instance pointer.
292 @param X X location on graphics screen.
293 @param Y Y location on the graphics screen.
294 @param Width Width of BltBuffer.
295 @param Height Hight of BltBuffer
296 @param BltOperation Operation to perform on BltBuffer and video memory
297 @param BltBuffer Buffer containing data to blt into video buffer.
298 This buffer has a size of
299 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
300 @param SourceX If the BltOperation is a EfiCopyBlt this is the
301 source of the copy. For other BLT operations this
302 argument is not used.
303 @param SourceX If the BltOperation is a EfiCopyBlt this is the
304 source of the copy. For other BLT operations this
305 argument is not used.
307 @retval EFI_SUCCESS The palette is updated with PaletteArray.
308 @retval EFI_INVALID_PARAMETER BltOperation is not valid.
309 @retval EFI_DEVICE_ERROR A hardware error occured writting to the video
313 // TODO: SourceY - add argument and description to function comment
314 // TODO: DestinationX - add argument and description to function comment
315 // TODO: DestinationY - add argument and description to function comment
316 // TODO: Delta - add argument and description to function comment
319 IN EMU_GRAPHICS_WINDOW_PROTOCOL
*GraphicsIo
,
320 IN EFI_UGA_PIXEL
*BltBuffer OPTIONAL
,
321 IN EFI_UGA_BLT_OPERATION BltOperation
,
322 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS
*Args
325 GRAPHICS_PRIVATE_DATA
*Private
;
330 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
333 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*FillPixel
;
334 UINT32 VerticalResolution
;
335 UINT32 HorizontalResolution
;
337 Private
= GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo
);
340 // We need to fill the Virtual Screen buffer with the blt data.
341 // The virtual screen is upside down, as the first row is the bootom row of
344 VerticalResolution
= Private
->VirtualScreenInfo
->bV4Height
;
345 HorizontalResolution
= Private
->VirtualScreenInfo
->bV4Width
;
346 if (BltOperation
== EfiBltVideoToBltBuffer
) {
348 for (SrcY
= Args
->SourceY
, DstY
= Args
->DestinationY
; DstY
< (Args
->Height
+ Args
->DestinationY
); SrcY
++, DstY
++) {
349 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) ((UINT8
*) BltBuffer
+ (DstY
* Args
->Delta
) + Args
->DestinationX
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
350 VScreen
= &Private
->VirtualScreen
[(VerticalResolution
- SrcY
- 1) * HorizontalResolution
+ Args
->SourceX
];
351 CopyMem (Blt
, VScreen
, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
) * Args
->Width
);
354 if (BltOperation
== EfiBltVideoFill
) {
355 FillPixel
= BltBuffer
;
356 for (Index
= 0; Index
< Args
->Width
; Index
++) {
357 Private
->FillLine
[Index
] = *FillPixel
;
361 for (Index
= 0; Index
< Args
->Height
; Index
++) {
362 if (Args
->DestinationY
<= Args
->SourceY
) {
363 SrcY
= Args
->SourceY
+ Index
;
364 DstY
= Args
->DestinationY
+ Index
;
366 SrcY
= Args
->SourceY
+ Args
->Height
- Index
- 1;
367 DstY
= Args
->DestinationY
+ Args
->Height
- Index
- 1;
370 VScreen
= &Private
->VirtualScreen
[(VerticalResolution
- DstY
- 1) * HorizontalResolution
+ Args
->DestinationX
];
371 switch (BltOperation
) {
372 case EfiBltBufferToVideo
:
373 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) ((UINT8
*) BltBuffer
+ (SrcY
* Args
->Delta
) + Args
->SourceX
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
374 CopyMem (VScreen
, Blt
, Args
->Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
377 case EfiBltVideoToVideo
:
378 VScreenSrc
= &Private
->VirtualScreen
[(VerticalResolution
- SrcY
- 1) * HorizontalResolution
+ Args
->SourceX
];
379 CopyMem (VScreen
, VScreenSrc
, Args
->Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
382 case EfiBltVideoFill
:
383 CopyMem (VScreen
, Private
->FillLine
, Args
->Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
389 if (BltOperation
!= EfiBltVideoToBltBuffer
) {
391 // Mark the area we just blted as Invalid so WM_PAINT will update.
393 Rect
.left
= (LONG
)Args
->DestinationX
;
394 Rect
.top
= (LONG
)Args
->DestinationY
;
395 Rect
.right
= (LONG
)(Args
->DestinationX
+ Args
->Width
);
396 Rect
.bottom
= (LONG
)(Args
->DestinationY
+ Args
->Height
);
397 InvalidateRect (Private
->WindowHandle
, &Rect
, FALSE
);
400 // Send the WM_PAINT message to the thread that is drawing the window. We
401 // are in the main thread and the window drawing is in a child thread.
402 // There is a child thread per window. We have no CriticalSection or Mutex
403 // since we write the data and the other thread displays the data. While
404 // we may miss some data for a short period of time this is no different than
405 // a write combining on writes to a frame buffer.
408 UpdateWindow (Private
->WindowHandle
);
417 Win32 Windows event handler.
421 @return See Win32 Book
424 // TODO: hwnd - add argument and description to function comment
425 // TODO: iMsg - add argument and description to function comment
426 // TODO: wParam - add argument and description to function comment
427 // TODO: lParam - add argument and description to function comment
430 WinNtGopThreadWindowProc (
437 GRAPHICS_PRIVATE_DATA
*Private
;
440 PAINTSTRUCT PaintStruct
;
446 // BugBug - if there are two instances of this DLL in memory (such as is
447 // the case for ERM), the correct instance of this function may not be called.
448 // This also means that the address of the mTlsIndex value will be wrong, and
449 // the value may be wrong too.
454 // Use mTlsIndex global to get a Thread Local Storage version of Private.
455 // This works since each Gop protocol has a unique Private data instance and
459 Private
= TlsGetValue (mTlsIndex
);
460 ASSERT (NULL
!= Private
);
464 Size
= Private
->Width
* Private
->Height
* sizeof (RGBQUAD
);
467 // Allocate DIB frame buffer directly from NT for performance enhancement
468 // This buffer is the virtual screen/frame buffer. This buffer is not the
469 // same a a frame buffer. The first fow of this buffer will be the bottom
470 // line of the image. This is an artifact of the way we draw to the screen.
472 Private
->VirtualScreenInfo
= HeapAlloc (
478 Private
->VirtualScreenInfo
->bV4Size
= sizeof (BITMAPV4HEADER
);
479 Private
->VirtualScreenInfo
->bV4Width
= Private
->Width
;
480 Private
->VirtualScreenInfo
->bV4Height
= Private
->Height
;
481 Private
->VirtualScreenInfo
->bV4Planes
= 1;
482 Private
->VirtualScreenInfo
->bV4BitCount
= 32;
486 Private
->VirtualScreenInfo
->bV4V4Compression
= BI_RGB
;
487 Private
->VirtualScreen
= (RGBQUAD
*) (Private
->VirtualScreenInfo
+ 1);
492 // I have not found a way to convert hwnd into a Private context. So for
493 // now we use this API to convert hwnd to Private data.
496 Handle
= BeginPaint (hwnd
, &PaintStruct
);
499 Handle
, // Destination Device Context
500 0, // Destination X - 0
501 0, // Destination Y - 0
502 Private
->Width
, // Width
503 Private
->Height
, // Height
506 0, // DIB Start Scan Line
507 Private
->Height
, // Number of scan lines
508 Private
->VirtualScreen
, // Address of array of DIB bits
509 (BITMAPINFO
*) Private
->VirtualScreenInfo
, // Address of structure with bitmap info
510 DIB_RGB_COLORS
// RGB or palette indexes
513 EndPaint (hwnd
, &PaintStruct
);
517 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
518 // WM_SYSKEYDOWN is posted when F10 is pressed or
519 // holds down ALT key and then presses another key.
524 Key
.UnicodeChar
= CHAR_NULL
;
527 Key
.ScanCode
= SCAN_F10
;
528 Key
.UnicodeChar
= CHAR_NULL
;
529 GopPrivateAddKey (Private
, Key
);
534 // If ALT or ALT + modifier key is pressed.
536 if (WinNtGopConvertParamToEfiKey (Private
, &wParam
, &lParam
, &Key
)) {
537 if (Key
.ScanCode
!= 0){
539 // If ALT is pressed with other ScanCode.
540 // Always revers the left Alt for simple.
542 Private
->LeftAlt
= TRUE
;
544 GopPrivateAddKey (Private
, Key
);
546 // When Alt is released there is no windoes message, so
547 // clean it after using it.
549 Private
->RightAlt
= FALSE
;
550 Private
->LeftAlt
= FALSE
;
557 // The ESC key also generate WM_CHAR.
559 if (wParam
== 0x1B) {
563 if (AltIsPress
== TRUE
) {
565 // If AltIsPress is true that means the Alt key is pressed.
567 Private
->LeftAlt
= TRUE
;
569 for (Index
= 0; Index
< (lParam
& 0xffff); Index
++) {
571 Key
.UnicodeChar
= (CHAR16
) wParam
;
572 Key
.ScanCode
= SCAN_NULL
;
573 GopPrivateAddKey (Private
, Key
);
576 if (AltIsPress
== TRUE
) {
578 // When Alt is released there is no windoes message, so
579 // clean it after using it.
581 Private
->LeftAlt
= FALSE
;
582 Private
->RightAlt
= FALSE
;
588 // ALT is pressed with another key released
590 WinNtGopConvertParamToEfiKeyShiftState (Private
, &wParam
, &lParam
, FALSE
);
594 Key
.ScanCode
= SCAN_NULL
;
595 Key
.UnicodeChar
= CHAR_NULL
;
597 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR
598 // So if there is no modifier key updated, skip the WM_KEYDOWN even.
600 if (WinNtGopConvertParamToEfiKey (Private
, &wParam
, &lParam
, &Key
)) {
602 // Support the partial keystroke, add all keydown event into the queue.
604 GopPrivateAddKey (Private
, Key
);
609 WinNtGopConvertParamToEfiKeyShiftState (Private
, &wParam
, &lParam
, FALSE
);
614 // This close message is issued by user, core is not aware of this,
615 // so don't release the window display resource, just hide the window.
617 ShowWindow (Private
->WindowHandle
, SW_HIDE
);
621 DestroyWindow (hwnd
);
624 HeapFree (GetProcessHeap (), 0, Private
->VirtualScreenInfo
);
632 return DefWindowProc (hwnd
, iMsg
, wParam
, lParam
);
637 This thread simulates the end of WinMain () aplication. Each Winow nededs
638 to process it's events. The messages are dispatched to
639 WinNtGopThreadWindowProc ().
640 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
641 are running in a seperate thread. We have to do this to process the events.
643 @param lpParameter Handle of window to manage.
645 @return if a WM_QUIT message is returned exit.
650 WinNtGopThreadWinMain (
655 GRAPHICS_PRIVATE_DATA
*Private
;
658 Private
= (GRAPHICS_PRIVATE_DATA
*) lpParameter
;
659 ASSERT (NULL
!= Private
);
662 // Since each thread has unique private data, save the private data in Thread
663 // Local Storage slot. Then the shared global mTlsIndex can be used to get
664 // thread specific context.
666 TlsSetValue (mTlsIndex
, Private
);
668 Private
->ThreadId
= GetCurrentThreadId ();
670 Private
->WindowsClass
.cbSize
= sizeof (WNDCLASSEX
);
671 Private
->WindowsClass
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_OWNDC
;
672 Private
->WindowsClass
.lpfnWndProc
= WinNtGopThreadWindowProc
;
673 Private
->WindowsClass
.cbClsExtra
= 0;
674 Private
->WindowsClass
.cbWndExtra
= 0;
675 Private
->WindowsClass
.hInstance
= NULL
;
676 Private
->WindowsClass
.hIcon
= LoadIcon (NULL
, IDI_APPLICATION
);
677 Private
->WindowsClass
.hCursor
= LoadCursor (NULL
, IDC_ARROW
);
678 Private
->WindowsClass
.hbrBackground
= (HBRUSH
)(UINTN
)COLOR_WINDOW
;
679 Private
->WindowsClass
.lpszMenuName
= NULL
;
680 Private
->WindowsClass
.lpszClassName
= WIN_NT_GOP_CLASS_NAME
;
681 Private
->WindowsClass
.hIconSm
= LoadIcon (NULL
, IDI_APPLICATION
);
684 // Use 100 x 100 as initial Window size.
686 Private
->Width
= 100;
687 Private
->Height
= 100;
691 // This call will fail after the first time, but thats O.K. since we only need
692 // WIN_NT_GOP_CLASS_NAME to exist to create the window.
694 // Note: Multiple instances of this DLL will use the same instance of this
695 // Class, including the callback function, unless the Class is unregistered and
696 // successfully registered again.
698 RegisterClassEx (&Private
->WindowsClass
);
701 // Setting Rect values to allow for the AdjustWindowRect to provide
702 // us the correct sizes for the client area when doing the CreateWindowEx
705 Rect
.bottom
= Private
->Height
;
707 Rect
.right
= Private
->Width
;
709 AdjustWindowRect (&Rect
, WS_OVERLAPPEDWINDOW
, 0);
711 Private
->WindowHandle
= CreateWindowEx (
713 WIN_NT_GOP_CLASS_NAME
,
718 Rect
.right
- Rect
.left
,
719 Rect
.bottom
- Rect
.top
,
727 // The reset of this thread is the standard winows program. We need a sperate
728 // thread since we must process the message loop to make windows act like
732 ShowWindow (Private
->WindowHandle
, SW_SHOW
);
733 UpdateWindow (Private
->WindowHandle
);
736 // Let the main thread get some work done
738 ReleaseSemaphore (Private
->ThreadInited
, 1, NULL
);
741 // This is the message loop that all Windows programs need.
743 while (GetMessage (&Message
, Private
->WindowHandle
, 0, 0)) {
744 TranslateMessage (&Message
);
745 DispatchMessage (&Message
);
748 return (DWORD
)Message
.wParam
;
753 TODO: Add function description
755 @param Private TODO: add argument description
756 @param HorizontalResolution TODO: add argument description
757 @param VerticalResolution TODO: add argument description
758 @param ColorDepth TODO: add argument description
759 @param RefreshRate TODO: add argument description
761 @return TODO: add return values
766 WinNtGraphicsWindowOpen (
767 IN EMU_IO_THUNK_PROTOCOL
*This
771 GRAPHICS_PRIVATE_DATA
*Private
;
773 Private
= AllocateZeroPool (sizeof (*Private
));
775 GopPrivateCreateQ (Private
, &Private
->QueueForRead
);
777 Private
->GraphicsWindowIo
.Size
= WinNtWndSize
;
778 Private
->GraphicsWindowIo
.CheckKey
= WinNtWndCheckKey
;
779 Private
->GraphicsWindowIo
.GetKey
= WinNtWndGetKey
;
780 Private
->GraphicsWindowIo
.KeySetState
= WinNtWndKeySetState
;
781 Private
->GraphicsWindowIo
.RegisterKeyNotify
= WinNtWndRegisterKeyNotify
;
782 Private
->GraphicsWindowIo
.Blt
= WinNtWndBlt
;
783 Private
->GraphicsWindowIo
.CheckPointer
= WinNtWndCheckPointer
;
784 Private
->GraphicsWindowIo
.GetPointerState
= WinNtWndGetPointerState
;
786 Private
->WindowName
= This
->ConfigString
;
788 // Initialize a Thread Local Storge variable slot. We use TLS to get the
789 // correct Private data instance into the windows thread.
791 if (mTlsIndex
== TLS_OUT_OF_INDEXES
) {
792 ASSERT (0 == mTlsIndexUseCount
);
793 mTlsIndex
= TlsAlloc ();
797 // always increase the use count!
801 Private
->ThreadInited
= CreateSemaphore (NULL
, 0, 1, NULL
);
802 Private
->ThreadHandle
= CreateThread (
805 WinNtGopThreadWinMain
,
812 // The other thread has entered the windows message loop so we can
813 // continue our initialization.
815 WaitForSingleObject (Private
->ThreadInited
, INFINITE
);
816 CloseHandle (Private
->ThreadInited
);
818 This
->Private
= Private
;
819 This
->Interface
= &Private
->GraphicsWindowIo
;
826 WinNtGraphicsWindowClose (
827 IN EMU_IO_THUNK_PROTOCOL
*This
830 GRAPHICS_PRIVATE_DATA
*Private
;
832 Private
= (GRAPHICS_PRIVATE_DATA
*)This
->Private
;
835 // BugBug: Shutdown GOP Hardware and any child devices.
837 SendMessage (Private
->WindowHandle
, WM_DESTROY
, 0, 0);
838 CloseHandle (Private
->ThreadHandle
);
843 // The callback function for another window could still be called,
844 // so we need to make sure there are no more users of mTlsIndex.
846 if (0 == mTlsIndexUseCount
) {
847 ASSERT (TLS_OUT_OF_INDEXES
!= mTlsIndex
);
850 mTlsIndex
= TLS_OUT_OF_INDEXES
;
853 Private
->WindowsClass
.lpszClassName
,
854 Private
->WindowsClass
.hInstance
859 GopPrivateDestroyQ (Private
, &Private
->QueueForRead
);
864 EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo
= {
865 &gEmuGraphicsWindowProtocolGuid
,
869 WinNtGraphicsWindowOpen
,
870 WinNtGraphicsWindowClose
,