]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Win/Host/WinGopScreen.c
EmulatorPkg/Win: Add input/output support
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinGopScreen.c
1 /** @file
2
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
8
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.
11
12 Module Name:
13
14 WinGopScreen.c
15
16 Abstract:
17
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.
21
22
23 **/
24
25 #include "WinGop.h"
26
27 DWORD mTlsIndex = TLS_OUT_OF_INDEXES;
28 DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.
29
30 BOOLEAN
31 WinNtGopConvertParamToEfiKeyShiftState (
32 IN GRAPHICS_PRIVATE_DATA *Private,
33 IN WPARAM *wParam,
34 IN LPARAM *lParam,
35 IN BOOLEAN Flag
36 )
37 {
38 switch (*wParam) {
39 //
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.
44 //
45 case VK_SHIFT:
46 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
47 Private->RightShift = Flag;
48 } else {
49 Private->LeftShift = Flag;
50 }
51 return TRUE;
52
53 case VK_LSHIFT:
54 Private->LeftShift = Flag;
55 return TRUE;
56
57 case VK_RSHIFT:
58 Private->RightShift = Flag;
59 return TRUE;
60
61 case VK_CONTROL:
62 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
63 Private->RightCtrl= Flag;
64 } else {
65 Private->LeftCtrl = Flag;
66 }
67 return TRUE;
68
69 case VK_LCONTROL:
70 Private->LeftCtrl = Flag;
71 return TRUE;
72
73 case VK_RCONTROL:
74 Private->RightCtrl = Flag;
75 return TRUE;
76
77 case VK_LWIN:
78 Private->LeftLogo = Flag;
79 return TRUE;
80
81 case VK_RWIN:
82 Private->RightLogo = Flag;
83 return TRUE;
84
85 case VK_APPS:
86 Private->Menu = Flag;
87 return TRUE;
88 //
89 // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,
90 // so SySReq shift state is not supported here.
91 //
92 case VK_PRINT:
93 Private->SysReq = Flag;
94 return TRUE;
95 //
96 // For Alt Keystroke.
97 //
98 case VK_MENU:
99 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
100 Private->RightAlt = Flag;
101 } else {
102 Private->LeftAlt = Flag;
103 }
104 return TRUE;
105
106 default:
107 return FALSE;
108 }
109 }
110
111 BOOLEAN
112 WinNtGopConvertParamToEfiKey (
113 IN GRAPHICS_PRIVATE_DATA *Private,
114 IN WPARAM *wParam,
115 IN LPARAM *lParam,
116 IN EFI_INPUT_KEY *Key
117 )
118 {
119 BOOLEAN Flag;
120 Flag = FALSE;
121 switch (*wParam) {
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;
133
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;
145
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;
159
160 //
161 // Set toggle state
162 //
163 case VK_NUMLOCK:
164 Private->NumLock = (BOOLEAN)(!Private->NumLock);
165 Flag = TRUE;
166 break;
167 case VK_SCROLL:
168 Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);
169 Flag = TRUE;
170 break;
171 case VK_CAPITAL:
172 Private->CapsLock = (BOOLEAN)(!Private->CapsLock);
173 Flag = TRUE;
174 break;
175 }
176
177 return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;
178 }
179
180
181 //
182 // GOP Protocol Member Functions
183 //
184
185 /**
186 Change the resolution and resize of the window
187 **/
188 EFI_STATUS
189 EFIAPI
190 WinNtWndSize (
191 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
192 IN UINT32 Width,
193 IN UINT32 Height
194 )
195 {
196 UINT32 Size;
197 GRAPHICS_PRIVATE_DATA *Private;
198 RECT Rect;
199 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewFillLine;
200
201 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
202 Private->Width = Width;
203 Private->Height = Height;
204
205
206 //
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()
210 //
211 if (Private->VirtualScreenInfo != NULL) {
212 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
213 }
214
215 //
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.
220 //
221 Size = Private->Width * Private->Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);
222 Private->VirtualScreenInfo = HeapAlloc (
223 GetProcessHeap (),
224 HEAP_ZERO_MEMORY,
225 Size
226 );
227
228 //
229 // Update the virtual screen info data structure
230 //
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;
236 //
237 // uncompressed
238 //
239 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
240
241 //
242 // The rest of the allocated memory block is the virtual screen buffer
243 //
244 Private->VirtualScreen = (RGBQUAD *)(Private->VirtualScreenInfo + 1);
245
246 //
247 // Use the AdjuctWindowRect fuction to calculate the real width and height
248 // of the new window including the border and caption
249 //
250 Rect.left = 0;
251 Rect.top = 0;
252 Rect.right = Private->Width;
253 Rect.bottom = Private->Height;
254
255 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
256
257 Width = Rect.right - Rect.left;
258 Height = Rect.bottom - Rect.top;
259
260 //
261 // Retrieve the original window position information
262 //
263 GetWindowRect (Private->WindowHandle, &Rect);
264
265 //
266 // Adjust the window size
267 //
268 MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);
269
270 NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Private->Width);
271 if (NewFillLine == NULL) {
272 return EFI_DEVICE_ERROR;
273 }
274
275 if (Private->FillLine != NULL) {
276 FreePool (Private->FillLine);
277 }
278
279 Private->FillLine = NewFillLine;
280 return EFI_SUCCESS;
281 }
282
283 /**
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.
290
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.
306
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
310 buffer.
311
312 **/
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
317 EFI_STATUS
318 WinNtWndBlt (
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
323 )
324 {
325 GRAPHICS_PRIVATE_DATA *Private;
326 UINTN DstY;
327 UINTN SrcY;
328 RGBQUAD *VScreen;
329 RGBQUAD *VScreenSrc;
330 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
331 UINTN Index;
332 RECT Rect;
333 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;
334 UINT32 VerticalResolution;
335 UINT32 HorizontalResolution;
336
337 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
338
339 //
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
342 // the image.
343 //
344 VerticalResolution = Private->VirtualScreenInfo->bV4Height;
345 HorizontalResolution = Private->VirtualScreenInfo->bV4Width;
346 if (BltOperation == EfiBltVideoToBltBuffer) {
347
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);
352 }
353 } else {
354 if (BltOperation == EfiBltVideoFill) {
355 FillPixel = BltBuffer;
356 for (Index = 0; Index < Args->Width; Index++) {
357 Private->FillLine[Index] = *FillPixel;
358 }
359 }
360
361 for (Index = 0; Index < Args->Height; Index++) {
362 if (Args->DestinationY <= Args->SourceY) {
363 SrcY = Args->SourceY + Index;
364 DstY = Args->DestinationY + Index;
365 } else {
366 SrcY = Args->SourceY + Args->Height - Index - 1;
367 DstY = Args->DestinationY + Args->Height - Index - 1;
368 }
369
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));
375 break;
376
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));
380 break;
381
382 case EfiBltVideoFill:
383 CopyMem (VScreen, Private->FillLine, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
384 break;
385 }
386 }
387 }
388
389 if (BltOperation != EfiBltVideoToBltBuffer) {
390 //
391 // Mark the area we just blted as Invalid so WM_PAINT will update.
392 //
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);
398
399 //
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.
406 //
407
408 UpdateWindow (Private->WindowHandle);
409 }
410
411 return EFI_SUCCESS;
412 }
413
414
415
416 /**
417 Win32 Windows event handler.
418
419 See Win32 Book
420
421 @return See Win32 Book
422
423 **/
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
428 LRESULT
429 CALLBACK
430 WinNtGopThreadWindowProc (
431 IN HWND hwnd,
432 IN UINT iMsg,
433 IN WPARAM wParam,
434 IN LPARAM lParam
435 )
436 {
437 GRAPHICS_PRIVATE_DATA *Private;
438 UINTN Size;
439 HDC Handle;
440 PAINTSTRUCT PaintStruct;
441 LPARAM Index;
442 EFI_INPUT_KEY Key;
443 BOOLEAN AltIsPress;
444
445 //
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.
450 //
451
452
453 //
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
456 // a unique thread.
457 //
458 AltIsPress = FALSE;
459 Private = TlsGetValue (mTlsIndex);
460 ASSERT (NULL != Private);
461
462 switch (iMsg) {
463 case WM_CREATE:
464 Size = Private->Width * Private->Height * sizeof (RGBQUAD);
465
466 //
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.
471 //
472 Private->VirtualScreenInfo = HeapAlloc (
473 GetProcessHeap (),
474 HEAP_ZERO_MEMORY,
475 Size
476 );
477
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;
483 //
484 // uncompressed
485 //
486 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
487 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
488 return 0;
489
490 case WM_PAINT:
491 //
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.
494 //
495
496 Handle = BeginPaint (hwnd, &PaintStruct);
497
498 SetDIBitsToDevice (
499 Handle, // Destination Device Context
500 0, // Destination X - 0
501 0, // Destination Y - 0
502 Private->Width, // Width
503 Private->Height, // Height
504 0, // Source X
505 0, // Source Y
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
511 );
512
513 EndPaint (hwnd, &PaintStruct);
514 return 0;
515
516 //
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.
520 //
521 case WM_SYSKEYDOWN:
522
523 Key.ScanCode = 0;
524 Key.UnicodeChar = CHAR_NULL;
525 switch (wParam) {
526 case VK_F10:
527 Key.ScanCode = SCAN_F10;
528 Key.UnicodeChar = CHAR_NULL;
529 GopPrivateAddKey (Private, Key);
530 return 0;
531 }
532
533 //
534 // If ALT or ALT + modifier key is pressed.
535 //
536 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
537 if (Key.ScanCode != 0){
538 //
539 // If ALT is pressed with other ScanCode.
540 // Always revers the left Alt for simple.
541 //
542 Private->LeftAlt = TRUE;
543 }
544 GopPrivateAddKey (Private, Key);
545 //
546 // When Alt is released there is no windoes message, so
547 // clean it after using it.
548 //
549 Private->RightAlt = FALSE;
550 Private->LeftAlt = FALSE;
551 return 0;
552 }
553 AltIsPress = TRUE;
554
555 case WM_CHAR:
556 //
557 // The ESC key also generate WM_CHAR.
558 //
559 if (wParam == 0x1B) {
560 return 0;
561 }
562
563 if (AltIsPress == TRUE) {
564 //
565 // If AltIsPress is true that means the Alt key is pressed.
566 //
567 Private->LeftAlt = TRUE;
568 }
569 for (Index = 0; Index < (lParam & 0xffff); Index++) {
570 if (wParam != 0) {
571 Key.UnicodeChar = (CHAR16) wParam;
572 Key.ScanCode = SCAN_NULL;
573 GopPrivateAddKey (Private, Key);
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 return 0;
585
586 case WM_SYSKEYUP:
587 //
588 // ALT is pressed with another key released
589 //
590 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
591 return 0;
592
593 case WM_KEYDOWN:
594 Key.ScanCode = SCAN_NULL;
595 Key.UnicodeChar = CHAR_NULL;
596 //
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.
599 //
600 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
601 //
602 // Support the partial keystroke, add all keydown event into the queue.
603 //
604 GopPrivateAddKey (Private, Key);
605 }
606 return 0;
607
608 case WM_KEYUP:
609 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
610 return 0;
611
612 case WM_CLOSE:
613 //
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.
616 //
617 ShowWindow (Private->WindowHandle, SW_HIDE);
618 return 0;
619
620 case WM_DESTROY:
621 DestroyWindow (hwnd);
622 PostQuitMessage (0);
623
624 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
625
626 ExitThread (0);
627
628 default:
629 break;
630 };
631
632 return DefWindowProc (hwnd, iMsg, wParam, lParam);
633 }
634
635
636 /**
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.
642
643 @param lpParameter Handle of window to manage.
644
645 @return if a WM_QUIT message is returned exit.
646
647 **/
648 DWORD
649 WINAPI
650 WinNtGopThreadWinMain (
651 LPVOID lpParameter
652 )
653 {
654 MSG Message;
655 GRAPHICS_PRIVATE_DATA *Private;
656 RECT Rect;
657
658 Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;
659 ASSERT (NULL != Private);
660
661 //
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.
665 //
666 TlsSetValue (mTlsIndex, Private);
667
668 Private->ThreadId = GetCurrentThreadId ();
669
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);
682
683 //
684 // Use 100 x 100 as initial Window size.
685 //
686 Private->Width = 100;
687 Private->Height = 100;
688
689
690 //
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.
693 //
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.
697 //
698 RegisterClassEx (&Private->WindowsClass);
699
700 //
701 // Setting Rect values to allow for the AdjustWindowRect to provide
702 // us the correct sizes for the client area when doing the CreateWindowEx
703 //
704 Rect.top = 0;
705 Rect.bottom = Private->Height;
706 Rect.left = 0;
707 Rect.right = Private->Width;
708
709 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
710
711 Private->WindowHandle = CreateWindowEx (
712 0,
713 WIN_NT_GOP_CLASS_NAME,
714 Private->WindowName,
715 WS_OVERLAPPEDWINDOW,
716 CW_USEDEFAULT,
717 CW_USEDEFAULT,
718 Rect.right - Rect.left,
719 Rect.bottom - Rect.top,
720 NULL,
721 NULL,
722 NULL,
723 (VOID **)&Private
724 );
725
726 //
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
729 // windows.
730 //
731
732 ShowWindow (Private->WindowHandle, SW_SHOW);
733 UpdateWindow (Private->WindowHandle);
734
735 //
736 // Let the main thread get some work done
737 //
738 ReleaseSemaphore (Private->ThreadInited, 1, NULL);
739
740 //
741 // This is the message loop that all Windows programs need.
742 //
743 while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {
744 TranslateMessage (&Message);
745 DispatchMessage (&Message);
746 }
747
748 return (DWORD)Message.wParam;
749 }
750
751
752 /**
753 TODO: Add function description
754
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
760
761 @return TODO: add return values
762
763 **/
764 EFI_STATUS
765 EFIAPI
766 WinNtGraphicsWindowOpen (
767 IN EMU_IO_THUNK_PROTOCOL *This
768 )
769 {
770 DWORD NewThreadId;
771 GRAPHICS_PRIVATE_DATA *Private;
772
773 Private = AllocateZeroPool (sizeof (*Private));
774
775 GopPrivateCreateQ (Private, &Private->QueueForRead);
776
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;
785
786 Private->WindowName = This->ConfigString;
787 //
788 // Initialize a Thread Local Storge variable slot. We use TLS to get the
789 // correct Private data instance into the windows thread.
790 //
791 if (mTlsIndex == TLS_OUT_OF_INDEXES) {
792 ASSERT (0 == mTlsIndexUseCount);
793 mTlsIndex = TlsAlloc ();
794 }
795
796 //
797 // always increase the use count!
798 //
799 mTlsIndexUseCount++;
800
801 Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);
802 Private->ThreadHandle = CreateThread (
803 NULL,
804 0,
805 WinNtGopThreadWinMain,
806 (VOID *) Private,
807 0,
808 &NewThreadId
809 );
810
811 //
812 // The other thread has entered the windows message loop so we can
813 // continue our initialization.
814 //
815 WaitForSingleObject (Private->ThreadInited, INFINITE);
816 CloseHandle (Private->ThreadInited);
817
818 This->Private = Private;
819 This->Interface = &Private->GraphicsWindowIo;
820
821 return EFI_SUCCESS;
822 }
823
824 EFI_STATUS
825 EFIAPI
826 WinNtGraphicsWindowClose (
827 IN EMU_IO_THUNK_PROTOCOL *This
828 )
829 {
830 GRAPHICS_PRIVATE_DATA *Private;
831
832 Private = (GRAPHICS_PRIVATE_DATA *)This->Private;
833
834 //
835 // BugBug: Shutdown GOP Hardware and any child devices.
836 //
837 SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
838 CloseHandle (Private->ThreadHandle);
839
840 mTlsIndexUseCount--;
841
842 //
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.
845 //
846 if (0 == mTlsIndexUseCount) {
847 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
848
849 TlsFree (mTlsIndex);
850 mTlsIndex = TLS_OUT_OF_INDEXES;
851
852 UnregisterClass (
853 Private->WindowsClass.lpszClassName,
854 Private->WindowsClass.hInstance
855 );
856 }
857
858
859 GopPrivateDestroyQ (Private, &Private->QueueForRead);
860 return EFI_SUCCESS;
861 }
862
863
864 EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {
865 &gEmuGraphicsWindowProtocolGuid,
866 NULL,
867 NULL,
868 0,
869 WinNtGraphicsWindowOpen,
870 WinNtGraphicsWindowClose,
871 NULL
872 };