]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinGopScreen.c
EmulatorPkg/Win: Fix various typos
[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
3d6b7fd3 300 @param Height Height of BltBuffer\r
7a465451
RN
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
3d6b7fd3 314 @retval EFI_DEVICE_ERROR A hardware error occurred writing to the video\r
7a465451
RN
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
109197ee
MH
402 INT32 PosX;\r
403 INT32 PosY;\r
7a465451 404\r
7a465451
RN
405 //\r
406 // Use mTlsIndex global to get a Thread Local Storage version of Private.\r
407 // This works since each Gop protocol has a unique Private data instance and\r
408 // a unique thread.\r
409 //\r
410 AltIsPress = FALSE;\r
411 Private = TlsGetValue (mTlsIndex);\r
412 ASSERT (NULL != Private);\r
413\r
414 switch (iMsg) {\r
7a465451 415 case WM_PAINT:\r
7a465451
RN
416 Handle = BeginPaint (hwnd, &PaintStruct);\r
417\r
418 SetDIBitsToDevice (\r
419 Handle, // Destination Device Context\r
420 0, // Destination X - 0\r
421 0, // Destination Y - 0\r
422 Private->Width, // Width\r
423 Private->Height, // Height\r
424 0, // Source X\r
425 0, // Source Y\r
426 0, // DIB Start Scan Line\r
427 Private->Height, // Number of scan lines\r
d773459e 428 Private->VirtualScreenInfo + 1, // Address of array of DIB bits\r
7a465451
RN
429 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info\r
430 DIB_RGB_COLORS // RGB or palette indexes\r
431 );\r
432\r
433 EndPaint (hwnd, &PaintStruct);\r
434 return 0;\r
435\r
436 //\r
437 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case\r
438 // WM_SYSKEYDOWN is posted when F10 is pressed or\r
439 // holds down ALT key and then presses another key.\r
440 //\r
441 case WM_SYSKEYDOWN:\r
442\r
443 Key.ScanCode = 0;\r
444 Key.UnicodeChar = CHAR_NULL;\r
445 switch (wParam) {\r
446 case VK_F10:\r
447 Key.ScanCode = SCAN_F10;\r
448 Key.UnicodeChar = CHAR_NULL;\r
449 GopPrivateAddKey (Private, Key);\r
450 return 0;\r
451 }\r
452\r
453 //\r
454 // If ALT or ALT + modifier key is pressed.\r
455 //\r
456 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
457 if (Key.ScanCode != 0){\r
458 //\r
459 // If ALT is pressed with other ScanCode.\r
460 // Always revers the left Alt for simple.\r
461 //\r
462 Private->LeftAlt = TRUE;\r
463 }\r
464 GopPrivateAddKey (Private, Key);\r
465 //\r
466 // When Alt is released there is no windoes message, so\r
467 // clean it after using it.\r
468 //\r
469 Private->RightAlt = FALSE;\r
470 Private->LeftAlt = FALSE;\r
471 return 0;\r
472 }\r
473 AltIsPress = TRUE;\r
474\r
475 case WM_CHAR:\r
476 //\r
477 // The ESC key also generate WM_CHAR.\r
478 //\r
479 if (wParam == 0x1B) {\r
480 return 0;\r
481 }\r
482\r
483 if (AltIsPress == TRUE) {\r
484 //\r
485 // If AltIsPress is true that means the Alt key is pressed.\r
486 //\r
487 Private->LeftAlt = TRUE;\r
488 }\r
489 for (Index = 0; Index < (lParam & 0xffff); Index++) {\r
490 if (wParam != 0) {\r
491 Key.UnicodeChar = (CHAR16) wParam;\r
492 Key.ScanCode = SCAN_NULL;\r
493 GopPrivateAddKey (Private, Key);\r
494 }\r
495 }\r
496 if (AltIsPress == TRUE) {\r
497 //\r
498 // When Alt is released there is no windoes message, so\r
499 // clean it after using it.\r
500 //\r
501 Private->LeftAlt = FALSE;\r
502 Private->RightAlt = FALSE;\r
503 }\r
504 return 0;\r
505\r
506 case WM_SYSKEYUP:\r
507 //\r
508 // ALT is pressed with another key released\r
509 //\r
510 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
511 return 0;\r
512\r
513 case WM_KEYDOWN:\r
514 Key.ScanCode = SCAN_NULL;\r
515 Key.UnicodeChar = CHAR_NULL;\r
516 //\r
517 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR\r
518 // So if there is no modifier key updated, skip the WM_KEYDOWN even.\r
519 //\r
520 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
521 //\r
522 // Support the partial keystroke, add all keydown event into the queue.\r
523 //\r
524 GopPrivateAddKey (Private, Key);\r
525 }\r
526 return 0;\r
527\r
528 case WM_KEYUP:\r
529 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
530 return 0;\r
531\r
109197ee
MH
532 case WM_MOUSEMOVE:\r
533 PosX = GET_X_LPARAM (lParam);\r
534 PosY = GET_Y_LPARAM (lParam);\r
535\r
536 if (Private->PointerPreviousX != PosX) {\r
537 Private->PointerState.RelativeMovementX += (PosX - Private->PointerPreviousX);\r
538 Private->PointerPreviousX = PosX;\r
539 Private->PointerStateChanged = TRUE;\r
540 }\r
541\r
542 if (Private->PointerPreviousY != PosY) {\r
543 Private->PointerState.RelativeMovementY += (PosY - Private->PointerPreviousY);\r
544 Private->PointerPreviousY = PosY;\r
545 Private->PointerStateChanged = TRUE;\r
546 }\r
547\r
548 Private->PointerState.RelativeMovementZ = 0;\r
549 return 0;\r
550\r
551 case WM_LBUTTONDOWN:\r
552 Private->PointerState.LeftButton = TRUE;\r
553 Private->PointerStateChanged = TRUE;\r
554 return 0;\r
555\r
556 case WM_LBUTTONUP:\r
557 Private->PointerState.LeftButton = FALSE;\r
558 Private->PointerStateChanged = TRUE;\r
559 return 0;\r
560\r
561 case WM_RBUTTONDOWN:\r
562 Private->PointerState.RightButton = TRUE;\r
563 Private->PointerStateChanged = TRUE;\r
564 return 0;\r
565\r
566 case WM_RBUTTONUP:\r
567 Private->PointerState.RightButton = FALSE;\r
568 Private->PointerStateChanged = TRUE;\r
569 return 0;\r
570\r
7a465451
RN
571 case WM_CLOSE:\r
572 //\r
573 // This close message is issued by user, core is not aware of this,\r
574 // so don't release the window display resource, just hide the window.\r
575 //\r
576 ShowWindow (Private->WindowHandle, SW_HIDE);\r
577 return 0;\r
578\r
579 case WM_DESTROY:\r
580 DestroyWindow (hwnd);\r
581 PostQuitMessage (0);\r
582\r
583 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
584\r
585 ExitThread (0);\r
586\r
587 default:\r
588 break;\r
589 };\r
590\r
591 return DefWindowProc (hwnd, iMsg, wParam, lParam);\r
592}\r
593\r
594\r
595/**\r
3d6b7fd3
AC
596 This thread simulates the end of WinMain () application. Each Window needs\r
597 to process its events. The messages are dispatched to\r
7a465451 598 WinNtGopThreadWindowProc ().\r
3d6b7fd3
AC
599 Be very careful since WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()\r
600 are running in a separate thread. We have to do this to process the events.\r
7a465451
RN
601\r
602 @param lpParameter Handle of window to manage.\r
603\r
604 @return if a WM_QUIT message is returned exit.\r
605\r
606**/\r
607DWORD\r
608WINAPI\r
609WinNtGopThreadWinMain (\r
610 LPVOID lpParameter\r
611 )\r
612{\r
613 MSG Message;\r
614 GRAPHICS_PRIVATE_DATA *Private;\r
615 RECT Rect;\r
616\r
617 Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;\r
618 ASSERT (NULL != Private);\r
619\r
620 //\r
621 // Since each thread has unique private data, save the private data in Thread\r
622 // Local Storage slot. Then the shared global mTlsIndex can be used to get\r
623 // thread specific context.\r
624 //\r
625 TlsSetValue (mTlsIndex, Private);\r
626\r
627 Private->ThreadId = GetCurrentThreadId ();\r
628\r
629 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);\r
630 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
631 Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;\r
632 Private->WindowsClass.cbClsExtra = 0;\r
633 Private->WindowsClass.cbWndExtra = 0;\r
634 Private->WindowsClass.hInstance = NULL;\r
635 Private->WindowsClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);\r
636 Private->WindowsClass.hCursor = LoadCursor (NULL, IDC_ARROW);\r
637 Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;\r
638 Private->WindowsClass.lpszMenuName = NULL;\r
639 Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;\r
640 Private->WindowsClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);\r
641\r
642 //\r
643 // Use 100 x 100 as initial Window size.\r
644 //\r
645 Private->Width = 100;\r
646 Private->Height = 100;\r
647\r
648\r
649 //\r
650 // This call will fail after the first time, but thats O.K. since we only need\r
651 // WIN_NT_GOP_CLASS_NAME to exist to create the window.\r
652 //\r
7a465451
RN
653 RegisterClassEx (&Private->WindowsClass);\r
654\r
655 //\r
656 // Setting Rect values to allow for the AdjustWindowRect to provide\r
657 // us the correct sizes for the client area when doing the CreateWindowEx\r
658 //\r
659 Rect.top = 0;\r
660 Rect.bottom = Private->Height;\r
661 Rect.left = 0;\r
662 Rect.right = Private->Width;\r
663\r
664 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
665\r
666 Private->WindowHandle = CreateWindowEx (\r
667 0,\r
668 WIN_NT_GOP_CLASS_NAME,\r
669 Private->WindowName,\r
670 WS_OVERLAPPEDWINDOW,\r
671 CW_USEDEFAULT,\r
672 CW_USEDEFAULT,\r
673 Rect.right - Rect.left,\r
674 Rect.bottom - Rect.top,\r
675 NULL,\r
676 NULL,\r
677 NULL,\r
678 (VOID **)&Private\r
679 );\r
680\r
681 //\r
3d6b7fd3 682 // The reset of this thread is the standard windows program. We need a separate\r
7a465451
RN
683 // thread since we must process the message loop to make windows act like\r
684 // windows.\r
685 //\r
686\r
687 ShowWindow (Private->WindowHandle, SW_SHOW);\r
688 UpdateWindow (Private->WindowHandle);\r
689\r
690 //\r
691 // Let the main thread get some work done\r
692 //\r
693 ReleaseSemaphore (Private->ThreadInited, 1, NULL);\r
694\r
695 //\r
696 // This is the message loop that all Windows programs need.\r
697 //\r
698 while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {\r
699 TranslateMessage (&Message);\r
700 DispatchMessage (&Message);\r
701 }\r
702\r
703 return (DWORD)Message.wParam;\r
704}\r
705\r
706\r
707/**\r
708 TODO: Add function description\r
709\r
710 @param Private TODO: add argument description\r
711 @param HorizontalResolution TODO: add argument description\r
712 @param VerticalResolution TODO: add argument description\r
713 @param ColorDepth TODO: add argument description\r
714 @param RefreshRate TODO: add argument description\r
715\r
716 @return TODO: add return values\r
717\r
718**/\r
719EFI_STATUS\r
720EFIAPI\r
721WinNtGraphicsWindowOpen (\r
722 IN EMU_IO_THUNK_PROTOCOL *This\r
723 )\r
724{\r
725 DWORD NewThreadId;\r
726 GRAPHICS_PRIVATE_DATA *Private;\r
727\r
728 Private = AllocateZeroPool (sizeof (*Private));\r
729\r
730 GopPrivateCreateQ (Private, &Private->QueueForRead);\r
731\r
732 Private->GraphicsWindowIo.Size = WinNtWndSize;\r
733 Private->GraphicsWindowIo.CheckKey = WinNtWndCheckKey;\r
734 Private->GraphicsWindowIo.GetKey = WinNtWndGetKey;\r
735 Private->GraphicsWindowIo.KeySetState = WinNtWndKeySetState;\r
736 Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;\r
737 Private->GraphicsWindowIo.Blt = WinNtWndBlt;\r
738 Private->GraphicsWindowIo.CheckPointer = WinNtWndCheckPointer;\r
739 Private->GraphicsWindowIo.GetPointerState = WinNtWndGetPointerState;\r
740\r
741 Private->WindowName = This->ConfigString;\r
742 //\r
743 // Initialize a Thread Local Storge variable slot. We use TLS to get the\r
744 // correct Private data instance into the windows thread.\r
745 //\r
746 if (mTlsIndex == TLS_OUT_OF_INDEXES) {\r
747 ASSERT (0 == mTlsIndexUseCount);\r
748 mTlsIndex = TlsAlloc ();\r
749 }\r
750\r
751 //\r
752 // always increase the use count!\r
753 //\r
754 mTlsIndexUseCount++;\r
755\r
756 Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);\r
757 Private->ThreadHandle = CreateThread (\r
758 NULL,\r
759 0,\r
760 WinNtGopThreadWinMain,\r
761 (VOID *) Private,\r
762 0,\r
763 &NewThreadId\r
764 );\r
765\r
766 //\r
767 // The other thread has entered the windows message loop so we can\r
768 // continue our initialization.\r
769 //\r
770 WaitForSingleObject (Private->ThreadInited, INFINITE);\r
771 CloseHandle (Private->ThreadInited);\r
772\r
773 This->Private = Private;\r
774 This->Interface = &Private->GraphicsWindowIo;\r
775\r
776 return EFI_SUCCESS;\r
777}\r
778\r
779EFI_STATUS\r
780EFIAPI\r
781WinNtGraphicsWindowClose (\r
782 IN EMU_IO_THUNK_PROTOCOL *This\r
783)\r
784{\r
785 GRAPHICS_PRIVATE_DATA *Private;\r
786\r
787 Private = (GRAPHICS_PRIVATE_DATA *)This->Private;\r
788\r
789 //\r
790 // BugBug: Shutdown GOP Hardware and any child devices.\r
791 //\r
792 SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);\r
793 CloseHandle (Private->ThreadHandle);\r
794\r
795 mTlsIndexUseCount--;\r
796\r
797 //\r
798 // The callback function for another window could still be called,\r
799 // so we need to make sure there are no more users of mTlsIndex.\r
800 //\r
801 if (0 == mTlsIndexUseCount) {\r
802 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);\r
803\r
804 TlsFree (mTlsIndex);\r
805 mTlsIndex = TLS_OUT_OF_INDEXES;\r
806\r
807 UnregisterClass (\r
808 Private->WindowsClass.lpszClassName,\r
809 Private->WindowsClass.hInstance\r
810 );\r
811 }\r
812\r
813\r
814 GopPrivateDestroyQ (Private, &Private->QueueForRead);\r
815 return EFI_SUCCESS;\r
816}\r
817\r
818\r
819EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {\r
820 &gEmuGraphicsWindowProtocolGuid,\r
821 NULL,\r
822 NULL,\r
823 0,\r
824 WinNtGraphicsWindowOpen,\r
825 WinNtGraphicsWindowClose,\r
826 NULL\r
827};\r