1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "string-extra.h"
28 #include "rbunicode.h"
30 #include "powermgmt.h"
38 #include "statusbar.h"
40 #include "scrollbar.h"
41 #include "screen_access.h"
46 #ifdef HAVE_LCD_BITMAP
47 #include "peakmeter.h"
56 #if CONFIG_CODEC == SWCODEC
65 #include "root_menu.h"
68 #include "wps_internals.h"
69 #include "skin_engine.h"
70 #include "statusbar-skinned.h"
71 #include "skin_display.h"
73 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
);
75 /* update a skinned screen, update_type is WPS_REFRESH_* values.
76 * Usually it should only be WPS_REFRESH_NON_STATIC
77 * A full update will be done if required (state.do_full_update == true)
79 void skin_update(struct gui_wps
*gwps
, unsigned int update_type
)
81 /* This maybe shouldnt be here,
82 * This is also safe for skined screen which dont use the id3 */
83 struct mp3entry
*id3
= gwps
->state
->id3
;
84 bool cuesheet_update
= (id3
!= NULL
? cuesheet_subtrack_changed(id3
) : false);
85 gwps
->sync_data
->do_full_update
|= cuesheet_update
;
87 skin_render(gwps
, gwps
->sync_data
->do_full_update
?
88 SKIN_REFRESH_ALL
: update_type
);
91 #ifdef HAVE_LCD_BITMAP
93 void skin_statusbar_changed(struct gui_wps
*skin
)
97 struct wps_data
*data
= skin
->data
;
98 const struct screen
*display
= skin
->display
;
99 const int screen
= display
->screen_type
;
101 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, data
)->vp
;
102 viewport_set_defaults(vp
, screen
);
104 if (data
->wps_sb_tag
)
105 { /* fix up the default viewport */
106 if (data
->show_sb_on_wps
)
108 if (statusbar_position(screen
) != STATUSBAR_OFF
)
109 return; /* vp is fixed already */
111 vp
->y
= STATUSBAR_HEIGHT
;
112 vp
->height
= display
->lcdheight
- STATUSBAR_HEIGHT
;
116 if (statusbar_position(screen
) == STATUSBAR_OFF
)
117 return; /* vp is fixed already */
119 vp
->height
= display
->lcdheight
;
120 vp
->width
= display
->lcdwidth
;
125 void draw_progressbar(struct gui_wps
*gwps
, int line
, struct progressbar
*pb
)
127 struct screen
*display
= gwps
->display
;
128 struct viewport
*vp
= pb
->vp
;
129 struct wps_state
*state
= gwps
->state
;
130 struct mp3entry
*id3
= state
->id3
;
131 int y
= pb
->y
, height
= pb
->height
;
132 unsigned long length
, elapsed
;
135 height
= font_get(vp
->font
)->height
;
139 int line_height
= font_get(vp
->font
)->height
;
140 /* center the pb in the line, but only if the line is higher than the pb */
141 int center
= (line_height
-height
)/2;
142 /* if Y was not set calculate by font height,Y is -line_number-1 */
143 y
= line
*line_height
+ (0 > center
? 0 : center
);
146 if (pb
->type
== SKIN_TOKEN_VOLUMEBAR
)
148 int minvol
= sound_min(SOUND_VOLUME
);
149 int maxvol
= sound_max(SOUND_VOLUME
);
150 length
= maxvol
-minvol
;
151 elapsed
= global_settings
.volume
-minvol
;
153 else if (pb
->type
== SKIN_TOKEN_BATTERY_PERCENTBAR
)
156 elapsed
= battery_level();
159 else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
161 int min
= fm_region_data
[global_settings
.fm_region
].freq_min
;
162 elapsed
= radio_current_frequency() - min
;
163 length
= fm_region_data
[global_settings
.fm_region
].freq_max
- min
;
166 else if (id3
&& id3
->length
)
168 length
= id3
->length
;
169 elapsed
= id3
->elapsed
+ state
->ff_rewind_count
;
177 if (pb
->have_bitmap_pb
)
178 gui_bitmap_scrollbar_draw(display
, &pb
->bm
,
179 pb
->x
, y
, pb
->width
, pb
->bm
.height
,
180 length
, 0, elapsed
, HORIZONTAL
);
182 gui_scrollbar_draw(display
, pb
->x
, y
, pb
->width
, height
,
183 length
, 0, elapsed
, HORIZONTAL
);
185 if (pb
->type
== SKIN_TOKEN_PROGRESSBAR
)
187 if (id3
&& id3
->length
)
189 #ifdef AB_REPEAT_ENABLE
190 if (ab_repeat_mode_enabled())
191 ab_draw_markers(display
, id3
->length
,
192 pb
->x
, y
, pb
->width
, height
);
196 cue_draw_markers(display
, id3
->cuesheet
, id3
->length
,
197 pb
->x
, y
+1, pb
->width
, height
-2);
199 #if 0 /* disable for now CONFIG_TUNER */
200 else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
202 presets_draw_markers(display
, pb
->x
, y
, pb
->width
, height
);
208 void draw_playlist_viewer_list(struct gui_wps
*gwps
, struct playlistviewer
*viewer
)
210 struct wps_state
*state
= gwps
->state
;
211 int lines
= viewport_get_nb_lines(viewer
->vp
);
212 int line_height
= font_get(viewer
->vp
->font
)->height
;
217 struct wps_token
*token
;
218 int x
, length
, alignment
= SKIN_TOKEN_ALIGN_LEFT
;
220 struct mp3entry
*pid3
;
221 char buf
[MAX_PATH
*2], tempbuf
[MAX_PATH
];
222 const char *filename
;
224 if (current_screen() == GO_TO_FM
)
226 cur_pos
= radio_current_preset();
227 start_item
= cur_pos
+ viewer
->start_offset
;
228 max
= start_item
+radio_preset_count();
233 cur_pos
= playlist_get_display_index();
234 max
= playlist_amount()+1;
235 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
238 gwps
->display
->set_viewport(viewer
->vp
);
239 for(i
=start_item
; (i
-start_item
)<lines
&& i
<max
; i
++)
243 if (current_screen() == GO_TO_FM
)
246 line
= TRACK_HAS_INFO
;
252 filename
= playlist_peek(i
-cur_pos
);
257 else if (i
== cur_pos
+1)
261 #if CONFIG_CODEC == SWCODEC
264 #ifdef HAVE_TC_RAMCACHE
265 if (tagcache_fill_tags(&viewer
->tempid3
, filename
))
267 pid3
= &viewer
->tempid3
;
271 if (!audio_peek_track(&pid3
, i
-cur_pos
))
279 line
= pid3
? TRACK_HAS_INFO
: TRACK_HAS_NO_INFO
;
281 unsigned int line_len
= 0;
282 if (viewer
->lines
[line
]->children_count
== 0)
284 struct skin_element
*element
= viewer
->lines
[line
]->children
[0];
286 while (element
&& line_len
< sizeof(buf
))
288 const char *out
= NULL
;
289 if (element
->type
== TEXT
)
291 line_len
= strlcat(buf
, (char*)element
->data
, sizeof(buf
));
292 element
= element
->next
;
295 if (element
->type
!= TAG
)
297 element
= element
->next
;
300 if (element
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
302 token
= (struct wps_token
*)element
->data
;
303 out
= get_id3_token(token
, pid3
, tempbuf
, sizeof(tempbuf
), -1, NULL
);
306 out
= get_radio_token(token
, i
-cur_pos
,
307 tempbuf
, sizeof(tempbuf
), -1, NULL
);
311 line_len
= strlcat(buf
, out
, sizeof(buf
));
312 element
= element
->next
;
318 case SKIN_TOKEN_ALIGN_CENTER
:
319 case SKIN_TOKEN_ALIGN_LEFT
:
320 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
321 case SKIN_TOKEN_ALIGN_RIGHT
:
322 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
323 alignment
= token
->type
;
326 case SKIN_TOKEN_PLAYLIST_POSITION
:
327 snprintf(tempbuf
, sizeof(tempbuf
), "%d", i
);
329 case SKIN_TOKEN_FILE_NAME
:
330 get_dir(tempbuf
, sizeof(tempbuf
), filename
, 0);
332 case SKIN_TOKEN_FILE_PATH
:
333 snprintf(tempbuf
, sizeof(tempbuf
), "%s", filename
);
341 line_len
= strlcat(buf
, tempbuf
, sizeof(buf
));
343 element
= element
->next
;
346 int vpwidth
= viewer
->vp
->width
;
347 length
= gwps
->display
->getstringsize(buf
, NULL
, NULL
);
348 if (scroll
&& length
>= vpwidth
)
350 gwps
->display
->puts_scroll(0, (i
-start_item
), buf
);
354 if (length
>= vpwidth
)
360 case SKIN_TOKEN_ALIGN_CENTER
:
361 x
= (vpwidth
-length
)/2;
363 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
364 if (lang_is_rtl() && VP_IS_RTL(viewer
->vp
))
366 x
= vpwidth
- length
;
369 case SKIN_TOKEN_ALIGN_LEFT
:
372 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
373 if (lang_is_rtl() && VP_IS_RTL(viewer
->vp
))
378 case SKIN_TOKEN_ALIGN_RIGHT
:
379 x
= vpwidth
- length
;
386 gwps
->display
->putsxy(x
, (i
-start_item
)*line_height
, buf
);
392 /* clears the area where the image was shown */
393 void clear_image_pos(struct gui_wps
*gwps
, struct gui_img
*img
)
397 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
398 gwps
->display
->fillrect(img
->x
, img
->y
, img
->bm
.width
, img
->subimage_height
);
399 gwps
->display
->set_drawmode(DRMODE_SOLID
);
402 void wps_draw_image(struct gui_wps
*gwps
, struct gui_img
*img
, int subimage
)
404 struct screen
*display
= gwps
->display
;
405 if(img
->always_display
)
406 display
->set_drawmode(DRMODE_FG
);
408 display
->set_drawmode(DRMODE_SOLID
);
411 if(img
->bm
.format
== FORMAT_MONO
) {
413 display
->mono_bitmap_part(img
->bm
.data
,
414 0, img
->subimage_height
* subimage
,
415 img
->bm
.width
, img
->x
,
416 img
->y
, img
->bm
.width
,
417 img
->subimage_height
);
420 display
->transparent_bitmap_part((fb_data
*)img
->bm
.data
,
421 0, img
->subimage_height
* subimage
,
422 STRIDE(display
->screen_type
,
423 img
->bm
.width
, img
->bm
.height
),
424 img
->x
, img
->y
, img
->bm
.width
,
425 img
->subimage_height
);
431 void wps_display_images(struct gui_wps
*gwps
, struct viewport
* vp
)
433 if(!gwps
|| !gwps
->data
|| !gwps
->display
)
436 struct wps_data
*data
= gwps
->data
;
437 struct screen
*display
= gwps
->display
;
438 struct skin_token_list
*list
= data
->images
;
442 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
445 if (img
->display
>= 0)
447 wps_draw_image(gwps
, img
, img
->display
);
449 else if (img
->always_display
&& img
->vp
== vp
)
451 wps_draw_image(gwps
, img
, 0);
457 /* now draw the AA */
458 if (data
->albumart
&& data
->albumart
->vp
== vp
459 && data
->albumart
->draw_handle
>= 0)
461 draw_album_art(gwps
, data
->albumart
->draw_handle
, false);
462 data
->albumart
->draw_handle
= -1;
466 display
->set_drawmode(DRMODE_SOLID
);
469 #else /* HAVE_LCD_CHARCELL */
471 bool draw_player_progress(struct gui_wps
*gwps
)
473 struct wps_state
*state
= gwps
->state
;
474 struct screen
*display
= gwps
->display
;
475 unsigned char progress_pattern
[7];
480 if (LIKELY(state
->id3
))
482 elapsed
= state
->id3
->elapsed
;
483 length
= state
->id3
->length
;
492 pos
= 36 * (elapsed
+ state
->ff_rewind_count
) / length
;
494 for (i
= 0; i
< 7; i
++, pos
-= 5)
497 progress_pattern
[i
] = 0x1fu
;
499 progress_pattern
[i
] = 0x00u
;
501 progress_pattern
[i
] = 0x1fu
>> pos
;
504 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
508 void draw_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
510 static const unsigned char numbers
[10][4] = {
511 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
512 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
513 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
514 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
515 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
516 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
517 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
518 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
519 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
520 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
523 struct wps_state
*state
= gwps
->state
;
524 struct screen
*display
= gwps
->display
;
525 struct wps_data
*data
= gwps
->data
;
526 unsigned char progress_pattern
[7];
536 if (LIKELY(state
->id3
))
538 elapsed
= state
->id3
->elapsed
;
539 length
= state
->id3
->length
;
547 if (buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
550 time
= elapsed
+ state
->ff_rewind_count
;
552 pos
= 55 * time
/ length
;
554 memset(timestr
, 0, sizeof(timestr
));
555 format_time(timestr
, sizeof(timestr
)-2, time
);
556 timestr
[strlen(timestr
)] = ':'; /* always safe */
558 for (i
= 0; i
< 11; i
++, pos
-= 5)
561 memset(progress_pattern
, 0, sizeof(progress_pattern
));
563 if ((digit
= timestr
[time_idx
]))
568 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
570 memcpy(progress_pattern
, numbers
[digit
], 4);
573 else /* tens, shifted right */
575 for (j
= 0; j
< 4; j
++)
576 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
578 if (time_idx
> 0) /* not the first group, add colon in front */
580 progress_pattern
[1] |= 0x10u
;
581 progress_pattern
[3] |= 0x10u
;
587 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
590 if (pos
> 0 && pos
< 5)
593 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
596 if (softchar
&& pat_idx
< 8)
598 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
600 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
604 buf
= utf8encode(' ', buf
);
606 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
611 #endif /* HAVE_LCD_CHARCELL */
613 /* Evaluate the conditional that is at *token_index and return whether a skip
614 has ocurred. *token_index is updated with the new position.
616 int evaluate_conditional(struct gui_wps
*gwps
, struct conditional
*conditional
, int num_options
)
624 /* treat ?xx<true> constructs as if they had 2 options.
625 * (i.e ?xx<true|false>) */
629 int intval
= num_options
;
630 /* get_token_value needs to know the number of options in the enum */
631 value
= get_token_value(gwps
, conditional
->token
,
632 result
, sizeof(result
), &intval
);
634 /* intval is now the number of the enum option we want to read,
635 starting from 1. If intval is -1, we check if value is empty. */
637 intval
= (value
&& *value
) ? 1 : num_options
;
638 else if (intval
> num_options
|| intval
< 1)
639 intval
= num_options
;
641 conditional
->last_value
= intval
-1;
646 /* Display a line appropriately according to its alignment format.
647 format_align contains the text, separated between left, center and right.
648 line is the index of the line on the screen.
649 scroll indicates whether the line is a scrolling one or not.
651 void write_line(struct screen
*display
,
652 struct align_pos
*format_align
,
656 int left_width
= 0, left_xpos
;
657 int center_width
= 0, center_xpos
;
658 int right_width
= 0, right_xpos
;
664 /* calculate different string sizes and positions */
665 display
->getstringsize((unsigned char *)" ", &space_width
, &string_height
);
666 if (format_align
->left
!= 0) {
667 display
->getstringsize((unsigned char *)format_align
->left
,
668 &left_width
, &string_height
);
671 if (format_align
->right
!= 0) {
672 display
->getstringsize((unsigned char *)format_align
->right
,
673 &right_width
, &string_height
);
676 if (format_align
->center
!= 0) {
677 display
->getstringsize((unsigned char *)format_align
->center
,
678 ¢er_width
, &string_height
);
682 right_xpos
= (display
->getwidth() - right_width
);
683 center_xpos
= (display
->getwidth() + left_xpos
- center_width
) / 2;
685 scroll_width
= display
->getwidth() - left_xpos
;
687 /* Checks for overlapping strings.
688 If needed the overlapping strings will be merged, separated by a
691 /* CASE 1: left and centered string overlap */
692 /* there is a left string, need to merge left and center */
693 if ((left_width
!= 0 && center_width
!= 0) &&
694 (left_xpos
+ left_width
+ space_width
> center_xpos
)) {
695 /* replace the former separator '\0' of left and
696 center string with a space */
697 *(--format_align
->center
) = ' ';
698 /* calculate the new width and position of the merged string */
699 left_width
= left_width
+ space_width
+ center_width
;
700 /* there is no centered string anymore */
703 /* there is no left string, move center to left */
704 if ((left_width
== 0 && center_width
!= 0) &&
705 (left_xpos
+ left_width
> center_xpos
)) {
706 /* move the center string to the left string */
707 format_align
->left
= format_align
->center
;
708 /* calculate the new width and position of the string */
709 left_width
= center_width
;
710 /* there is no centered string anymore */
714 /* CASE 2: centered and right string overlap */
715 /* there is a right string, need to merge center and right */
716 if ((center_width
!= 0 && right_width
!= 0) &&
717 (center_xpos
+ center_width
+ space_width
> right_xpos
)) {
718 /* replace the former separator '\0' of center and
719 right string with a space */
720 *(--format_align
->right
) = ' ';
721 /* move the center string to the right after merge */
722 format_align
->right
= format_align
->center
;
723 /* calculate the new width and position of the merged string */
724 right_width
= center_width
+ space_width
+ right_width
;
725 right_xpos
= (display
->getwidth() - right_width
);
726 /* there is no centered string anymore */
729 /* there is no right string, move center to right */
730 if ((center_width
!= 0 && right_width
== 0) &&
731 (center_xpos
+ center_width
> right_xpos
)) {
732 /* move the center string to the right string */
733 format_align
->right
= format_align
->center
;
734 /* calculate the new width and position of the string */
735 right_width
= center_width
;
736 right_xpos
= (display
->getwidth() - right_width
);
737 /* there is no centered string anymore */
741 /* CASE 3: left and right overlap
742 There is no center string anymore, either there never
743 was one or it has been merged in case 1 or 2 */
744 /* there is a left string, need to merge left and right */
745 if ((left_width
!= 0 && center_width
== 0 && right_width
!= 0) &&
746 (left_xpos
+ left_width
+ space_width
> right_xpos
)) {
747 /* replace the former separator '\0' of left and
748 right string with a space */
749 *(--format_align
->right
) = ' ';
750 /* calculate the new width and position of the string */
751 left_width
= left_width
+ space_width
+ right_width
;
752 /* there is no right string anymore */
755 /* there is no left string, move right to left */
756 if ((left_width
== 0 && center_width
== 0 && right_width
!= 0) &&
757 (left_width
> right_xpos
)) {
758 /* move the right string to the left string */
759 format_align
->left
= format_align
->right
;
760 /* calculate the new width and position of the string */
761 left_width
= right_width
;
762 /* there is no right string anymore */
766 ypos
= (line
* string_height
);
769 if (scroll
&& ((left_width
> scroll_width
) ||
770 (center_width
> scroll_width
) ||
771 (right_width
> scroll_width
)))
773 display
->puts_scroll(0, line
,
774 (unsigned char *)format_align
->left
);
778 #ifdef HAVE_LCD_BITMAP
779 /* clear the line first */
780 display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
781 display
->fillrect(left_xpos
, ypos
, display
->getwidth(), string_height
);
782 display
->set_drawmode(DRMODE_SOLID
);
785 /* Nasty hack: we output an empty scrolling string,
786 which will reset the scroller for that line */
787 display
->puts_scroll(0, line
, (unsigned char *)"");
789 /* print aligned strings */
792 display
->putsxy(left_xpos
, ypos
,
793 (unsigned char *)format_align
->left
);
795 if (center_width
!= 0)
797 display
->putsxy(center_xpos
, ypos
,
798 (unsigned char *)format_align
->center
);
800 if (right_width
!= 0)
802 display
->putsxy(right_xpos
, ypos
,
803 (unsigned char *)format_align
->right
);
808 #ifdef HAVE_LCD_BITMAP
809 void draw_peakmeters(struct gui_wps
*gwps
, int line_number
,
810 struct viewport
*viewport
)
812 struct wps_data
*data
= gwps
->data
;
813 if (!data
->peak_meter_enabled
)
815 peak_meter_enable(false);
819 int h
= font_get(viewport
->font
)->height
;
820 int peak_meter_y
= line_number
* h
;
822 /* The user might decide to have the peak meter in the last
823 line so that it is only displayed if no status bar is
824 visible. If so we neither want do draw nor enable the
826 if (peak_meter_y
+ h
<= viewport
->y
+viewport
->height
) {
827 peak_meter_enable(true);
828 peak_meter_screen(gwps
->display
, 0, peak_meter_y
,
829 MIN(h
, viewport
->y
+viewport
->height
- peak_meter_y
));
834 bool skin_has_sbs(enum screen_type screen
, struct wps_data
*data
)
839 #ifdef HAVE_LCD_BITMAP
840 if (data
->wps_sb_tag
)
841 draw
= data
->show_sb_on_wps
;
842 else if (statusbar_position(screen
) != STATUSBAR_OFF
)
849 /* do the button loop as often as required for the peak meters to update
850 * with a good refresh rate.
851 * gwps is really gwps[NB_SCREENS]! don't wrap this if FOR_NB_SCREENS()
853 int skin_wait_for_action(struct gui_wps
*gwps
, int context
, int timeout
)
855 (void)gwps
; /* silence charcell warning */
856 int button
= ACTION_NONE
;
857 #ifdef HAVE_LCD_BITMAP
859 /* when the peak meter is enabled we want to have a
860 few extra updates to make it look smooth. On the
861 other hand we don't want to waste energy if it
866 if(gwps
[i
].data
->peak_meter_enabled
)
871 long next_refresh
= current_tick
;
872 long next_big_refresh
= current_tick
+ timeout
;
873 button
= BUTTON_NONE
;
874 while (TIME_BEFORE(current_tick
, next_big_refresh
)) {
875 button
= get_action(context
,TIMEOUT_NOBLOCK
);
876 if (button
!= ACTION_NONE
) {
880 sleep(0); /* Sleep until end of current tick. */
882 if (TIME_AFTER(current_tick
, next_refresh
)) {
885 if(gwps
[i
].data
->peak_meter_enabled
)
886 skin_update(&gwps
[i
], SKIN_REFRESH_PEAK_METER
);
887 next_refresh
+= HZ
/ PEAK_METER_FPS
;
894 /* The peak meter is disabled
895 -> no additional screen updates needed */
899 button
= get_action(context
, timeout
);