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