Chameleon

Chameleon Svn Source Tree

Root/branches/slice/i386/boot2/graphics.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29#include "boot.h"
30#include "graphics.h"
31#include "vbe.h"
32#include "appleClut8.h"
33#include "bootstruct.h"
34#include "IOHibernatePrivate.h"
35
36/*
37 * for spinning disk
38 */
39static int currentIndicator = 0;
40
41int previewTotalSectors = 0;
42int previewLoadedSectors = 0;
43uint8_t *previewSaveunder = 0;
44
45#define VIDEO(x) (bootArgs->Video.v_ ## x)
46
47#define MIN(x, y) ((x) < (y) ? (x) : (y))
48
49#ifndef OPTION_ROM
50#endif
51
52//==========================================================================
53// getVESAModeWithProperties
54//
55// Return the VESA mode that matches the properties specified.
56// If a mode is not found, then return the "best" available mode.
57
58unsigned short
59getVESAModeWithProperties( unsigned short width,
60 unsigned short height,
61 unsigned char bitsPerPixel,
62 unsigned short attributesSet,
63 unsigned short attributesClear,
64 VBEModeInfoBlock * outModeInfo,
65 unsigned short * vesaVersion )
66{
67 VBEInfoBlock vbeInfo;
68 unsigned short * modePtr;
69 VBEModeInfoBlock modeInfo;
70 unsigned char modeBitsPerPixel;
71 unsigned short matchedMode = modeEndOfList;
72 int err;
73
74 // Clear output mode info.
75
76 bzero( outModeInfo, sizeof(*outModeInfo) );
77
78 // Get VBE controller info containing the list of supported modes.
79
80 bzero( &vbeInfo, sizeof(vbeInfo) );
81 strcpy( (char*)&vbeInfo, "VBE2" );
82 err = getVBEInfo( &vbeInfo );
83 if ( err != errSuccess )
84 {
85 return modeEndOfList;
86 }
87
88 // Report the VESA major/minor version number.
89
90 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
91
92 // Loop through the mode list, and find the matching mode.
93
94 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
95 *modePtr != modeEndOfList; modePtr++ )
96 {
97 // Get mode information.
98
99 bzero( &modeInfo, sizeof(modeInfo) );
100 err = getVBEModeInfo( *modePtr, &modeInfo );
101 if ( err != errSuccess )
102 {
103 continue;
104 }
105
106#if DEBUG
107 verbose("Mode %x: %dx%dx%d mm:%d attr:%x\n",
108 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
109 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
110 modeInfo.ModeAttributes);
111#endif
112
113 // Filter out unwanted modes based on mode attributes.
114
115 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
116|| ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
117 {
118 continue;
119 }
120
121 // Pixel depth in bits.
122
123 modeBitsPerPixel = modeInfo.BitsPerPixel;
124
125 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
126 {
127 // Text mode, 16 colors.
128 }
129 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
130 {
131 // Packed pixel, 256 colors.
132 }
133 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
134 && ( modeInfo.MemoryModel == 6 )
135 && ( modeInfo.RedMaskSize == 5 )
136 && ( modeInfo.GreenMaskSize == 5 )
137 && ( modeInfo.BlueMaskSize == 5 ) )
138 {
139 // Direct color, 16 bpp (1:5:5:5).
140 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
141 }
142 else if ( ( modeBitsPerPixel == 32 )
143 && ( modeInfo.MemoryModel == 6 )
144 && ( modeInfo.RedMaskSize == 8 )
145 && ( modeInfo.GreenMaskSize == 8 )
146 && ( modeInfo.BlueMaskSize == 8 ) )
147 {
148 // Direct color, 32 bpp (8:8:8:8).
149 }
150 else
151 {
152 continue; // Not a supported mode.
153 }
154
155 // Modes larger than the specified dimensions are skipped.
156
157 if ( ( modeInfo.XResolution > width ) ||
158( modeInfo.YResolution > height ) )
159 {
160 continue;
161 }
162
163 // Perfect match, we're done looking.
164
165 if ( ( modeInfo.XResolution == width ) &&
166( modeInfo.YResolution == height ) &&
167( modeBitsPerPixel == bitsPerPixel ) )
168 {
169 matchedMode = *modePtr;
170 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
171 break;
172 }
173
174 // Save the next "best" mode in case a perfect match is not found.
175
176 if ( modeInfo.XResolution == outModeInfo->XResolution &&
177modeInfo.YResolution == outModeInfo->YResolution &&
178modeBitsPerPixel <= outModeInfo->BitsPerPixel )
179 {
180 continue; // Saved mode has more depth.
181 }
182 if ( modeInfo.XResolution < outModeInfo->XResolution ||
183modeInfo.YResolution < outModeInfo->YResolution ||
184modeBitsPerPixel < outModeInfo->BitsPerPixel )
185 {
186 continue; // Saved mode has more resolution.
187 }
188
189 matchedMode = *modePtr;
190 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
191 }
192
193 return matchedMode;
194}
195
196//==========================================================================
197// setupPalette
198
199static void setupPalette( VBEPalette * p, const unsigned char * g )
200{
201 int i;
202 unsigned char * source = (unsigned char *) g;
203
204 for (i = 0; i < 256; i++)
205 {
206 (*p)[i] = 0;
207 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
208 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
209 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
210 }
211}
212
213//==========================================================================
214// Simple decompressor for boot images encoded in RLE format.
215
216char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
217{
218 char *out, *cp;
219
220 struct RLEBlock {
221 unsigned char count;
222 unsigned char value;
223 } * bp = (struct RLEBlock *) rleData;
224
225 out = cp = malloc( outBytes );
226 if ( out == NULL ) return NULL;
227
228 while ( rleBlocks-- )
229 {
230 memset( cp, bp->value, bp->count );
231 cp += bp->count;
232 bp++;
233 }
234
235 return out;
236}
237
238//==========================================================================
239// setVESAGraphicsMode
240
241int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short refreshRate )
242{
243 VBEModeInfoBlock minfo;
244 unsigned short mode;
245 unsigned short vesaVersion;
246 int err = errFuncNotSupported;
247
248 do {
249 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
250 maColorModeBit |
251 maModeIsSupportedBit |
252 maGraphicsModeBit |
253 maLinearFrameBufferAvailBit,
254 0,
255 &minfo, &vesaVersion );
256 if ( mode == modeEndOfList )
257 {
258 break;
259 }
260
261//
262// FIXME : generateCRTCTiming() causes crash.
263//
264
265// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
266// (gBootMode & kBootModeSafe) == 0 )
267// {
268// VBECRTCInfoBlock timing;
269//
270// // Generate CRTC timing for given refresh rate.
271//
272// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
273// refreshRate, kCRTCParamRefreshRate,
274// &timing );
275//
276// // Find the actual pixel clock supported by the hardware.
277//
278// getVBEPixelClock( mode, &timing.PixelClock );
279//
280// // Re-compute CRTC timing based on actual pixel clock.
281//
282// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
283// timing.PixelClock, kCRTCParamPixelClock,
284// &timing );
285//
286// // Set the video mode and use specified CRTC timing.
287//
288// err = setVBEMode( mode | kLinearFrameBufferBit |
289// kCustomRefreshRateBit, &timing );
290// }
291// else
292// {
293// // Set the mode with default refresh rate.
294//
295// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
296// }
297
298 // Set the mode with default refresh rate.
299
300 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
301
302 if ( err != errSuccess )
303 {
304 break;
305 }
306
307 // Set 8-bit color palette.
308
309 if ( minfo.BitsPerPixel == 8 )
310 {
311 VBEPalette palette;
312 setupPalette( &palette, appleClut8 );
313 if ((err = setVBEPalette(palette)) != errSuccess)
314 {
315 break;
316 }
317 }
318
319 // Is this required for buggy Video BIOS implementations?
320 // On which adapter?
321
322 if ( minfo.BytesPerScanline == 0 )
323minfo.BytesPerScanline = ( minfo.XResolution *
324 minfo.BitsPerPixel ) >> 3;
325
326 // Update KernBootStruct using info provided by the selected
327 // VESA mode.
328
329 bootArgs->Video.v_display = GRAPHICS_MODE;
330//setVideoMode(GRAPHICS_MODE, 0);
331 bootArgs->Video.v_width = minfo.XResolution;
332 bootArgs->Video.v_height = minfo.YResolution;
333 bootArgs->Video.v_depth = minfo.BitsPerPixel;
334 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
335 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
336
337 }
338 while ( 0 );
339
340 return err;
341}
342
343
344#ifndef OPTION_ROM
345
346
347//==========================================================================
348// LookUpCLUTIndex
349
350unsigned long lookUpCLUTIndex( unsigned char index,
351 unsigned char depth )
352{
353 long result, red, green, blue;
354
355 red = appleClut8[index * 3 + 0];
356 green = appleClut8[index * 3 + 1];
357 blue = appleClut8[index * 3 + 2];
358
359 switch (depth) {
360 case 16 :
361 result = ((red & 0xF8) << 7) |
362((green & 0xF8) << 2) |
363((blue & 0xF8) >> 3);
364 result |= (result << 16);
365 break;
366
367 case 32 :
368 result = (red << 16) | (green << 8) | blue;
369 break;
370
371 default :
372 result = index | (index << 8);
373 result |= (result << 16);
374 break;
375 }
376
377 return result;
378}
379
380//==========================================================================
381// drawColorRectangle
382
383void * stosl(void * dst, long val, long len)
384{
385 asm volatile ( "rep; stosl"
386 : "=c" (len), "=D" (dst)
387 : "0" (len), "1" (dst), "a" (val)
388 : "memory" );
389
390 return dst;
391}
392
393void drawColorRectangle( unsigned short x,
394unsigned short y,
395unsigned short width,
396unsigned short height,
397unsigned char colorIndex )
398{
399 long pixelBytes;
400 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
401 char * vram;
402
403 pixelBytes = VIDEO(depth) / 8;
404 vram = (char *) VIDEO(baseAddr) +
405VIDEO(rowBytes) * y + pixelBytes * x;
406
407 width = MIN(width, VIDEO(width) - x);
408 height = MIN(height, VIDEO(height) - y);
409
410 while ( height-- )
411 {
412 int rem = ( pixelBytes * width ) % 4;
413 if ( rem ) bcopy( &color, vram, rem );
414 stosl( vram + rem, color, pixelBytes * width / 4 );
415 vram += VIDEO(rowBytes);
416 }
417}
418
419void
420loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
421{
422int x,y, off;
423int red=0x7f, green=0x7f, blue=0x7f;
424for (x=0;x<ow;x++)
425for (y=0;y<oh;y++)
426{
427off=(x*iw)/ow+((y*ih)/oh)*iw;
428switch (ip)
429{
430case 16:
431{
432uint16_t val;
433val=((uint16_t *)input)[off];
434red=(val>>7)&0xf8;
435green=(val>>2)&0xf8;
436blue=(val<<3)&0xf8;
437break;
438}
439case 32:
440{
441uint32_t val;
442val=((uint32_t *)input)[off];
443red=(val>>16)&0xff;
444green=(val>>8)&0xff;
445blue=(val)&0xff;
446break;
447}
448}
449char *ptr=(char *)output+x*(op/8)+y*or;
450switch (op)
451{
452case 16:
453*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
454((green & 0xF8) << 2) |
455((blue & 0xF8) >> 3);
456break;
457case 32 :
458*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
459break;
460}
461}
462}
463
464DECLARE_IOHIBERNATEPROGRESSALPHA
465
466void drawPreview(void *src, uint8_t * saveunder)
467{
468uint8_t * screen;
469uint32_t rowBytes, pixelShift;
470uint32_t x, y;
471int32_t blob;
472uint32_t alpha, in, color, result;
473uint8_t * out;
474void *uncomp;
475int origwidth, origheight, origbpx;
476uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
477
478if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
479{
480if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
481if (initGraphicsMode () != errSuccess)
482return;
483screen = (uint8_t *) VIDEO (baseAddr);
484rowBytes = VIDEO (rowBytes);
485loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
486}
487else
488{
489if (initGraphicsMode () != errSuccess)
490return;
491screen = (uint8_t *) VIDEO (baseAddr);
492rowBytes = VIDEO (rowBytes);
493// Set the screen to 75% grey.
494 drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
495}
496
497
498pixelShift = VIDEO (depth) >> 4;
499if (pixelShift < 1) return;
500
501screen += ((VIDEO (width)
502- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
503+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
504
505for (y = 0; y < kIOHibernateProgressHeight; y++)
506{
507out = screen + y * rowBytes;
508for (blob = 0; blob < kIOHibernateProgressCount; blob++)
509{
510color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
511for (x = 0; x < kIOHibernateProgressWidth; x++)
512{
513alpha = gIOHibernateProgressAlpha[y][x];
514result = color;
515if (alpha)
516{
517if (0xff != alpha)
518{
519if (1 == pixelShift)
520{
521in = *((uint16_t *)out) & 0x1f;// 16
522in = (in << 3) | (in >> 2);
523}
524else
525in = *((uint32_t *)out) & 0xff;// 32
526saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
527result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
528}
529if (1 == pixelShift)
530{
531result >>= 3;
532*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
533}
534else
535*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
536}
537out += (1 << pixelShift);
538}
539out += (kIOHibernateProgressSpacing << pixelShift);
540}
541}
542}
543
544void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
545{
546uint8_t * screen;
547uint32_t rowBytes, pixelShift;
548uint32_t x, y;
549int32_t blob, lastBlob;
550uint32_t alpha, in, color, result;
551uint8_t * out;
552uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
553
554pixelShift = VIDEO(depth) >> 4;
555if (pixelShift < 1) return;
556screen = (uint8_t *) VIDEO (baseAddr);
557rowBytes = VIDEO (rowBytes);
558
559screen += ((VIDEO (width)
560- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
561+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
562
563lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
564
565screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
566
567for (y = 0; y < kIOHibernateProgressHeight; y++)
568{
569out = screen + y * rowBytes;
570for (blob = firstBlob; blob <= lastBlob; blob++)
571{
572color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
573for (x = 0; x < kIOHibernateProgressWidth; x++)
574{
575alpha = gIOHibernateProgressAlpha[y][x];
576result = color;
577if (alpha)
578{
579if (0xff != alpha)
580{
581in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
582result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
583}
584if (1 == pixelShift)
585{
586result >>= 3;
587*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
588}
589else
590*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
591}
592out += (1 << pixelShift);
593}
594out += (kIOHibernateProgressSpacing << pixelShift);
595}
596}
597}
598#endif
599
600
601//==========================================================================
602// setVESATextMode
603
604static int
605setVESATextMode( unsigned short cols,
606unsigned short rows,
607unsigned char bitsPerPixel )
608{
609 VBEModeInfoBlock minfo;
610 unsigned short mode = modeEndOfList;
611
612 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
613 {
614 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
615 maColorModeBit |
616 maModeIsSupportedBit,
617 maGraphicsModeBit,
618 &minfo, NULL );
619 }
620
621 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
622 {
623 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
624 minfo.XResolution = 80;
625 minfo.YResolution = 25;
626 }
627
628 // Update KernBootStruct using info provided by the selected
629 // VESA mode.
630
631 bootArgs->Video.v_display = VGA_TEXT_MODE;
632 bootArgs->Video.v_baseAddr = 0xb8000;
633 bootArgs->Video.v_width = minfo.XResolution;
634 bootArgs->Video.v_height = minfo.YResolution;
635 bootArgs->Video.v_depth = 8;
636 bootArgs->Video.v_rowBytes = 0x8000;
637
638 return errSuccess; // always return success
639}
640
641//==========================================================================
642// getNumberArrayFromProperty
643
644int
645getNumberArrayFromProperty( const char * propKey,
646 unsigned long numbers[],
647 unsigned long maxArrayCount )
648{
649 char * propStr;
650 unsigned long count = 0;
651
652 propStr = newStringForKey( (char *) propKey , &bootInfo->bootConfig );
653 if ( propStr )
654 {
655 char * delimiter = propStr;
656 char * p = propStr;
657
658 while ( count < maxArrayCount && *p != '\0' )
659 {
660 unsigned long val = strtoul( p, &delimiter, 10 );
661 if ( p != delimiter )
662 {
663 numbers[count++] = val;
664 p = delimiter;
665 }
666 while ( ( *p != '\0' ) && !isdigit(*p) )
667 p++;
668 }
669
670 free( propStr );
671 }
672
673 return count;
674}
675
676int initGraphicsMode ()
677{
678unsigned long params[4];
679int count;
680
681params[3] = 0;
682count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
683
684// Try to find a resolution if "Graphics Mode" setting is not available.
685if ( count < 3 )
686{
687 // Use the default resolution if we don't have an initialized GUI.
688/* if (gui.screen.width == 0 || gui.screen.height == 0)
689 {
690 gui.screen.width = DEFAULT_SCREEN_WIDTH;
691 gui.screen.height = DEFAULT_SCREEN_HEIGHT;
692 }
693*/
694 params[0] = DEFAULT_SCREEN_WIDTH; //gui.screen.width;
695 params[1] = DEFAULT_SCREEN_HEIGHT; // gui.screen.height;
696params[2] = 32;
697}
698
699// Map from pixel format to bits per pixel.
700
701if ( params[2] == 256 ) params[2] = 8;
702if ( params[2] == 555 ) params[2] = 16;
703if ( params[2] == 888 ) params[2] = 32;
704
705return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
706}
707
708//==========================================================================
709// setVideoMode
710//
711// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
712
713void
714setVideoMode( int mode, int drawgraphics)
715{
716 unsigned long params[4];
717 int count;
718 int err = errSuccess;
719
720 if ( mode == GRAPHICS_MODE )
721 {
722 if ( (err=initGraphicsMode ()) == errSuccess ) {
723if (gVerboseMode) {
724// Tell the kernel to use text mode on a linear frame buffer display
725bootArgs->Video.v_display = FB_TEXT_MODE;
726//video_mode(2);
727} else {
728bootArgs->Video.v_display = GRAPHICS_MODE;
729//video_mode(1);
730}
731}
732else video_mode(1);
733 }
734
735 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
736 {
737 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
738 if ( count < 2 )
739 {
740 params[0] = 80; // Default text mode is 80x25.
741 params[1] = 25;
742 }
743
744setVESATextMode( params[0], params[1], 4 );
745 bootArgs->Video.v_display = VGA_TEXT_MODE;
746 }
747
748 currentIndicator = 0;
749}
750
751//==========================================================================
752// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
753
754inline int getVideoMode(void)
755{
756 return bootArgs->Video.v_display;
757}
758
759//==========================================================================
760// Display and clear the activity indicator.
761
762static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
763
764// To prevent a ridiculously fast-spinning indicator,
765// ensure a minimum of 1/9 sec between animation frames.
766#define MIN_TICKS 2
767
768void
769spinActivityIndicator(int sectors)
770{
771 static unsigned long lastTickTime = 0, currentTickTime;
772#ifndef OPTION_ROM
773if (previewTotalSectors && previewSaveunder)
774{
775int blob, lastBlob;
776
777lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
778previewLoadedSectors+=sectors;
779blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
780
781if (blob!=lastBlob)
782updateProgressBar (previewSaveunder, lastBlob, blob);
783return;
784}
785#endif
786currentTickTime = time18(); // late binding
787if (currentTickTime < lastTickTime + MIN_TICKS)
788{
789return;
790}
791else
792{
793lastTickTime = currentTickTime;
794}
795
796if (getVideoMode() == VGA_TEXT_MODE)
797{
798if (currentIndicator >= sizeof(indicator))
799{
800currentIndicator = 0;
801}
802putc(indicator[currentIndicator++]);
803putc('\b');
804}
805}
806
807void
808clearActivityIndicator( void )
809{
810 if ( getVideoMode() == VGA_TEXT_MODE )
811 {
812putc(' ');
813putc('\b');
814 }
815}
816
817

Archive Download this file

Revision: 693