]> code.delx.au - refind/blob - refind/screen.c
Version 0.3.0 (beta) release. Adds "resolution" option to refind.conf.
[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 if (!AllowGraphicsMode)
171 UseGraphicsMode = FALSE;
172
173 if (UseGraphicsMode) {
174 SwitchToGraphics();
175 BltClearScreen(FALSE);
176 }
177
178 // show the header
179 DrawScreenHeader(Title);
180
181 if (!UseGraphicsMode)
182 SwitchToText(TRUE);
183
184 // reset error flag
185 haveError = FALSE;
186 }
187
188 VOID FinishExternalScreen(VOID)
189 {
190 // make sure we clean up later
191 GraphicsScreenDirty = TRUE;
192
193 if (haveError) {
194 SwitchToText(FALSE);
195 PauseForKey();
196 }
197
198 // reset error flag
199 haveError = FALSE;
200 }
201
202 VOID TerminateScreen(VOID)
203 {
204 // clear text screen
205 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
206 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
207
208 // enable cursor
209 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
210 }
211
212 static VOID DrawScreenHeader(IN CHAR16 *Title)
213 {
214 UINTN y;
215
216 // clear to black background
217 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
218 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
219
220 // paint header background
221 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER);
222 for (y = 0; y < 3; y++) {
223 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y);
224 Print(BlankLine);
225 }
226
227 // print header text
228 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1);
229 Print(L"rEFInd - %s", Title);
230
231 // reposition cursor
232 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
233 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4);
234 }
235
236 //
237 // Keyboard input
238 //
239
240 static BOOLEAN ReadAllKeyStrokes(VOID)
241 {
242 BOOLEAN GotKeyStrokes;
243 EFI_STATUS Status;
244 EFI_INPUT_KEY key;
245
246 GotKeyStrokes = FALSE;
247 for (;;) {
248 Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
249 if (Status == EFI_SUCCESS) {
250 GotKeyStrokes = TRUE;
251 continue;
252 }
253 break;
254 }
255 return GotKeyStrokes;
256 }
257
258 VOID PauseForKey(VOID)
259 {
260 UINTN index;
261
262 Print(L"\n* Hit any key to continue *");
263
264 if (ReadAllKeyStrokes()) { // remove buffered key strokes
265 refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay
266 ReadAllKeyStrokes(); // empty the buffer again
267 }
268
269 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
270 ReadAllKeyStrokes(); // empty the buffer to protect the menu
271
272 Print(L"\n");
273 }
274
275 #if REFIT_DEBUG > 0
276 VOID DebugPause(VOID)
277 {
278 // show console and wait for key
279 SwitchToText(FALSE);
280 PauseForKey();
281
282 // reset error flag
283 haveError = FALSE;
284 }
285 #endif
286
287 VOID EndlessIdleLoop(VOID)
288 {
289 UINTN index;
290
291 for (;;) {
292 ReadAllKeyStrokes();
293 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
294 }
295 }
296
297 //
298 // Error handling
299 //
300
301 BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where)
302 {
303 CHAR16 ErrorName[64];
304
305 if (!EFI_ERROR(Status))
306 return FALSE;
307
308 StatusToString(ErrorName, Status);
309 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
310 Print(L"Fatal Error: %s %s\n", ErrorName, where);
311 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
312 haveError = TRUE;
313
314 //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
315
316 return TRUE;
317 }
318
319 BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where)
320 {
321 CHAR16 ErrorName[64];
322
323 if (!EFI_ERROR(Status))
324 return FALSE;
325
326 StatusToString(ErrorName, Status);
327 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
328 Print(L"Error: %s %s\n", ErrorName, where);
329 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
330 haveError = TRUE;
331
332 return TRUE;
333 }
334
335 //
336 // Graphics functions
337 //
338
339 VOID SwitchToGraphicsAndClear(VOID)
340 {
341 SwitchToGraphics();
342 if (GraphicsScreenDirty)
343 BltClearScreen(TRUE);
344 }
345
346 VOID BltClearScreen(IN BOOLEAN ShowBanner)
347 {
348 static EG_IMAGE *Banner = NULL;
349
350 if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) {
351 // load banner on first call
352 if (Banner == NULL) {
353 if (GlobalConfig.BannerFileName == NULL)
354 Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE);
355 else
356 Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE);
357 if (Banner != NULL)
358 MenuBackgroundPixel = Banner->PixelData[0];
359 }
360
361 // clear and draw banner
362 egClearScreen(&MenuBackgroundPixel);
363 if (Banner != NULL)
364 BltImage(Banner, (UGAWidth - Banner->Width) >> 1,
365 ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height);
366
367 } else {
368 // clear to standard background color
369 egClearScreen(&StdBackgroundPixel);
370 }
371
372 GraphicsScreenDirty = FALSE;
373 }
374
375 VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos)
376 {
377 egDrawImage(Image, XPos, YPos);
378 GraphicsScreenDirty = TRUE;
379 }
380
381 VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel)
382 {
383 EG_IMAGE *CompImage;
384
385 // compose on background
386 CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel);
387 egComposeImage(CompImage, Image, 0, 0);
388
389 // blit to screen and clean up
390 egDrawImage(CompImage, XPos, YPos);
391 egFreeImage(CompImage);
392 GraphicsScreenDirty = TRUE;
393 }
394
395 // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
396 // {
397 // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
398 // EG_IMAGE *CompImage;
399 //
400 // // initialize buffer with base image
401 // CompImage = egCopyImage(BaseImage);
402 // TotalWidth = BaseImage->Width;
403 // TotalHeight = BaseImage->Height;
404 //
405 // // place the top image
406 // CompWidth = TopImage->Width;
407 // if (CompWidth > TotalWidth)
408 // CompWidth = TotalWidth;
409 // OffsetX = (TotalWidth - CompWidth) >> 1;
410 // CompHeight = TopImage->Height;
411 // if (CompHeight > TotalHeight)
412 // CompHeight = TotalHeight;
413 // OffsetY = (TotalHeight - CompHeight) >> 1;
414 // egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
415 //
416 // // blit to screen and clean up
417 // egDrawImage(CompImage, XPos, YPos);
418 // egFreeImage(CompImage);
419 // GraphicsScreenDirty = TRUE;
420 // }
421
422 VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos)
423 {
424 UINTN TotalWidth, TotalHeight, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0;
425 EG_IMAGE *CompImage = NULL;
426
427 // initialize buffer with base image
428 if (BaseImage != NULL) {
429 CompImage = egCopyImage(BaseImage);
430 TotalWidth = BaseImage->Width;
431 TotalHeight = BaseImage->Height;
432 }
433
434 // place the top image
435 if ((TopImage != NULL) && (CompImage != NULL)) {
436 CompWidth = TopImage->Width;
437 if (CompWidth > TotalWidth)
438 CompWidth = TotalWidth;
439 OffsetX = (TotalWidth - CompWidth) >> 1;
440 CompHeight = TopImage->Height;
441 if (CompHeight > TotalHeight)
442 CompHeight = TotalHeight;
443 OffsetY = (TotalHeight - CompHeight) >> 1;
444 egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
445 }
446
447 // place the badge image
448 if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) {
449 OffsetX += CompWidth - 8 - BadgeImage->Width;
450 OffsetY += CompHeight - 8 - BadgeImage->Height;
451 egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY);
452 }
453
454 // blit to screen and clean up
455 egDrawImage(CompImage, XPos, YPos);
456 egFreeImage(CompImage);
457 GraphicsScreenDirty = TRUE;
458 }