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