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