]> code.delx.au - refind/blob - refind/screen.c
Various changes, esp. to "disabled", "hideui", & "showtools"
[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 "refit_call_wrapper.h"
41
42 #include "egemb_refind_banner.h"
43
44 // Console defines and variables
45
46 UINTN ConWidth;
47 UINTN ConHeight;
48 CHAR16 *BlankLine;
49
50 static VOID SwitchToText(IN BOOLEAN CursorEnabled);
51 static VOID SwitchToGraphics(VOID);
52 static VOID DrawScreenHeader(IN CHAR16 *Title);
53
54 // UGA defines and variables
55
56 UINTN UGAWidth;
57 UINTN UGAHeight;
58 BOOLEAN AllowGraphicsMode;
59
60 EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
61 EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 };
62
63 static BOOLEAN GraphicsScreenDirty;
64
65 // general defines and variables
66
67 static BOOLEAN haveError = FALSE;
68
69 //
70 // Screen initialization and switching
71 //
72
73 VOID InitScreen(VOID)
74 {
75 UINTN i;
76
77 // initialize libeg
78 egInitScreen();
79
80 if (egHasGraphicsMode()) {
81 egGetScreenSize(&UGAWidth, &UGAHeight);
82 AllowGraphicsMode = TRUE;
83 } else {
84 AllowGraphicsMode = FALSE;
85 egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode
86 }
87 GraphicsScreenDirty = TRUE;
88
89 // disable cursor
90 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
91
92 // get size of text console
93 if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) {
94 // use default values on error
95 ConWidth = 80;
96 ConHeight = 25;
97 }
98
99 // make a buffer for a whole text line
100 BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16));
101 for (i = 0; i < ConWidth; i++)
102 BlankLine[i] = ' ';
103 BlankLine[i] = 0;
104
105 // show the banner (even when in graphics mode)
106 DrawScreenHeader(L"Initializing...");
107 }
108
109 VOID SetupScreen(VOID)
110 {
111 if (GlobalConfig.TextOnly) {
112 // switch to text mode if requested
113 AllowGraphicsMode = FALSE;
114 SwitchToText(FALSE);
115
116 } else if (AllowGraphicsMode) {
117 // clear screen and show banner
118 // (now we know we'll stay in graphics mode)
119 SwitchToGraphics();
120 BltClearScreen(TRUE);
121 }
122 }
123
124 static VOID SwitchToText(IN BOOLEAN CursorEnabled)
125 {
126 egSetGraphicsModeEnabled(FALSE);
127 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled);
128 }
129
130 static VOID SwitchToGraphics(VOID)
131 {
132 if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) {
133 egSetGraphicsModeEnabled(TRUE);
134 GraphicsScreenDirty = TRUE;
135 }
136 }
137
138 //
139 // Screen control for running tools
140 //
141
142 VOID BeginTextScreen(IN CHAR16 *Title)
143 {
144 DrawScreenHeader(Title);
145 SwitchToText(FALSE);
146
147 // reset error flag
148 haveError = FALSE;
149 }
150
151 VOID FinishTextScreen(IN BOOLEAN WaitAlways)
152 {
153 if (haveError || WaitAlways) {
154 SwitchToText(FALSE);
155 PauseForKey();
156 }
157
158 // reset error flag
159 haveError = FALSE;
160 }
161
162 VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title)
163 {
164 if (!AllowGraphicsMode)
165 UseGraphicsMode = FALSE;
166
167 if (UseGraphicsMode) {
168 SwitchToGraphics();
169 BltClearScreen(FALSE);
170 }
171
172 // show the header
173 DrawScreenHeader(Title);
174
175 if (!UseGraphicsMode)
176 SwitchToText(TRUE);
177
178 // reset error flag
179 haveError = FALSE;
180 }
181
182 VOID FinishExternalScreen(VOID)
183 {
184 // make sure we clean up later
185 GraphicsScreenDirty = TRUE;
186
187 if (haveError) {
188 SwitchToText(FALSE);
189 PauseForKey();
190 }
191
192 // reset error flag
193 haveError = FALSE;
194 }
195
196 VOID TerminateScreen(VOID)
197 {
198 // clear text screen
199 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
200 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
201
202 // enable cursor
203 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
204 }
205
206 static VOID DrawScreenHeader(IN CHAR16 *Title)
207 {
208 UINTN y;
209
210 // clear to black background
211 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
212 refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut);
213
214 // paint header background
215 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER);
216 for (y = 0; y < 3; y++) {
217 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y);
218 Print(BlankLine);
219 }
220
221 // print header text
222 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1);
223 Print(L"rEFInd - %s", Title);
224
225 // reposition cursor
226 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
227 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4);
228 }
229
230 //
231 // Keyboard input
232 //
233
234 static BOOLEAN ReadAllKeyStrokes(VOID)
235 {
236 BOOLEAN GotKeyStrokes;
237 EFI_STATUS Status;
238 EFI_INPUT_KEY key;
239
240 GotKeyStrokes = FALSE;
241 for (;;) {
242 Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
243 if (Status == EFI_SUCCESS) {
244 GotKeyStrokes = TRUE;
245 continue;
246 }
247 break;
248 }
249 return GotKeyStrokes;
250 }
251
252 VOID PauseForKey(VOID)
253 {
254 UINTN index;
255
256 Print(L"\n* Hit any key to continue *");
257
258 if (ReadAllKeyStrokes()) { // remove buffered key strokes
259 refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay
260 ReadAllKeyStrokes(); // empty the buffer again
261 }
262
263 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
264 ReadAllKeyStrokes(); // empty the buffer to protect the menu
265
266 Print(L"\n");
267 }
268
269 #if REFIT_DEBUG > 0
270 VOID DebugPause(VOID)
271 {
272 // show console and wait for key
273 SwitchToText(FALSE);
274 PauseForKey();
275
276 // reset error flag
277 haveError = FALSE;
278 }
279 #endif
280
281 VOID EndlessIdleLoop(VOID)
282 {
283 UINTN index;
284
285 for (;;) {
286 ReadAllKeyStrokes();
287 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
288 }
289 }
290
291 //
292 // Error handling
293 //
294
295 BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where)
296 {
297 CHAR16 ErrorName[64];
298
299 if (!EFI_ERROR(Status))
300 return FALSE;
301
302 StatusToString(ErrorName, Status);
303 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
304 Print(L"Fatal Error: %s %s\n", ErrorName, where);
305 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
306 haveError = TRUE;
307
308 //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
309
310 return TRUE;
311 }
312
313 BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where)
314 {
315 CHAR16 ErrorName[64];
316
317 if (!EFI_ERROR(Status))
318 return FALSE;
319
320 StatusToString(ErrorName, Status);
321 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
322 Print(L"Error: %s %s\n", ErrorName, where);
323 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
324 haveError = TRUE;
325
326 return TRUE;
327 }
328
329 //
330 // Graphics functions
331 //
332
333 VOID SwitchToGraphicsAndClear(VOID)
334 {
335 SwitchToGraphics();
336 if (GraphicsScreenDirty)
337 BltClearScreen(TRUE);
338 }
339
340 VOID BltClearScreen(IN BOOLEAN ShowBanner)
341 {
342 static EG_IMAGE *Banner = NULL;
343
344 if (ShowBanner && !(GlobalConfig.DisableFlags & DISABLE_FLAG_BANNER)) {
345 // load banner on first call
346 if (Banner == NULL) {
347 if (GlobalConfig.BannerFileName == NULL)
348 Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE);
349 else
350 Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE);
351 if (Banner != NULL)
352 MenuBackgroundPixel = Banner->PixelData[0];
353 }
354
355 // clear and draw banner
356 egClearScreen(&MenuBackgroundPixel);
357 if (Banner != NULL)
358 BltImage(Banner, (UGAWidth - Banner->Width) >> 1,
359 ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height);
360
361 } else {
362 // clear to standard background color
363 egClearScreen(&StdBackgroundPixel);
364 }
365
366 GraphicsScreenDirty = FALSE;
367 }
368
369 VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos)
370 {
371 egDrawImage(Image, XPos, YPos);
372 GraphicsScreenDirty = TRUE;
373 }
374
375 VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel)
376 {
377 EG_IMAGE *CompImage;
378
379 // compose on background
380 CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel);
381 egComposeImage(CompImage, Image, 0, 0);
382
383 // blit to screen and clean up
384 egDrawImage(CompImage, XPos, YPos);
385 egFreeImage(CompImage);
386 GraphicsScreenDirty = TRUE;
387 }
388
389 // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
390 // {
391 // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
392 // EG_IMAGE *CompImage;
393 //
394 // // initialize buffer with base image
395 // CompImage = egCopyImage(BaseImage);
396 // TotalWidth = BaseImage->Width;
397 // TotalHeight = BaseImage->Height;
398 //
399 // // place the top image
400 // CompWidth = TopImage->Width;
401 // if (CompWidth > TotalWidth)
402 // CompWidth = TotalWidth;
403 // OffsetX = (TotalWidth - CompWidth) >> 1;
404 // CompHeight = TopImage->Height;
405 // if (CompHeight > TotalHeight)
406 // CompHeight = TotalHeight;
407 // OffsetY = (TotalHeight - CompHeight) >> 1;
408 // egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
409 //
410 // // blit to screen and clean up
411 // egDrawImage(CompImage, XPos, YPos);
412 // egFreeImage(CompImage);
413 // GraphicsScreenDirty = TRUE;
414 // }
415
416 VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos)
417 {
418 UINTN TotalWidth, TotalHeight, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0;
419 EG_IMAGE *CompImage = NULL;
420
421 // initialize buffer with base image
422 if (BaseImage != NULL) {
423 CompImage = egCopyImage(BaseImage);
424 TotalWidth = BaseImage->Width;
425 TotalHeight = BaseImage->Height;
426 }
427
428 // place the top image
429 if ((TopImage != NULL) && (CompImage != NULL)) {
430 CompWidth = TopImage->Width;
431 if (CompWidth > TotalWidth)
432 CompWidth = TotalWidth;
433 OffsetX = (TotalWidth - CompWidth) >> 1;
434 CompHeight = TopImage->Height;
435 if (CompHeight > TotalHeight)
436 CompHeight = TotalHeight;
437 OffsetY = (TotalHeight - CompHeight) >> 1;
438 egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
439 }
440
441 // place the badge image
442 if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) {
443 OffsetX += CompWidth - 8 - BadgeImage->Width;
444 OffsetY += CompHeight - 8 - BadgeImage->Height;
445 egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY);
446 }
447
448 // blit to screen and clean up
449 egDrawImage(CompImage, XPos, YPos);
450 egFreeImage(CompImage);
451 GraphicsScreenDirty = TRUE;
452 }