]> git.proxmox.com Git - mirror_edk2.git/blob - EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c
1. Perfect libraries MSA files
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Bus / Uga / WinNtUgaScreen.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. 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 WinNtUgaScreen.c
15
16 Abstract:
17
18 This file produces the graphics abstration of UGA. It is called by
19 WinNtUgaDriver.c file which deals with the EFI 1.1 driver model.
20 This file just does graphics.
21
22 --*/
23
24 #include "WinNtUga.h"
25
26 EFI_WIN_NT_THUNK_PROTOCOL *mWinNt;
27 DWORD mTlsIndex = TLS_OUT_OF_INDEXES;
28 DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.
29 static EFI_EVENT mUgaScreenExitBootServicesEvent;
30
31 EFI_STATUS
32 WinNtUgaStartWindow (
33 IN UGA_PRIVATE_DATA *Private,
34 IN UINT32 HorizontalResolution,
35 IN UINT32 VerticalResolution,
36 IN UINT32 ColorDepth,
37 IN UINT32 RefreshRate
38 );
39
40 STATIC
41 VOID
42 EFIAPI
43 KillNtUgaThread (
44 IN EFI_EVENT Event,
45 IN VOID *Context
46 );
47
48 //
49 // UGA Protocol Member Functions
50 //
51
52 EFI_STATUS
53 EFIAPI
54 WinNtUgaGetMode (
55 EFI_UGA_DRAW_PROTOCOL *This,
56 UINT32 *HorizontalResolution,
57 UINT32 *VerticalResolution,
58 UINT32 *ColorDepth,
59 UINT32 *RefreshRate
60 )
61 /*++
62
63 Routine Description:
64 Return the current video mode information.
65
66 Arguments:
67 This - Protocol instance pointer.
68 HorizontalResolution - Current video horizontal resolution in pixels
69 VerticalResolution - Current video Vertical resolution in pixels
70 ColorDepth - Current video color depth in bits per pixel
71 RefreshRate - Current video refresh rate in Hz.
72
73 Returns:
74 EFI_SUCCESS - Mode information returned.
75 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
76 EFI_INVALID_PARAMETER - One of the input args was NULL.
77
78 --*/
79 // TODO: ADD IN/OUT description here
80 {
81 UGA_PRIVATE_DATA *Private;
82
83 Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This);
84
85 if (Private->HardwareNeedsStarting) {
86 return EFI_NOT_STARTED;
87 }
88
89 if ((HorizontalResolution == NULL) ||
90 (VerticalResolution == NULL) ||
91 (ColorDepth == NULL) ||
92 (RefreshRate == NULL)) {
93 return EFI_INVALID_PARAMETER;
94 }
95
96 *HorizontalResolution = Private->HorizontalResolution;
97 *VerticalResolution = Private->VerticalResolution;
98 *ColorDepth = Private->ColorDepth;
99 *RefreshRate = Private->RefreshRate;
100 return EFI_SUCCESS;
101 }
102
103 EFI_STATUS
104 EFIAPI
105 WinNtUgaSetMode (
106 EFI_UGA_DRAW_PROTOCOL *This,
107 UINT32 HorizontalResolution,
108 UINT32 VerticalResolution,
109 UINT32 ColorDepth,
110 UINT32 RefreshRate
111 )
112 /*++
113
114 Routine Description:
115 Return the current video mode information.
116
117 Arguments:
118 This - Protocol instance pointer.
119 HorizontalResolution - Current video horizontal resolution in pixels
120 VerticalResolution - Current video Vertical resolution in pixels
121 ColorDepth - Current video color depth in bits per pixel
122 RefreshRate - Current video refresh rate in Hz.
123
124 Returns:
125 EFI_SUCCESS - Mode information returned.
126 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
127 EFI_INVALID_PARAMETER - One of the input args was NULL.
128
129 --*/
130 // TODO: EFI_DEVICE_ERROR - add return value to function comment
131 // TODO: EFI_DEVICE_ERROR - add return value to function comment
132 // TODO: ADD IN/OUT description here
133 {
134 EFI_STATUS Status;
135 UGA_PRIVATE_DATA *Private;
136 EFI_UGA_PIXEL Fill;
137 EFI_UGA_PIXEL *NewFillLine;
138 RECT Rect;
139 UINTN Size;
140 UINTN Width;
141 UINTN Height;
142
143 Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This);
144
145 if (Private->HardwareNeedsStarting) {
146 Status = WinNtUgaStartWindow (
147 Private,
148 HorizontalResolution,
149 VerticalResolution,
150 ColorDepth,
151 RefreshRate
152 );
153 if (EFI_ERROR (Status)) {
154 return EFI_DEVICE_ERROR;
155 }
156
157 Private->HardwareNeedsStarting = FALSE;
158 } else {
159 //
160 // Change the resolution and resize of the window
161 //
162
163 //
164 // Free the old buffer. We do not save the content of the old buffer since the
165 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
166 // See EFI spec chepter 10.5-EFI_UGA_DRAW_PROTOCOL.SetMode()
167 //
168 Private->WinNtThunk->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);
169
170 //
171 // Allocate DIB frame buffer directly from NT for performance enhancement
172 // This buffer is the virtual screen/frame buffer. This buffer is not the
173 // same a a frame buffer. The first row of this buffer will be the bottom
174 // line of the image. This is an artifact of the way we draw to the screen.
175 //
176 Size = HorizontalResolution * VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);
177 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (
178 Private->WinNtThunk->GetProcessHeap (),
179 HEAP_ZERO_MEMORY,
180 Size
181 );
182
183 //
184 // Update the virtual screen info data structure
185 //
186 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
187 Private->VirtualScreenInfo->bV4Width = HorizontalResolution;
188 Private->VirtualScreenInfo->bV4Height = VerticalResolution;
189 Private->VirtualScreenInfo->bV4Planes = 1;
190 Private->VirtualScreenInfo->bV4BitCount = 32;
191 //
192 // uncompressed
193 //
194 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
195
196 //
197 // The rest of the allocated memory block is the virtual screen buffer
198 //
199 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
200
201 //
202 // Use the AdjuctWindowRect fuction to calculate the real width and height
203 // of the new window including the border and caption
204 //
205 Rect.left = 0;
206 Rect.top = 0;
207 Rect.right = HorizontalResolution;
208 Rect.bottom = VerticalResolution;
209
210 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
211
212 Width = Rect.right - Rect.left;
213 Height = Rect.bottom - Rect.top;
214
215 //
216 // Retrieve the original window position information
217 //
218 Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect);
219
220 //
221 // Adjust the window size
222 //
223 Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, Width, Height, TRUE);
224
225 }
226
227 NewFillLine = AllocatePool (sizeof (EFI_UGA_PIXEL) * HorizontalResolution);
228 if (NewFillLine == NULL) {
229 return EFI_DEVICE_ERROR;
230 }
231
232 if (Private->FillLine != NULL) {
233 FreePool (Private->FillLine);
234 }
235
236 Private->FillLine = NewFillLine;
237
238 Private->HorizontalResolution = HorizontalResolution;
239 Private->VerticalResolution = VerticalResolution;
240 Private->ColorDepth = ColorDepth;
241 Private->RefreshRate = RefreshRate;
242
243 Fill.Red = 0x00;
244 Fill.Green = 0x00;
245 Fill.Blue = 0x00;
246 This->Blt (
247 This,
248 &Fill,
249 EfiUgaVideoFill,
250 0,
251 0,
252 0,
253 0,
254 HorizontalResolution,
255 VerticalResolution,
256 HorizontalResolution * sizeof (EFI_UGA_PIXEL)
257 );
258 return EFI_SUCCESS;
259 }
260
261 EFI_STATUS
262 EFIAPI
263 WinNtUgaBlt (
264 IN EFI_UGA_DRAW_PROTOCOL *This,
265 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
266 IN EFI_UGA_BLT_OPERATION BltOperation,
267 IN UINTN SourceX,
268 IN UINTN SourceY,
269 IN UINTN DestinationX,
270 IN UINTN DestinationY,
271 IN UINTN Width,
272 IN UINTN Height,
273 IN UINTN Delta OPTIONAL
274 )
275 /*++
276
277 Routine Description:
278 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
279 onto the graphics screen starting a location (X, Y). (0, 0) is defined as
280 the upper left hand side of the screen. (X, Y) can be outside of the
281 current screen geometry and the BltBuffer will be cliped when it is
282 displayed. X and Y can be negative or positive. If Width or Height is
283 bigger than the current video screen the image will be clipped.
284
285 Arguments:
286 This - Protocol instance pointer.
287 X - X location on graphics screen.
288 Y - Y location on the graphics screen.
289 Width - Width of BltBuffer.
290 Height - Hight of BltBuffer
291 BltOperation - Operation to perform on BltBuffer and video memory
292 BltBuffer - Buffer containing data to blt into video buffer. This
293 buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)
294 SourceX - If the BltOperation is a EfiCopyBlt this is the source
295 of the copy. For other BLT operations this argument is not
296 used.
297 SourceX - If the BltOperation is a EfiCopyBlt this is the source
298 of the copy. For other BLT operations this argument is not
299 used.
300
301 Returns:
302 EFI_SUCCESS - The palette is updated with PaletteArray.
303 EFI_INVALID_PARAMETER - BltOperation is not valid.
304 EFI_DEVICE_ERROR - A hardware error occured writting to the video
305 buffer.
306
307 --*/
308 // TODO: SourceY - add argument and description to function comment
309 // TODO: DestinationX - add argument and description to function comment
310 // TODO: DestinationY - add argument and description to function comment
311 // TODO: Delta - add argument and description to function comment
312 {
313 UGA_PRIVATE_DATA *Private;
314 EFI_TPL OriginalTPL;
315 UINTN DstY;
316 UINTN SrcY;
317 RGBQUAD *VScreen;
318 RGBQUAD *VScreenSrc;
319 EFI_UGA_PIXEL *Blt;
320 UINTN Index;
321 RECT Rect;
322 EFI_UGA_PIXEL *FillPixel;
323
324 Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This);
325
326 if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
327 return EFI_INVALID_PARAMETER;
328 }
329
330 if (Width == 0 || Height == 0) {
331 return EFI_INVALID_PARAMETER;
332 }
333 //
334 // If Delta is zero, then the entire BltBuffer is being used, so Delta
335 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
336 // the number of bytes in each row can be computed.
337 //
338 if (Delta == 0) {
339 Delta = Width * sizeof (EFI_UGA_PIXEL);
340 }
341
342 //
343 // We need to fill the Virtual Screen buffer with the blt data.
344 // The virtual screen is upside down, as the first row is the bootom row of
345 // the image.
346 //
347
348 if (BltOperation == EfiUgaVideoToBltBuffer) {
349
350 //
351 // Video to BltBuffer: Source is Video, destination is BltBuffer
352 //
353 if (SourceY + Height > Private->VerticalResolution) {
354 return EFI_INVALID_PARAMETER;
355 }
356
357 if (SourceX + Width > Private->HorizontalResolution) {
358 return EFI_INVALID_PARAMETER;
359 }
360 //
361 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
362 // We would not want a timer based event (Cursor, ...) to come in while we are
363 // doing this operation.
364 //
365 OriginalTPL = gBS->RaiseTPL (EFI_TPL_NOTIFY);
366
367 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
368 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
369 VScreen = &Private->VirtualScreen[(Private->VerticalResolution - SrcY - 1) * Private->HorizontalResolution + SourceX];
370 CopyMem (Blt, VScreen, sizeof (EFI_UGA_PIXEL) * Width);
371 }
372 } else {
373 //
374 // BltBuffer to Video: Source is BltBuffer, destination is Video
375 //
376 if (DestinationY + Height > Private->VerticalResolution) {
377 return EFI_INVALID_PARAMETER;
378 }
379
380 if (DestinationX + Width > Private->HorizontalResolution) {
381 return EFI_INVALID_PARAMETER;
382 }
383
384 //
385 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
386 // We would not want a timer based event (Cursor, ...) to come in while we are
387 // doing this operation.
388 //
389 OriginalTPL = gBS->RaiseTPL (EFI_TPL_NOTIFY);
390
391 if (BltOperation == EfiUgaVideoFill) {
392 FillPixel = BltBuffer;
393 for (Index = 0; Index < Width; Index++) {
394 Private->FillLine[Index] = *FillPixel;
395 }
396 }
397
398 for (Index = 0; Index < Height; Index++) {
399 if (DestinationY <= SourceY) {
400 SrcY = SourceY + Index;
401 DstY = DestinationY + Index;
402 } else {
403 SrcY = SourceY + Height - Index - 1;
404 DstY = DestinationY + Height - Index - 1;
405 }
406
407 VScreen = &Private->VirtualScreen[(Private->VerticalResolution - DstY - 1) * Private->HorizontalResolution + DestinationX];
408 switch (BltOperation) {
409 case EfiUgaBltBufferToVideo:
410 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
411 CopyMem (VScreen, Blt, Width * sizeof (EFI_UGA_PIXEL));
412 break;
413
414 case EfiUgaVideoToVideo:
415 VScreenSrc = &Private->VirtualScreen[(Private->VerticalResolution - SrcY - 1) * Private->HorizontalResolution + SourceX];
416 CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_UGA_PIXEL));
417 break;
418
419 case EfiUgaVideoFill:
420 CopyMem (VScreen, Private->FillLine, Width * sizeof (EFI_UGA_PIXEL));
421 break;
422 }
423 }
424 }
425
426 if (BltOperation != EfiUgaVideoToBltBuffer) {
427 //
428 // Mark the area we just blted as Invalid so WM_PAINT will update.
429 //
430 Rect.left = DestinationX;
431 Rect.top = DestinationY;
432 Rect.right = DestinationX + Width;
433 Rect.bottom = DestinationY + Height;
434 Private->WinNtThunk->InvalidateRect (Private->WindowHandle, &Rect, FALSE);
435
436 //
437 // Send the WM_PAINT message to the thread that is drawing the window. We
438 // are in the main thread and the window drawing is in a child thread.
439 // There is a child thread per window. We have no CriticalSection or Mutex
440 // since we write the data and the other thread displays the data. While
441 // we may miss some data for a short period of time this is no different than
442 // a write combining on writes to a frame buffer.
443 //
444
445 Private->WinNtThunk->UpdateWindow (Private->WindowHandle);
446 }
447
448 gBS->RestoreTPL (OriginalTPL);
449
450 return EFI_SUCCESS;
451 }
452
453
454 //
455 // Construction and Destruction functions
456 //
457
458 EFI_STATUS
459 WinNtUgaSupported (
460 IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo
461 )
462 /*++
463
464 Routine Description:
465
466 Arguments:
467
468 Returns:
469
470 None
471
472 --*/
473 // TODO: WinNtIo - add argument and description to function comment
474 // TODO: EFI_UNSUPPORTED - add return value to function comment
475 // TODO: EFI_SUCCESS - add return value to function comment
476 {
477 //
478 // Check to see if the IO abstraction represents a device type we support.
479 //
480 // This would be replaced a check of PCI subsystem ID, etc.
481 //
482 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtUgaGuid)) {
483 return EFI_UNSUPPORTED;
484 }
485
486 return EFI_SUCCESS;
487 }
488
489 LRESULT
490 CALLBACK
491 WinNtUgaThreadWindowProc (
492 IN HWND hwnd,
493 IN UINT iMsg,
494 IN WPARAM wParam,
495 IN LPARAM lParam
496 )
497 /*++
498
499 Routine Description:
500 Win32 Windows event handler.
501
502 Arguments:
503 See Win32 Book
504
505 Returns:
506 See Win32 Book
507
508 --*/
509 // TODO: hwnd - add argument and description to function comment
510 // TODO: iMsg - add argument and description to function comment
511 // TODO: wParam - add argument and description to function comment
512 // TODO: lParam - add argument and description to function comment
513 {
514 UGA_PRIVATE_DATA *Private;
515 UINTN Size;
516 HDC Handle;
517 PAINTSTRUCT PaintStruct;
518 LPARAM Index;
519 EFI_INPUT_KEY Key;
520
521 //
522 // BugBug - if there are two instances of this DLL in memory (such as is
523 // the case for ERM), the correct instance of this function may not be called.
524 // This also means that the address of the mTlsIndex value will be wrong, and
525 // the value may be wrong too.
526 //
527
528
529 //
530 // Use mTlsIndex global to get a Thread Local Storage version of Private.
531 // This works since each Uga protocol has a unique Private data instance and
532 // a unique thread.
533 //
534 Private = mWinNt->TlsGetValue (mTlsIndex);
535 ASSERT (NULL != Private);
536
537 switch (iMsg) {
538 case WM_CREATE:
539 Size = Private->HorizontalResolution * Private->VerticalResolution * sizeof (RGBQUAD);
540
541 //
542 // Allocate DIB frame buffer directly from NT for performance enhancement
543 // This buffer is the virtual screen/frame buffer. This buffer is not the
544 // same a a frame buffer. The first fow of this buffer will be the bottom
545 // line of the image. This is an artifact of the way we draw to the screen.
546 //
547 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (
548 Private->WinNtThunk->GetProcessHeap (),
549 HEAP_ZERO_MEMORY,
550 Size
551 );
552
553 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
554 Private->VirtualScreenInfo->bV4Width = Private->HorizontalResolution;
555 Private->VirtualScreenInfo->bV4Height = Private->VerticalResolution;
556 Private->VirtualScreenInfo->bV4Planes = 1;
557 Private->VirtualScreenInfo->bV4BitCount = 32;
558 //
559 // uncompressed
560 //
561 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
562 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
563 return 0;
564
565 case WM_PAINT:
566 //
567 // I have not found a way to convert hwnd into a Private context. So for
568 // now we use this API to convert hwnd to Private data.
569 //
570
571 Handle = mWinNt->BeginPaint (hwnd, &PaintStruct);
572
573 mWinNt->SetDIBitsToDevice (
574 Handle, // Destination Device Context
575 0, // Destination X - 0
576 0, // Destination Y - 0
577 Private->HorizontalResolution, // Width
578 Private->VerticalResolution, // Height
579 0, // Source X
580 0, // Source Y
581 0, // DIB Start Scan Line
582 Private->VerticalResolution, // Number of scan lines
583 Private->VirtualScreen, // Address of array of DIB bits
584 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info
585 DIB_RGB_COLORS // RGB or palette indexes
586 );
587
588 mWinNt->EndPaint (hwnd, &PaintStruct);
589 return 0;
590
591 //
592 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
593 //
594 case WM_SYSKEYDOWN:
595 Key.ScanCode = 0;
596 switch (wParam) {
597 case VK_F10:
598 Key.ScanCode = SCAN_F10;
599 Key.UnicodeChar = 0;
600 UgaPrivateAddQ (Private, Key);
601 return 0;
602 }
603 break;
604
605 case WM_KEYDOWN:
606 Key.ScanCode = 0;
607 switch (wParam) {
608 case VK_HOME: Key.ScanCode = SCAN_HOME; break;
609 case VK_END: Key.ScanCode = SCAN_END; break;
610 case VK_LEFT: Key.ScanCode = SCAN_LEFT; break;
611 case VK_RIGHT: Key.ScanCode = SCAN_RIGHT; break;
612 case VK_UP: Key.ScanCode = SCAN_UP; break;
613 case VK_DOWN: Key.ScanCode = SCAN_DOWN; break;
614 case VK_DELETE: Key.ScanCode = SCAN_DELETE; break;
615 case VK_INSERT: Key.ScanCode = SCAN_INSERT; break;
616 case VK_PRIOR: Key.ScanCode = SCAN_PAGE_UP; break;
617 case VK_NEXT: Key.ScanCode = SCAN_PAGE_DOWN; break;
618 case VK_ESCAPE: Key.ScanCode = SCAN_ESC; break;
619
620 case VK_F1: Key.ScanCode = SCAN_F1; break;
621 case VK_F2: Key.ScanCode = SCAN_F2; break;
622 case VK_F3: Key.ScanCode = SCAN_F3; break;
623 case VK_F4: Key.ScanCode = SCAN_F4; break;
624 case VK_F5: Key.ScanCode = SCAN_F5; break;
625 case VK_F6: Key.ScanCode = SCAN_F6; break;
626 case VK_F7: Key.ScanCode = SCAN_F7; break;
627 case VK_F8: Key.ScanCode = SCAN_F8; break;
628 case VK_F9: Key.ScanCode = SCAN_F9; break;
629 case VK_F11: Key.ScanCode = SCAN_F11; break;
630 case VK_F12: Key.ScanCode = SCAN_F12; break;
631 }
632
633 if (Key.ScanCode != 0) {
634 Key.UnicodeChar = 0;
635 UgaPrivateAddQ (Private, Key);
636 }
637
638 return 0;
639
640 case WM_CHAR:
641 //
642 // The ESC key also generate WM_CHAR.
643 //
644 if (wParam == 0x1B) {
645 return 0;
646 }
647
648 for (Index = 0; Index < (lParam & 0xffff); Index++) {
649 if (wParam != 0) {
650 Key.UnicodeChar = (CHAR16) wParam;
651 Key.ScanCode = 0;
652 UgaPrivateAddQ (Private, Key);
653 }
654 }
655
656 return 0;
657
658 case WM_CLOSE:
659 //
660 // This close message is issued by user, core is not aware of this,
661 // so don't release the window display resource, just hide the window.
662 //
663 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE);
664 return 0;
665
666 case WM_DESTROY:
667 mWinNt->DestroyWindow (hwnd);
668 mWinNt->PostQuitMessage (0);
669
670 mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);
671
672 mWinNt->ExitThread (0);
673 return 0;
674
675 default:
676 break;
677 };
678
679 return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam);
680 }
681
682 DWORD
683 WINAPI
684 WinNtUgaThreadWinMain (
685 LPVOID lpParameter
686 )
687 /*++
688
689 Routine Description:
690
691 This thread simulates the end of WinMain () aplication. Each Winow nededs
692 to process it's events. The messages are dispatched to
693 WinNtUgaThreadWindowProc ().
694
695 Be very careful sine WinNtUgaThreadWinMain () and WinNtUgaThreadWindowProc ()
696 are running in a seperate thread. We have to do this to process the events.
697
698 Arguments:
699
700 lpParameter - Handle of window to manage.
701
702 Returns:
703
704 if a WM_QUIT message is returned exit.
705
706 --*/
707 {
708 MSG Message;
709 UGA_PRIVATE_DATA *Private;
710 ATOM Atom;
711 RECT Rect;
712
713 Private = (UGA_PRIVATE_DATA *) lpParameter;
714 ASSERT (NULL != Private);
715
716 //
717 // Since each thread has unique private data, save the private data in Thread
718 // Local Storage slot. Then the shared global mTlsIndex can be used to get
719 // thread specific context.
720 //
721 Private->WinNtThunk->TlsSetValue (mTlsIndex, Private);
722
723 Private->ThreadId = Private->WinNtThunk->GetCurrentThreadId ();
724
725 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);
726 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
727 Private->WindowsClass.lpfnWndProc = WinNtUgaThreadWindowProc;
728 Private->WindowsClass.cbClsExtra = 0;
729 Private->WindowsClass.cbWndExtra = 0;
730 Private->WindowsClass.hInstance = NULL;
731 Private->WindowsClass.hIcon = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION);
732 Private->WindowsClass.hCursor = Private->WinNtThunk->LoadCursor (NULL, IDC_ARROW);
733 Private->WindowsClass.hbrBackground = (HBRUSH) COLOR_WINDOW;
734 Private->WindowsClass.lpszMenuName = NULL;
735 Private->WindowsClass.lpszClassName = WIN_NT_UGA_CLASS_NAME;
736 Private->WindowsClass.hIconSm = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION);
737
738 //
739 // This call will fail after the first time, but thats O.K. since we only need
740 // WIN_NT_UGA_CLASS_NAME to exist to create the window.
741 //
742 // Note: Multiple instances of this DLL will use the same instance of this
743 // Class, including the callback function, unless the Class is unregistered and
744 // successfully registered again.
745 //
746 Atom = Private->WinNtThunk->RegisterClassEx (&Private->WindowsClass);
747
748 //
749 // Setting Rect values to allow for the AdjustWindowRect to provide
750 // us the correct sizes for the client area when doing the CreateWindowEx
751 //
752 Rect.top = 0;
753 Rect.bottom = Private->VerticalResolution;
754 Rect.left = 0;
755 Rect.right = Private->HorizontalResolution;
756
757 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
758
759 Private->WindowHandle = Private->WinNtThunk->CreateWindowEx (
760 0,
761 WIN_NT_UGA_CLASS_NAME,
762 Private->WindowName,
763 WS_OVERLAPPEDWINDOW,
764 CW_USEDEFAULT,
765 CW_USEDEFAULT,
766 Rect.right - Rect.left,
767 Rect.bottom - Rect.top,
768 NULL,
769 NULL,
770 NULL,
771 &Private
772 );
773
774 //
775 // The reset of this thread is the standard winows program. We need a sperate
776 // thread since we must process the message loop to make windows act like
777 // windows.
778 //
779
780 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_SHOW);
781 Private->WinNtThunk->UpdateWindow (Private->WindowHandle);
782
783 //
784 // Let the main thread get some work done
785 //
786 Private->WinNtThunk->ReleaseSemaphore (Private->ThreadInited, 1, NULL);
787
788 //
789 // This is the message loop that all Windows programs need.
790 //
791 while (Private->WinNtThunk->GetMessage (&Message, Private->WindowHandle, 0, 0)) {
792 Private->WinNtThunk->TranslateMessage (&Message);
793 Private->WinNtThunk->DispatchMessage (&Message);
794 }
795
796 return Message.wParam;
797 }
798
799 EFI_STATUS
800 WinNtUgaStartWindow (
801 IN UGA_PRIVATE_DATA *Private,
802 IN UINT32 HorizontalResolution,
803 IN UINT32 VerticalResolution,
804 IN UINT32 ColorDepth,
805 IN UINT32 RefreshRate
806 )
807 /*++
808
809 Routine Description:
810
811 TODO: Add function description
812
813 Arguments:
814
815 Private - TODO: add argument description
816 HorizontalResolution - TODO: add argument description
817 VerticalResolution - TODO: add argument description
818 ColorDepth - TODO: add argument description
819 RefreshRate - TODO: add argument description
820
821 Returns:
822
823 TODO: add return values
824
825 --*/
826 {
827 EFI_STATUS Status;
828 DWORD NewThreadId;
829
830
831 mWinNt = Private->WinNtThunk;
832
833 //
834 // Initialize a Thread Local Storge variable slot. We use TLS to get the
835 // correct Private data instance into the windows thread.
836 //
837 if (mTlsIndex == TLS_OUT_OF_INDEXES) {
838 ASSERT (0 == mTlsIndexUseCount);
839 mTlsIndex = Private->WinNtThunk->TlsAlloc ();
840 }
841
842 //
843 // always increase the use count!
844 //
845 mTlsIndexUseCount++;
846
847 Private->HorizontalResolution = HorizontalResolution;
848 Private->VerticalResolution = VerticalResolution;
849
850 //
851 // Register to be notified on exit boot services so we can destroy the window.
852 //
853 Status = gBS->CreateEvent (
854 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
855 EFI_TPL_CALLBACK,
856 KillNtUgaThread,
857 Private,
858 &mUgaScreenExitBootServicesEvent
859 );
860
861 Private->ThreadInited = Private->WinNtThunk->CreateSemaphore (NULL, 0, 1, NULL);
862 Private->ThreadHandle = Private->WinNtThunk->CreateThread (
863 NULL,
864 0,
865 WinNtUgaThreadWinMain,
866 (VOID *) Private,
867 0,
868 &NewThreadId
869 );
870
871 //
872 // The other thread has entered the windows message loop so we can
873 // continue our initialization.
874 //
875 Private->WinNtThunk->WaitForSingleObject (Private->ThreadInited, INFINITE);
876 Private->WinNtThunk->CloseHandle (Private->ThreadInited);
877
878 return Status;
879 }
880
881 EFI_STATUS
882 WinNtUgaConstructor (
883 UGA_PRIVATE_DATA *Private
884 )
885 /*++
886
887 Routine Description:
888
889 Arguments:
890
891 Returns:
892
893 None
894
895 --*/
896 // TODO: Private - add argument and description to function comment
897 // TODO: EFI_SUCCESS - add return value to function comment
898 {
899
900 Private->UgaDraw.GetMode = WinNtUgaGetMode;
901 Private->UgaDraw.SetMode = WinNtUgaSetMode;
902 Private->UgaDraw.Blt = WinNtUgaBlt;
903
904 Private->HardwareNeedsStarting = TRUE;
905 Private->FillLine = NULL;
906
907 WinNtUgaInitializeSimpleTextInForWindow (Private);
908
909 return EFI_SUCCESS;
910 }
911
912 EFI_STATUS
913 WinNtUgaDestructor (
914 UGA_PRIVATE_DATA *Private
915 )
916 /*++
917
918 Routine Description:
919
920 Arguments:
921
922 Returns:
923
924 None
925
926 --*/
927 // TODO: Private - add argument and description to function comment
928 // TODO: EFI_SUCCESS - add return value to function comment
929 {
930 UINT32 UnregisterReturn;
931
932 if (!Private->HardwareNeedsStarting) {
933 //
934 // BugBug: Shutdown Uga Hardware and any child devices.
935 //
936 Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
937 Private->WinNtThunk->CloseHandle (Private->ThreadHandle);
938
939 mTlsIndexUseCount--;
940
941 //
942 // The callback function for another window could still be called,
943 // so we need to make sure there are no more users of mTlsIndex.
944 //
945 if (0 == mTlsIndexUseCount) {
946 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
947
948 Private->WinNtThunk->TlsFree (mTlsIndex);
949 mTlsIndex = TLS_OUT_OF_INDEXES;
950
951 UnregisterReturn = Private->WinNtThunk->UnregisterClass (
952 Private->WindowsClass.lpszClassName,
953 Private->WindowsClass.hInstance
954 );
955 }
956
957 WinNtUgaDestroySimpleTextInForWindow (Private);
958 }
959
960 return EFI_SUCCESS;
961 }
962
963 STATIC
964 VOID
965 EFIAPI
966 KillNtUgaThread (
967 IN EFI_EVENT Event,
968 IN VOID *Context
969 )
970 /*++
971
972 Routine Description:
973
974 This is the UGA screen's callback notification function for exit-boot-services.
975 All we do here is call WinNtUgaDestructor().
976
977 Arguments:
978
979 Event - not used
980 Context - pointer to the Private structure.
981
982 Returns:
983
984 None.
985
986 --*/
987 {
988 EFI_STATUS Status;
989 Status = WinNtUgaDestructor (Context);
990 }