1
#if !defined(lint) && !defined(DOS)
2
static char rcsid[] = "$Id: signal.c 138 2006-09-22 22:12:03Z mikes@u.washington.edu $";
5
/* ========================================================================
6
* Copyright 2006-2007 University of Washington
8
* Licensed under the Apache License, Version 2.0 (the "License");
9
* you may not use this file except in compliance with the License.
10
* You may obtain a copy of the License at
12
* http://www.apache.org/licenses/LICENSE-2.0
14
* ========================================================================
17
/*======================================================================
18
Implement busy_cue spinner
25
#include "../c-client/c-client.h"
27
#include "../pith/conf.h"
28
#include "../pith/state.h"
29
#include "../pith/status.h"
30
#include "../pith/busy.h"
31
#include "../pith/debug.h"
34
#include "../pico/osdep/mswin.h"
42
static char busy_message[MAX_BM + 1];
43
static int busy_cue_on;
44
static int busy_cue_pause;
45
static int busy_width;
46
static int final_message;
47
static int final_message_pri;
49
static percent_done_t percent_done_ptr;
51
#define MAX_SPINNER_WIDTH 32
52
#define MAX_SPINNER_ELEMENTS 28
54
static int spinner = 0;
55
static struct _spinner {
58
char *bars[MAX_SPINNER_ELEMENTS];
60
{4, 8, {"| ", " / ", " _ ", " \\ ", " | ", " \\ ", " _ ", "/ "}},
61
{4, 8, {"_ _ ", "\\ \\ ", " | |", " / /", " _ _", " / /", " | |", "\\ \\ "}},
62
{4, 8, {"_ ", "\\ ", " | ", " / ", " _ ", " \\ ", " | ", "/ "}},
63
{4, 8, {"_ ", "\\ ", " | ", " / ", " _ ", " / ", " | ", "\\ "}},
64
{4, 4, {" . ", " o ", " O ", " o "}},
65
{4, 4, {"... ", " .. ", ". . ", ".. "}},
66
{4, 4, {".oOo", "oOo.", "Oo.o", "o.oO"}},
67
{7, 9, {". .", " . . ", " . . ",
68
" . ", " + ", " * ", " X ",
70
{4, 4, {". O ", "o o ", "O . ", "o o "}},
71
{4, 26,{"| ", "/ ", "_ ", "\\ ", " | ", " / ", " _ ", " \\ ",
72
" | ", " / ", " _ ", " \\ ", " |", " |", " \\ ", " _ ", " / ",
73
" | ", " \\ ", " _ ", " / ", " | ", "\\ ", "_ ", "/ ", "| "}},
74
{4, 8, {"* ", "-* ", "--* ", " --*", " --", " -", " ", " "}},
75
{4, 2, {"\\/\\/", "/\\/\\"}},
76
{4, 4, {"\\|/|", "|\\|/", "/|\\|", "|/|\\"}},
77
{4, 4, {"<|> ", "</> ", "<-> ", "<\\> "}}
83
* various pauses in 100th's of second
85
#define BUSY_PERIOD_SPIN 5 /* busy spinner */
86
#define BUSY_PERIOD_PERCENT 25 /* percent done update */
87
#define BUSY_MSG_DONE 0 /* no more updates */
88
#define BUSY_MSG_RETRY 25 /* message line conflict */
89
#define BUSY_DELAY_PERCENT 33 /* pause before showing % */
90
#define BUSY_DELAY_SPINNER 100 /* second pause before spinner */
93
/* internal prototypes */
94
int do_busy_cue(void *);
95
void done_busy_cue(void *);
101
* msg -- the busy message to print in status line
102
* pc_f -- if non-null, call this function to get the percent done,
103
* (an integer between 0 and 100). If null, append dots.
104
* delay -- seconds to delay output of delay notification
106
* Returns: 0 If busy cue was already set up before we got here
107
* 1 If busy cue was not already set up.
109
* NOTE: busy_cue and cancel_busy_cue MUST be called symetrically in the
110
* same lexical scope.
113
busy_cue(char *msg, percent_done_t pc_f, int delay)
115
AFTER_S *a = NULL, **ap;
117
dprint((9, "busy_cue(%s, %p, %d)\n", msg ? msg : "Busy", pc_f, delay));
119
if(!(ps_global && ps_global->ttyo))
123
* If we're already busy'ing, but a cue is invoked that
124
* supplies more useful info, use it...
128
stop_after(1); /* uninstall old handler */
130
return(0); /* nothing to add, return */
133
/* get ready to set up list of AFTER_S's */
139
percent_done_ptr = pc_f;
142
strncpy(busy_message, msg, sizeof(busy_message));
146
strncpy(busy_message, "Busy", sizeof(busy_message));
150
busy_message[sizeof(busy_message)-1] = '\0';
151
busy_width = utf8_width(busy_message);
154
char progress[MAX_SCREEN_COLS+1];
155
int space_left, slots_used;
158
space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols
159
: 80) - busy_width - 2; /* 2 is for [] */
160
slots_used = MAX(0, MIN(space_left-3, 10));
162
if(percent_done_ptr && slots_used >= 4){
163
snprintf(progress, sizeof(progress), "%s |%*s|", busy_message, slots_used, "");
164
progress[sizeof(progress)-1] = '\0';
168
snprintf(progress, sizeof(progress), "%s%*s", busy_message,
169
spinners[spinner].width + 1, "");
170
progress[sizeof(progress)-1] = '\0';
174
if(status_message_remaining()){
175
char buf[sizeof(progress) + 30];
176
char *append = " [not actually shown]";
178
strncpy(buf, progress, sizeof(buf)-1);
179
buf[sizeof(buf)-1] = '\0';
181
strncat(buf, append, sizeof(buf) - strlen(buf) - 1);
182
buf[sizeof(buf)-1] = '\0';
184
add_review_message(buf, -1);
187
q_status_message(SM_ORDER, 0, 1, progress);
190
* We use display_message so that the initial message will
191
* be forced out only if there is not a previous message
192
* currently being displayed that hasn't been displayed for
193
* its min display time yet. In that case, we don't want
194
* to force out the initial message.
196
display_message('x');
202
spinner = (random() % (sizeof(spinners)/sizeof(struct _spinner)));
204
*ap = new_afterstruct();
205
(*ap)->delay = (pc_f) ? BUSY_DELAY_PERCENT : BUSY_DELAY_SPINNER;
206
(*ap)->f = do_busy_cue;
207
(*ap)->cf = done_busy_cue;
210
start_after(a); /* launch cue handler */
213
mswin_setcursor(MSWIN_CURSOR_BUSY);
221
* If final_message was set when busy_cue was called:
222
* and message_pri = -1 -- no final message queued
223
* else final message queued with min equal to message_pri
226
cancel_busy_cue(int message_pri)
228
dprint((9, "cancel_cue_cue(%d)\n", message_pri));
230
final_message_pri = message_pri;
238
* suspend_busy_cue - continue previously installed busy_cue.
241
suspend_busy_cue(void)
243
dprint((9, "suspend_busy_cue\n"));
251
* resume_busy_cue - continue previously installed busy_cue.
254
resume_busy_cue(unsigned int pause)
256
dprint((9, "resume_busy_cue\n"));
265
* do_busy_cue - paint the busy cue and return how long caller
266
* should pause before calling us again
269
do_busy_cue(void *data)
271
int space_left, slots_used, period;
272
char dbuf[MAX_SCREEN_COLS+1];
274
/* Don't wipe out any displayed status message prematurely */
275
if(status_message_remaining() || busy_cue_pause)
276
return(BUSY_MSG_RETRY);
278
space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) -
279
busy_width - 2; /* 2 is for [] */
280
slots_used = MAX(0, MIN(space_left-3, 10));
282
if(percent_done_ptr && slots_used >= 4){
286
pd = (*percent_done_ptr)();
287
pd = MIN(MAX(0, pd), 100);
289
completed = (pd * slots_used) / 100;
290
snprintf(dbuf, sizeof(dbuf), "%s |%s%s%*s|", busy_message,
291
completed > 1 ? repeat_char(completed-1, pd==100 ? ' ' : '-') : "",
292
(completed > 0 && pd != 100) ? ">" : "",
293
slots_used - completed, "");
294
dbuf[sizeof(dbuf)-1] = '\0';
296
if(slots_used == 10){
297
s = dbuf + strlen(dbuf) - 8;
304
*s++ = '0' + pd / 10;
305
*s++ = '0' + pd % 10;
316
period = BUSY_PERIOD_PERCENT;
319
char b[MAX_SPINNER_WIDTH + 2];
322
ind = (dotcount % spinners[spinner].elements);
324
if(space_left >= spinners[spinner].width + 1){
327
(ps_global->active_status_interval > 0)
328
? spinners[spinner].bars[ind] : "... ", sizeof(b)-1);
329
b[sizeof(b)-1] = '\0';
331
else if(space_left >= 2 && space_left < sizeof(b)){
335
b[space_left] = '\0';
340
snprintf(dbuf, sizeof(dbuf), "%s%s", busy_message, b);
341
dbuf[sizeof(dbuf)-1] = '\0';
343
/* convert interval to delay in 100ths of second */
344
period = (ps_global->active_status_interval > 0)
345
? (100 / MIN(10, ps_global->active_status_interval)) : BUSY_MSG_DONE;
348
status_message_write(dbuf, 1);
357
done_busy_cue(void *data)
359
int space_left, slots_used;
361
if(final_message && final_message_pri >= 0){
362
char progress[MAX_SCREEN_COLS+1];
365
space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) - busy_width - 2;
366
slots_used = MAX(0, MIN(space_left-3, 10));
368
if(percent_done_ptr && slots_used >= 4){
371
right = (slots_used - 4)/2;
372
left = slots_used - 4 - right;
373
snprintf(progress, sizeof(progress), "%s |%*s100%%%*s|",
374
busy_message, left, "", right, "");
375
progress[sizeof(progress)-1] = '\0';
376
q_status_message(SM_ORDER,
377
final_message_pri>=2 ? MAX(final_message_pri,3) : 0,
378
final_message_pri+2, progress);
381
snprintf(progress, sizeof(progress), "%s%*sDONE", busy_message,
382
spinners[spinner].width - 4 + 1, "");
383
progress[sizeof(progress)-1] = '\0';
384
q_status_message(SM_ORDER,
385
final_message_pri>=2 ? MAX(final_message_pri,3) : 0,
386
final_message_pri+2, progress);