]> code.delx.au - refind/blob - refind/screen.c
0.4.1 release
[refind] / refind / screen.c
1 /*
2 * refit/screen.c
3 * Screen handling functions
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "global.h"
38 #include "screen.h"
39 #include "config.h"
40 #include "libegint.h"
41 #include "refit_call_wrapper.h"
42
43 #include "egemb_refind_banner.h"
44
45 // Console defines and variables
46
47 UINTN ConWidth;
48 UINTN ConHeight;
49 CHAR16 *BlankLine;
50
51 static VOID SwitchToText(IN BOOLEAN CursorEnabled);
52 static VOID SwitchToGraphics(VOID);
53 static VOID DrawScreenHeader(IN CHAR16 *Title);
54
55 // UGA defines and variables
56
57 UINTN UGAWidth;
58 UINTN UGAHeight;
59 BOOLEAN AllowGraphicsMode;
60
61 EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
62 EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
63
64 static BOOLEAN GraphicsScreenDirty;
65
66 // general defines and variables
67
68 static BOOLEAN haveError = FALSE;
69
70 //
71 // Screen initialization and switching
72 //
73
74 VOID InitScreen(VOID)
75 {
76 UINTN i;
77
78 // initialize libeg
79 egInitScreen();
80
81 if (egHasGraphicsMode()) {
82 egGetScreenSize(&UGAWidth, &UGAHeight);
83 AllowGraphicsMode = TRUE;
84 } else {
85 AllowGraphicsMode = FALSE;
86 egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode
87 }
88 GraphicsScreenDirty = TRUE;
89
90 // disable cursor
91 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
92
93 // get size of text console
94 if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) {
95 // use default values on error
96 ConWidth = 80;
97 ConHeight = 25;
98 }
99
100 // make a buffer for a whole text line
101 BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16));
102 for (i = 0; i < ConWidth; i++)
103 BlankLine[i] = ' ';
104 BlankLine[i] = 0;
105
106 // show the banner (even when in graphics mode)
107 DrawScreenHeader(L"Initializing...");
108 }
109
110 VOID SetupScreen(VOID)
111 {
112 if (GlobalConfig.TextOnly) {
113 // switch to text mode if requested
114 AllowGraphicsMode = FALSE;
115 SwitchToText(FALSE);
116
117 } else if (AllowGraphicsMode) {
118 // clear screen and show banner
119 // (now we know we'll stay in graphics mode)
120 if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0) &&
121 egSetScreenSize(GlobalConfig.RequestedScreenWidth, GlobalConfig.RequestedScreenHeight)) {
122 UGAWidth = GlobalConfig.RequestedScreenWidth;
123 UGAHeight = GlobalConfig.RequestedScreenHeight;
124 } // if user requested a particular screen resolution
125 SwitchToGraphics();
126 BltClearScreen(TRUE);
127 }
128 }
129
130 static VOID SwitchToText(IN BOOLEAN CursorEnabled)
131 {
132 egSetGraphicsModeEnabled(FALSE);
133 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled);
134 }
135
136 static VOID SwitchToGraphics(VOID)
137 {
138 if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) {
139 egSetGraphicsModeEnabled(TRUE);
140 GraphicsScreenDirty = TRUE;
141 }
142 }
143
144 //
145 // Screen control for running tools
146 //
147
148 VOID BeginTextScreen(IN CHAR16 *Title)
149 {
150 DrawScreenHeader(Title);
151 SwitchToText(FALSE);
152
153 // reset error flag
154 haveError = FALSE;
155 }
156
157 VOID FinishTextScreen(IN BOOLEAN WaitAlways)
158 {
159 if (haveError || WaitAlways) {
160 SwitchToText(FALSE);
161 PauseForKey();
162 }
163
164 // reset error flag
165 haveError = FALSE;
166 }
167
168 VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title)
169 {
170 EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 };
171
172 if (!AllowGraphicsMode)
173 UseGraphicsMode = FALSE;
174
175 if (UseGraphicsMode) {
176 SwitchToGraphics();
177 BltClearScreen(FALSE);
178 } else {
179 egClearScreen(&DarkBackgroundPixel);
180 } // if/else
181
182 // show the header
183 DrawScreenHeader(Title);
184
185 if (!UseGraphicsMode)
186 SwitchToText(TRUE);
187
188 // reset error flag
189 haveError = FALSE;
190 }
191
192 VOID FinishExternalScreen(VOID)
193 {
194 // make sure we clean up later
195 GraphicsScreenDirty = TRUE;
196
197 if (haveError) {
198 SwitchToText(FALSE);
199 PauseForKey();
200 }
201
202 // reset error flag
203 haveError = FALSE;
204 }
205
206 VOID TerminateScreen(VOID)
207 {
208 // clear text screen
209 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
210 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
211
212 // enable cursor
213 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
214 }
215
216 static VOID DrawScreenHeader(IN CHAR16 *Title)
217 {
218 UINTN y;
219
220 // clear to black background
221 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
222 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
223
224 // paint header background
225 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER);
226 for (y = 0; y < 3; y++) {
227 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y);
228 Print(BlankLine);
229 }
230
231 // print header text
232 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1);
233 Print(L"rEFInd - %s", Title);
234
235 // reposition cursor
236 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
237 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4);
238 }
239
240 //
241 // Keyboard input
242 //
243
244 static BOOLEAN ReadAllKeyStrokes(VOID)
245 {
246 BOOLEAN GotKeyStrokes;
247 EFI_STATUS Status;
248 EFI_INPUT_KEY key;
249
250 GotKeyStrokes = FALSE;
251 for (;;) {
252 Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
253 if (Status == EFI_SUCCESS) {
254 GotKeyStrokes = TRUE;
255 continue;
256 }
257 break;
258 }
259 return GotKeyStrokes;
260 }
261
262 VOID PauseForKey(VOID)
263 {
264 UINTN index;
265
266 Print(L"\n* Hit any key to continue *");
267
268 if (ReadAllKeyStrokes()) { // remove buffered key strokes
269 refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay
270 ReadAllKeyStrokes(); // empty the buffer again
271 }
272
273 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
274 ReadAllKeyStrokes(); // empty the buffer to protect the menu
275
276 Print(L"\n");
277 }
278
279 #if REFIT_DEBUG > 0
280 VOID DebugPause(VOID)
281 {
282 // show console and wait for key
283 SwitchToText(FALSE);
284 PauseForKey();
285
286 // reset error flag
287 haveError = FALSE;
288 }
289 #endif
290
291 VOID EndlessIdleLoop(VOID)
292 {
293 UINTN index;
294
295 for (;;) {
296 ReadAllKeyStrokes();
297 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
298 }
299 }
300
301 //
302 // Error handling
303 //
304
305 BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where)
306 {
307 CHAR16 ErrorName[64];
308
309 if (!EFI_ERROR(Status))
310 return FALSE;
311
312 StatusToString(ErrorName, Status);
313 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
314 Print(L"Fatal Error: %s %s\n", ErrorName, where);
315 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
316 haveError = TRUE;
317
318 //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
319
320 return TRUE;
321 }
322
323 BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where)
324 {
325 CHAR16 ErrorName[64];
326
327 if (!EFI_ERROR(Status))
328 return FALSE;
329
330 StatusToString(ErrorName, Status);
331 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
332 Print(L"Error: %s %s\n", ErrorName, where);
333 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
334 haveError = TRUE;
335
336 return TRUE;
337 }
338
339 //
340 // Graphics functions
341 //
342
343 VOID SwitchToGraphicsAndClear(VOID)
344 {
345 SwitchToGraphics();
346 if (GraphicsScreenDirty)
347 BltClearScreen(TRUE);
348 }
349
350 VOID BltClearScreen(IN BOOLEAN ShowBanner)
351 {
352 static EG_IMAGE *Banner = NULL;
353
354 if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) {
355 // load banner on first call
356 if (Banner == NULL) {
357 if (GlobalConfig.BannerFileName == NULL)
358 Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE);
359 else
360 Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE);
361 if (Banner != NULL)
362 MenuBackgroundPixel = Banner->PixelData[0];
363 }
364
365 // clear and draw banner
366 egClearScreen(&MenuBackgroundPixel);
367 if (Banner != NULL)
368 BltImage(Banner, (UGAWidth - Banner->Width) >> 1,
369 ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height);
370
371 } else {
372 // clear to standard background color
373 egClearScreen(&StdBackgroundPixel);
374 }
375
376 GraphicsScreenDirty = FALSE;
377 }
378
379 VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos)
380 {
381 egDrawImage(Image, XPos, YPos);
382 GraphicsScreenDirty = TRUE;
383 }
384
385 VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel)
386 {
387 EG_IMAGE *CompImage;
388
389 // compose on background
390 CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel);
391 egComposeImage(CompImage, Image, 0, 0);
392
393 // blit to screen and clean up
394 egDrawImage(CompImage, XPos, YPos);
395 egFreeImage(CompImage);
396 GraphicsScreenDirty = TRUE;
397 }
398
399 // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
400 // {
401 // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
402 // EG_IMAGE *CompImage;
403 //
404 // // initialize buffer with base image
405 // CompImage = egCopyImage(BaseImage);
406 // TotalWidth = BaseImage->Width;
407 // TotalHeight = BaseImage->Height;
408 //
409 // // place the top image
410 // CompWidth = TopImage->Width;
411 // if (CompWidth > TotalWidth)
412 // CompWidth = TotalWidth;
413 // OffsetX = (TotalWidth - CompWidth) >> 1;
414 // CompHeight = TopImage->Height;
415 // if (CompHeight > TotalHeight)
416 // CompHeight = TotalHeight;
417 // OffsetY = (TotalHeight - CompHeight) >> 1;
418 // egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
419 //
420 // // blit to screen and clean up
421 // egDrawImage(CompImage, XPos, YPos);
422 // egFreeImage(CompImage);
423 // GraphicsScreenDirty = TRUE;
424 // }
425
426 VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos)
427 {
428 UINTN TotalWidth, TotalHeight, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0;
429 EG_IMAGE *CompImage = NULL;
430
431 // initialize buffer with base image
432 if (BaseImage != NULL) {
433 CompImage = egCopyImage(BaseImage);
434 TotalWidth = BaseImage->Width;
435 TotalHeight = BaseImage->Height;
436 }
437
438 // place the top image
439 if ((TopImage != NULL) && (CompImage != NULL)) {
440 CompWidth = TopImage->Width;
441 if (CompWidth > TotalWidth)
442 CompWidth = TotalWidth;
443 OffsetX = (TotalWidth - CompWidth) >> 1;
444 CompHeight = TopImage->Height;
445 if (CompHeight > TotalHeight)
446 CompHeight = TotalHeight;
447 OffsetY = (TotalHeight - CompHeight) >> 1;
448 egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
449 }
450
451 // place the badge image
452 if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) {
453 OffsetX += CompWidth - 8 - BadgeImage->Width;
454 OffsetY += CompHeight - 8 - BadgeImage->Height;
455 egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY);
456 }
457
458 // blit to screen and clean up
459 egDrawImage(CompImage, XPos, YPos);
460 egFreeImage(CompImage);
461 GraphicsScreenDirty = TRUE;
462 }