]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Win/Host/WinGopScreen.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinGopScreen.c
1 /** @file
2
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6 Module Name:
7
8 WinGopScreen.c
9
10 Abstract:
11
12 This file produces the graphics abstration of GOP. It is called by
13 WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.
14 This file just does graphics.
15
16
17 **/
18
19 #include "WinGop.h"
20
21 DWORD mTlsIndex = TLS_OUT_OF_INDEXES;
22 DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.
23
24 BOOLEAN
25 WinNtGopConvertParamToEfiKeyShiftState (
26 IN GRAPHICS_PRIVATE_DATA *Private,
27 IN WPARAM *wParam,
28 IN LPARAM *lParam,
29 IN BOOLEAN Flag
30 )
31 {
32 switch (*wParam) {
33 //
34 // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish
35 // left and right Ctrl, and Shift key.
36 // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.
37 // Therefor, we can not set the correct Shift state here.
38 //
39 case VK_SHIFT:
40 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
41 Private->RightShift = Flag;
42 } else {
43 Private->LeftShift = Flag;
44 }
45 return TRUE;
46
47 case VK_LSHIFT:
48 Private->LeftShift = Flag;
49 return TRUE;
50
51 case VK_RSHIFT:
52 Private->RightShift = Flag;
53 return TRUE;
54
55 case VK_CONTROL:
56 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
57 Private->RightCtrl= Flag;
58 } else {
59 Private->LeftCtrl = Flag;
60 }
61 return TRUE;
62
63 case VK_LCONTROL:
64 Private->LeftCtrl = Flag;
65 return TRUE;
66
67 case VK_RCONTROL:
68 Private->RightCtrl = Flag;
69 return TRUE;
70
71 case VK_LWIN:
72 Private->LeftLogo = Flag;
73 return TRUE;
74
75 case VK_RWIN:
76 Private->RightLogo = Flag;
77 return TRUE;
78
79 case VK_APPS:
80 Private->Menu = Flag;
81 return TRUE;
82 //
83 // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,
84 // so SySReq shift state is not supported here.
85 //
86 case VK_PRINT:
87 Private->SysReq = Flag;
88 return TRUE;
89 //
90 // For Alt Keystroke.
91 //
92 case VK_MENU:
93 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
94 Private->RightAlt = Flag;
95 } else {
96 Private->LeftAlt = Flag;
97 }
98 return TRUE;
99
100 default:
101 return FALSE;
102 }
103 }
104
105 BOOLEAN
106 WinNtGopConvertParamToEfiKey (
107 IN GRAPHICS_PRIVATE_DATA *Private,
108 IN WPARAM *wParam,
109 IN LPARAM *lParam,
110 IN EFI_INPUT_KEY *Key
111 )
112 {
113 BOOLEAN Flag;
114 Flag = FALSE;
115 switch (*wParam) {
116 case VK_HOME: Key->ScanCode = SCAN_HOME; Flag = TRUE; break;
117 case VK_END: Key->ScanCode = SCAN_END; Flag = TRUE; break;
118 case VK_LEFT: Key->ScanCode = SCAN_LEFT; Flag = TRUE; break;
119 case VK_RIGHT: Key->ScanCode = SCAN_RIGHT; Flag = TRUE; break;
120 case VK_UP: Key->ScanCode = SCAN_UP; Flag = TRUE; break;
121 case VK_DOWN: Key->ScanCode = SCAN_DOWN; Flag = TRUE; break;
122 case VK_DELETE: Key->ScanCode = SCAN_DELETE; Flag = TRUE; break;
123 case VK_INSERT: Key->ScanCode = SCAN_INSERT; Flag = TRUE; break;
124 case VK_PRIOR: Key->ScanCode = SCAN_PAGE_UP; Flag = TRUE; break;
125 case VK_NEXT: Key->ScanCode = SCAN_PAGE_DOWN; Flag = TRUE; break;
126 case VK_ESCAPE: Key->ScanCode = SCAN_ESC; Flag = TRUE; break;
127
128 case VK_F1: Key->ScanCode = SCAN_F1; Flag = TRUE; break;
129 case VK_F2: Key->ScanCode = SCAN_F2; Flag = TRUE; break;
130 case VK_F3: Key->ScanCode = SCAN_F3; Flag = TRUE; break;
131 case VK_F4: Key->ScanCode = SCAN_F4; Flag = TRUE; break;
132 case VK_F5: Key->ScanCode = SCAN_F5; Flag = TRUE; break;
133 case VK_F6: Key->ScanCode = SCAN_F6; Flag = TRUE; break;
134 case VK_F7: Key->ScanCode = SCAN_F7; Flag = TRUE; break;
135 case VK_F8: Key->ScanCode = SCAN_F8; Flag = TRUE; break;
136 case VK_F9: Key->ScanCode = SCAN_F9; Flag = TRUE; break;
137 case VK_F11: Key->ScanCode = SCAN_F11; Flag = TRUE; break;
138 case VK_F12: Key->ScanCode = SCAN_F12; Flag = TRUE; break;
139
140 case VK_F13: Key->ScanCode = SCAN_F13; Flag = TRUE; break;
141 case VK_F14: Key->ScanCode = SCAN_F14; Flag = TRUE; break;
142 case VK_F15: Key->ScanCode = SCAN_F15; Flag = TRUE; break;
143 case VK_F16: Key->ScanCode = SCAN_F16; Flag = TRUE; break;
144 case VK_F17: Key->ScanCode = SCAN_F17; Flag = TRUE; break;
145 case VK_F18: Key->ScanCode = SCAN_F18; Flag = TRUE; break;
146 case VK_F19: Key->ScanCode = SCAN_F19; Flag = TRUE; break;
147 case VK_F20: Key->ScanCode = SCAN_F20; Flag = TRUE; break;
148 case VK_F21: Key->ScanCode = SCAN_F21; Flag = TRUE; break;
149 case VK_F22: Key->ScanCode = SCAN_F22; Flag = TRUE; break;
150 case VK_F23: Key->ScanCode = SCAN_F23; Flag = TRUE; break;
151 case VK_F24: Key->ScanCode = SCAN_F24; Flag = TRUE; break;
152 case VK_PAUSE: Key->ScanCode = SCAN_PAUSE; Flag = TRUE; break;
153
154 //
155 // Set toggle state
156 //
157 case VK_NUMLOCK:
158 Private->NumLock = (BOOLEAN)(!Private->NumLock);
159 Flag = TRUE;
160 break;
161 case VK_SCROLL:
162 Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);
163 Flag = TRUE;
164 break;
165 case VK_CAPITAL:
166 Private->CapsLock = (BOOLEAN)(!Private->CapsLock);
167 Flag = TRUE;
168 break;
169 }
170
171 return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;
172 }
173
174
175 //
176 // GOP Protocol Member Functions
177 //
178
179 /**
180 Change the resolution and resize of the window
181 **/
182 EFI_STATUS
183 EFIAPI
184 WinNtWndSize (
185 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
186 IN UINT32 Width,
187 IN UINT32 Height
188 )
189 {
190 RETURN_STATUS RStatus;
191 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION Info;
192 GRAPHICS_PRIVATE_DATA *Private;
193 RECT Rect;
194 BITMAPV4HEADER *VirtualScreenInfo;
195 FRAME_BUFFER_CONFIGURE *FrameBufferConfigure;
196 UINTN FrameBufferConfigureSize;
197
198 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
199
200 //
201 // Allocate DIB frame buffer directly from NT for performance enhancement
202 // This buffer is the virtual screen/frame buffer.
203 //
204 VirtualScreenInfo = HeapAlloc (
205 GetProcessHeap (),
206 HEAP_ZERO_MEMORY,
207 Width * Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER)
208 );
209 if (VirtualScreenInfo == NULL) {
210 return EFI_OUT_OF_RESOURCES;
211 }
212
213 //
214 // Update the virtual screen info data structure
215 // Use negative Height to make sure screen/buffer are using the same coordinate.
216 //
217 VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
218 VirtualScreenInfo->bV4Width = Width;
219 VirtualScreenInfo->bV4Height = -(LONG)Height;
220 VirtualScreenInfo->bV4Planes = 1;
221 VirtualScreenInfo->bV4BitCount = 32;
222 //
223 // uncompressed
224 //
225 VirtualScreenInfo->bV4V4Compression = BI_RGB;
226
227 Info.HorizontalResolution = Width;
228 Info.VerticalResolution = Height;
229 Info.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
230 Info.PixelsPerScanLine = Width;
231 FrameBufferConfigureSize = 0;
232 RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, NULL, &FrameBufferConfigureSize);
233 ASSERT (RStatus == EFI_BUFFER_TOO_SMALL);
234 FrameBufferConfigure = AllocatePool (FrameBufferConfigureSize);
235 if (FrameBufferConfigure == NULL) {
236 HeapFree (GetProcessHeap (), 0, VirtualScreenInfo);
237 return EFI_OUT_OF_RESOURCES;
238 }
239 RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, FrameBufferConfigure, &FrameBufferConfigureSize);
240 ASSERT_RETURN_ERROR (RStatus);
241
242
243 if (Private->FrameBufferConfigure != NULL) {
244 FreePool (Private->FrameBufferConfigure);
245 }
246 Private->FrameBufferConfigure = FrameBufferConfigure;
247
248 //
249 // Free the old buffer. We do not save the content of the old buffer since the
250 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
251 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()
252 //
253 if (Private->VirtualScreenInfo != NULL) {
254 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
255 }
256 Private->VirtualScreenInfo = VirtualScreenInfo;
257
258 Private->Width = Width;
259 Private->Height = Height;
260
261 //
262 // Use the AdjuctWindowRect fuction to calculate the real width and height
263 // of the new window including the border and caption
264 //
265 Rect.left = 0;
266 Rect.top = 0;
267 Rect.right = Width;
268 Rect.bottom = Height;
269
270 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
271
272 Width = Rect.right - Rect.left;
273 Height = Rect.bottom - Rect.top;
274
275 //
276 // Retrieve the original window position information
277 //
278 GetWindowRect (Private->WindowHandle, &Rect);
279
280 //
281 // Adjust the window size
282 //
283 MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);
284
285 return EFI_SUCCESS;
286 }
287
288 /**
289 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
290 onto the graphics screen starting a location (X, Y). (0, 0) is defined as
291 the upper left hand side of the screen. (X, Y) can be outside of the
292 current screen geometry and the BltBuffer will be cliped when it is
293 displayed. X and Y can be negative or positive. If Width or Height is
294 bigger than the current video screen the image will be clipped.
295
296 @param This Protocol instance pointer.
297 @param X X location on graphics screen.
298 @param Y Y location on the graphics screen.
299 @param Width Width of BltBuffer.
300 @param Height Hight of BltBuffer
301 @param BltOperation Operation to perform on BltBuffer and video memory
302 @param BltBuffer Buffer containing data to blt into video buffer.
303 This buffer has a size of
304 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
305 @param SourceX If the BltOperation is a EfiCopyBlt this is the
306 source of the copy. For other BLT operations this
307 argument is not used.
308 @param SourceX If the BltOperation is a EfiCopyBlt this is the
309 source of the copy. For other BLT operations this
310 argument is not used.
311
312 @retval EFI_SUCCESS The palette is updated with PaletteArray.
313 @retval EFI_INVALID_PARAMETER BltOperation is not valid.
314 @retval EFI_DEVICE_ERROR A hardware error occured writting to the video
315 buffer.
316
317 **/
318 // TODO: SourceY - add argument and description to function comment
319 // TODO: DestinationX - add argument and description to function comment
320 // TODO: DestinationY - add argument and description to function comment
321 // TODO: Delta - add argument and description to function comment
322 EFI_STATUS
323 WinNtWndBlt (
324 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
325 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
326 IN EFI_UGA_BLT_OPERATION BltOperation,
327 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
328 )
329 {
330 RETURN_STATUS RStatus;
331 GRAPHICS_PRIVATE_DATA *Private;
332 RECT Rect;
333
334 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
335 RStatus = FrameBufferBlt (
336 Private->FrameBufferConfigure,
337 BltBuffer,
338 BltOperation,
339 Args->SourceX, Args->SourceY,
340 Args->DestinationX, Args->DestinationY,
341 Args->Width, Args->Height,
342 Args->Delta
343 );
344 if (RETURN_ERROR (RStatus)) {
345 return (EFI_STATUS)RStatus;
346 }
347
348 if (BltOperation != EfiBltVideoToBltBuffer) {
349 //
350 // Mark the area we just blted as Invalid so WM_PAINT will update.
351 //
352 Rect.left = (LONG)Args->DestinationX;
353 Rect.top = (LONG)Args->DestinationY;
354 Rect.right = (LONG)(Args->DestinationX + Args->Width);
355 Rect.bottom = (LONG)(Args->DestinationY + Args->Height);
356 InvalidateRect (Private->WindowHandle, &Rect, FALSE);
357
358 //
359 // Send the WM_PAINT message to the thread that is drawing the window. We
360 // are in the main thread and the window drawing is in a child thread.
361 // There is a child thread per window. We have no CriticalSection or Mutex
362 // since we write the data and the other thread displays the data. While
363 // we may miss some data for a short period of time this is no different than
364 // a write combining on writes to a frame buffer.
365 //
366
367 UpdateWindow (Private->WindowHandle);
368 }
369
370 return EFI_SUCCESS;
371 }
372
373
374
375 /**
376 Win32 Windows event handler.
377
378 See Win32 Book
379
380 @return See Win32 Book
381
382 **/
383 // TODO: hwnd - add argument and description to function comment
384 // TODO: iMsg - add argument and description to function comment
385 // TODO: wParam - add argument and description to function comment
386 // TODO: lParam - add argument and description to function comment
387 LRESULT
388 CALLBACK
389 WinNtGopThreadWindowProc (
390 IN HWND hwnd,
391 IN UINT iMsg,
392 IN WPARAM wParam,
393 IN LPARAM lParam
394 )
395 {
396 GRAPHICS_PRIVATE_DATA *Private;
397 HDC Handle;
398 PAINTSTRUCT PaintStruct;
399 LPARAM Index;
400 EFI_INPUT_KEY Key;
401 BOOLEAN AltIsPress;
402
403 //
404 // Use mTlsIndex global to get a Thread Local Storage version of Private.
405 // This works since each Gop protocol has a unique Private data instance and
406 // a unique thread.
407 //
408 AltIsPress = FALSE;
409 Private = TlsGetValue (mTlsIndex);
410 ASSERT (NULL != Private);
411
412 switch (iMsg) {
413 case WM_PAINT:
414 Handle = BeginPaint (hwnd, &PaintStruct);
415
416 SetDIBitsToDevice (
417 Handle, // Destination Device Context
418 0, // Destination X - 0
419 0, // Destination Y - 0
420 Private->Width, // Width
421 Private->Height, // Height
422 0, // Source X
423 0, // Source Y
424 0, // DIB Start Scan Line
425 Private->Height, // Number of scan lines
426 Private->VirtualScreenInfo + 1, // Address of array of DIB bits
427 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info
428 DIB_RGB_COLORS // RGB or palette indexes
429 );
430
431 EndPaint (hwnd, &PaintStruct);
432 return 0;
433
434 //
435 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
436 // WM_SYSKEYDOWN is posted when F10 is pressed or
437 // holds down ALT key and then presses another key.
438 //
439 case WM_SYSKEYDOWN:
440
441 Key.ScanCode = 0;
442 Key.UnicodeChar = CHAR_NULL;
443 switch (wParam) {
444 case VK_F10:
445 Key.ScanCode = SCAN_F10;
446 Key.UnicodeChar = CHAR_NULL;
447 GopPrivateAddKey (Private, Key);
448 return 0;
449 }
450
451 //
452 // If ALT or ALT + modifier key is pressed.
453 //
454 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
455 if (Key.ScanCode != 0){
456 //
457 // If ALT is pressed with other ScanCode.
458 // Always revers the left Alt for simple.
459 //
460 Private->LeftAlt = TRUE;
461 }
462 GopPrivateAddKey (Private, Key);
463 //
464 // When Alt is released there is no windoes message, so
465 // clean it after using it.
466 //
467 Private->RightAlt = FALSE;
468 Private->LeftAlt = FALSE;
469 return 0;
470 }
471 AltIsPress = TRUE;
472
473 case WM_CHAR:
474 //
475 // The ESC key also generate WM_CHAR.
476 //
477 if (wParam == 0x1B) {
478 return 0;
479 }
480
481 if (AltIsPress == TRUE) {
482 //
483 // If AltIsPress is true that means the Alt key is pressed.
484 //
485 Private->LeftAlt = TRUE;
486 }
487 for (Index = 0; Index < (lParam & 0xffff); Index++) {
488 if (wParam != 0) {
489 Key.UnicodeChar = (CHAR16) wParam;
490 Key.ScanCode = SCAN_NULL;
491 GopPrivateAddKey (Private, Key);
492 }
493 }
494 if (AltIsPress == TRUE) {
495 //
496 // When Alt is released there is no windoes message, so
497 // clean it after using it.
498 //
499 Private->LeftAlt = FALSE;
500 Private->RightAlt = FALSE;
501 }
502 return 0;
503
504 case WM_SYSKEYUP:
505 //
506 // ALT is pressed with another key released
507 //
508 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
509 return 0;
510
511 case WM_KEYDOWN:
512 Key.ScanCode = SCAN_NULL;
513 Key.UnicodeChar = CHAR_NULL;
514 //
515 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR
516 // So if there is no modifier key updated, skip the WM_KEYDOWN even.
517 //
518 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
519 //
520 // Support the partial keystroke, add all keydown event into the queue.
521 //
522 GopPrivateAddKey (Private, Key);
523 }
524 return 0;
525
526 case WM_KEYUP:
527 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
528 return 0;
529
530 case WM_CLOSE:
531 //
532 // This close message is issued by user, core is not aware of this,
533 // so don't release the window display resource, just hide the window.
534 //
535 ShowWindow (Private->WindowHandle, SW_HIDE);
536 return 0;
537
538 case WM_DESTROY:
539 DestroyWindow (hwnd);
540 PostQuitMessage (0);
541
542 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
543
544 ExitThread (0);
545
546 default:
547 break;
548 };
549
550 return DefWindowProc (hwnd, iMsg, wParam, lParam);
551 }
552
553
554 /**
555 This thread simulates the end of WinMain () aplication. Each Winow nededs
556 to process it's events. The messages are dispatched to
557 WinNtGopThreadWindowProc ().
558 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
559 are running in a seperate thread. We have to do this to process the events.
560
561 @param lpParameter Handle of window to manage.
562
563 @return if a WM_QUIT message is returned exit.
564
565 **/
566 DWORD
567 WINAPI
568 WinNtGopThreadWinMain (
569 LPVOID lpParameter
570 )
571 {
572 MSG Message;
573 GRAPHICS_PRIVATE_DATA *Private;
574 RECT Rect;
575
576 Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;
577 ASSERT (NULL != Private);
578
579 //
580 // Since each thread has unique private data, save the private data in Thread
581 // Local Storage slot. Then the shared global mTlsIndex can be used to get
582 // thread specific context.
583 //
584 TlsSetValue (mTlsIndex, Private);
585
586 Private->ThreadId = GetCurrentThreadId ();
587
588 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);
589 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
590 Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;
591 Private->WindowsClass.cbClsExtra = 0;
592 Private->WindowsClass.cbWndExtra = 0;
593 Private->WindowsClass.hInstance = NULL;
594 Private->WindowsClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
595 Private->WindowsClass.hCursor = LoadCursor (NULL, IDC_ARROW);
596 Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;
597 Private->WindowsClass.lpszMenuName = NULL;
598 Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;
599 Private->WindowsClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
600
601 //
602 // Use 100 x 100 as initial Window size.
603 //
604 Private->Width = 100;
605 Private->Height = 100;
606
607
608 //
609 // This call will fail after the first time, but thats O.K. since we only need
610 // WIN_NT_GOP_CLASS_NAME to exist to create the window.
611 //
612 RegisterClassEx (&Private->WindowsClass);
613
614 //
615 // Setting Rect values to allow for the AdjustWindowRect to provide
616 // us the correct sizes for the client area when doing the CreateWindowEx
617 //
618 Rect.top = 0;
619 Rect.bottom = Private->Height;
620 Rect.left = 0;
621 Rect.right = Private->Width;
622
623 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
624
625 Private->WindowHandle = CreateWindowEx (
626 0,
627 WIN_NT_GOP_CLASS_NAME,
628 Private->WindowName,
629 WS_OVERLAPPEDWINDOW,
630 CW_USEDEFAULT,
631 CW_USEDEFAULT,
632 Rect.right - Rect.left,
633 Rect.bottom - Rect.top,
634 NULL,
635 NULL,
636 NULL,
637 (VOID **)&Private
638 );
639
640 //
641 // The reset of this thread is the standard winows program. We need a sperate
642 // thread since we must process the message loop to make windows act like
643 // windows.
644 //
645
646 ShowWindow (Private->WindowHandle, SW_SHOW);
647 UpdateWindow (Private->WindowHandle);
648
649 //
650 // Let the main thread get some work done
651 //
652 ReleaseSemaphore (Private->ThreadInited, 1, NULL);
653
654 //
655 // This is the message loop that all Windows programs need.
656 //
657 while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {
658 TranslateMessage (&Message);
659 DispatchMessage (&Message);
660 }
661
662 return (DWORD)Message.wParam;
663 }
664
665
666 /**
667 TODO: Add function description
668
669 @param Private TODO: add argument description
670 @param HorizontalResolution TODO: add argument description
671 @param VerticalResolution TODO: add argument description
672 @param ColorDepth TODO: add argument description
673 @param RefreshRate TODO: add argument description
674
675 @return TODO: add return values
676
677 **/
678 EFI_STATUS
679 EFIAPI
680 WinNtGraphicsWindowOpen (
681 IN EMU_IO_THUNK_PROTOCOL *This
682 )
683 {
684 DWORD NewThreadId;
685 GRAPHICS_PRIVATE_DATA *Private;
686
687 Private = AllocateZeroPool (sizeof (*Private));
688
689 GopPrivateCreateQ (Private, &Private->QueueForRead);
690
691 Private->GraphicsWindowIo.Size = WinNtWndSize;
692 Private->GraphicsWindowIo.CheckKey = WinNtWndCheckKey;
693 Private->GraphicsWindowIo.GetKey = WinNtWndGetKey;
694 Private->GraphicsWindowIo.KeySetState = WinNtWndKeySetState;
695 Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;
696 Private->GraphicsWindowIo.Blt = WinNtWndBlt;
697 Private->GraphicsWindowIo.CheckPointer = WinNtWndCheckPointer;
698 Private->GraphicsWindowIo.GetPointerState = WinNtWndGetPointerState;
699
700 Private->WindowName = This->ConfigString;
701 //
702 // Initialize a Thread Local Storge variable slot. We use TLS to get the
703 // correct Private data instance into the windows thread.
704 //
705 if (mTlsIndex == TLS_OUT_OF_INDEXES) {
706 ASSERT (0 == mTlsIndexUseCount);
707 mTlsIndex = TlsAlloc ();
708 }
709
710 //
711 // always increase the use count!
712 //
713 mTlsIndexUseCount++;
714
715 Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);
716 Private->ThreadHandle = CreateThread (
717 NULL,
718 0,
719 WinNtGopThreadWinMain,
720 (VOID *) Private,
721 0,
722 &NewThreadId
723 );
724
725 //
726 // The other thread has entered the windows message loop so we can
727 // continue our initialization.
728 //
729 WaitForSingleObject (Private->ThreadInited, INFINITE);
730 CloseHandle (Private->ThreadInited);
731
732 This->Private = Private;
733 This->Interface = &Private->GraphicsWindowIo;
734
735 return EFI_SUCCESS;
736 }
737
738 EFI_STATUS
739 EFIAPI
740 WinNtGraphicsWindowClose (
741 IN EMU_IO_THUNK_PROTOCOL *This
742 )
743 {
744 GRAPHICS_PRIVATE_DATA *Private;
745
746 Private = (GRAPHICS_PRIVATE_DATA *)This->Private;
747
748 //
749 // BugBug: Shutdown GOP Hardware and any child devices.
750 //
751 SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
752 CloseHandle (Private->ThreadHandle);
753
754 mTlsIndexUseCount--;
755
756 //
757 // The callback function for another window could still be called,
758 // so we need to make sure there are no more users of mTlsIndex.
759 //
760 if (0 == mTlsIndexUseCount) {
761 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
762
763 TlsFree (mTlsIndex);
764 mTlsIndex = TLS_OUT_OF_INDEXES;
765
766 UnregisterClass (
767 Private->WindowsClass.lpszClassName,
768 Private->WindowsClass.hInstance
769 );
770 }
771
772
773 GopPrivateDestroyQ (Private, &Private->QueueForRead);
774 return EFI_SUCCESS;
775 }
776
777
778 EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {
779 &gEmuGraphicsWindowProtocolGuid,
780 NULL,
781 NULL,
782 0,
783 WinNtGraphicsWindowOpen,
784 WinNtGraphicsWindowClose,
785 NULL
786 };