~ubuntu-branches/debian/squeeze/alpine/squeeze

« back to all changes in this revision

Viewing changes to alpine/busy.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: signal.c 138 2006-09-22 22:12:03Z mikes@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/* ========================================================================
 
6
 * Copyright 2006-2007 University of Washington
 
7
 *
 
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
 
11
 *
 
12
 *     http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 * ========================================================================
 
15
 */
 
16
 
 
17
/*======================================================================
 
18
     Implement busy_cue spinner
 
19
 ====*/
 
20
 
 
21
 
 
22
#include <system.h>
 
23
#include <general.h>
 
24
 
 
25
#include "../c-client/c-client.h"
 
26
 
 
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"
 
32
 
 
33
#ifdef _WINDOWS
 
34
#include "../pico/osdep/mswin.h"
 
35
#endif
 
36
 
 
37
#include "after.h"
 
38
#include "busy.h"
 
39
 
 
40
 
 
41
static int       dotcount;
 
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;
 
48
 
 
49
static percent_done_t percent_done_ptr;
 
50
 
 
51
#define MAX_SPINNER_WIDTH       32
 
52
#define MAX_SPINNER_ELEMENTS    28
 
53
 
 
54
static int spinner = 0;
 
55
static struct _spinner {
 
56
        int    width, 
 
57
               elements;
 
58
        char *bars[MAX_SPINNER_ELEMENTS];
 
59
} spinners[] = {
 
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   ",
 
69
            "   #   ", "       "}},
 
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, {"<|> ", "</> ", "<-> ", "<\\> "}}
 
78
};
 
79
 
 
80
 
 
81
 
 
82
/*
 
83
 * various pauses in 100th's of second
 
84
 */
 
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 */
 
91
 
 
92
 
 
93
/* internal prototypes */
 
94
int     do_busy_cue(void *);
 
95
void    done_busy_cue(void *);
 
96
 
 
97
 
 
98
/*
 
99
 * Turn on a busy cue.
 
100
 *
 
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
 
105
 *
 
106
 *   Returns:  0 If busy cue was already set up before we got here
 
107
 *             1 If busy cue was not already set up.
 
108
 *
 
109
 *   NOTE: busy_cue and cancel_busy_cue MUST be called symetrically in the
 
110
 *         same lexical scope.
 
111
 */
 
112
int
 
113
busy_cue(char *msg, percent_done_t pc_f, int delay)
 
114
{
 
115
    AFTER_S *a = NULL, **ap;
 
116
 
 
117
    dprint((9, "busy_cue(%s, %p, %d)\n", msg ? msg : "Busy", pc_f, delay));
 
118
 
 
119
    if(!(ps_global && ps_global->ttyo))
 
120
      return(0);
 
121
 
 
122
    /*
 
123
     * If we're already busy'ing, but a cue is invoked that
 
124
     * supplies more useful info, use it...
 
125
     */
 
126
    if(busy_cue_on){
 
127
        if(msg || pc_f)
 
128
          stop_after(1);        /* uninstall old handler */
 
129
        else
 
130
          return(0);            /* nothing to add, return */
 
131
    }
 
132
 
 
133
    /* get ready to set up list of AFTER_S's */
 
134
    ap = &a;
 
135
 
 
136
    busy_cue_on = 1;
 
137
 
 
138
    dotcount = 0;
 
139
    percent_done_ptr = pc_f;
 
140
 
 
141
    if(msg){
 
142
        strncpy(busy_message, msg, sizeof(busy_message));
 
143
        final_message = 1;
 
144
    }
 
145
    else{
 
146
        strncpy(busy_message, "Busy", sizeof(busy_message));
 
147
        final_message = 0;
 
148
    }
 
149
 
 
150
    busy_message[sizeof(busy_message)-1] = '\0';
 
151
    busy_width = utf8_width(busy_message);
 
152
 
 
153
    if(!delay){
 
154
        char progress[MAX_SCREEN_COLS+1];
 
155
        int space_left, slots_used;
 
156
 
 
157
        final_message = 1;
 
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));
 
161
 
 
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';
 
165
        }
 
166
        else{
 
167
            dotcount++;
 
168
            snprintf(progress, sizeof(progress), "%s%*s", busy_message,
 
169
                     spinners[spinner].width + 1, "");
 
170
            progress[sizeof(progress)-1] = '\0';
 
171
        }
 
172
 
 
173
 
 
174
        if(status_message_remaining()){
 
175
            char buf[sizeof(progress) + 30];
 
176
            char  *append = " [not actually shown]";
 
177
 
 
178
            strncpy(buf, progress, sizeof(buf)-1);
 
179
            buf[sizeof(buf)-1] = '\0';
 
180
 
 
181
            strncat(buf, append, sizeof(buf) - strlen(buf) - 1);
 
182
            buf[sizeof(buf)-1] = '\0';
 
183
 
 
184
            add_review_message(buf, -1);
 
185
        }
 
186
        else{
 
187
            q_status_message(SM_ORDER, 0, 1, progress);
 
188
 
 
189
            /*
 
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.
 
195
             */
 
196
            display_message('x');
 
197
        }
 
198
        
 
199
        fflush(stdout);
 
200
    }
 
201
 
 
202
    spinner = (random() % (sizeof(spinners)/sizeof(struct _spinner)));
 
203
 
 
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;
 
208
    ap           = &(*ap)->next;
 
209
 
 
210
    start_after(a);             /* launch cue handler */
 
211
 
 
212
#ifdef _WINDOWS
 
213
    mswin_setcursor(MSWIN_CURSOR_BUSY);
 
214
#endif
 
215
 
 
216
    return(1);
 
217
}
 
218
 
 
219
 
 
220
/*
 
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
 
224
 */
 
225
void
 
226
cancel_busy_cue(int message_pri)
 
227
{
 
228
    dprint((9, "cancel_cue_cue(%d)\n", message_pri));
 
229
 
 
230
    final_message_pri = message_pri;
 
231
 
 
232
    stop_after(0);
 
233
 
 
234
    busy_cue_on = 0;
 
235
}
 
236
 
 
237
/*
 
238
 * suspend_busy_cue - continue previously installed busy_cue.
 
239
 */
 
240
void
 
241
suspend_busy_cue(void)
 
242
{
 
243
    dprint((9, "suspend_busy_cue\n"));
 
244
 
 
245
    if(busy_cue_on)
 
246
      busy_cue_pause = 1;
 
247
}
 
248
 
 
249
 
 
250
/*
 
251
 * resume_busy_cue - continue previously installed busy_cue.
 
252
 */
 
253
void
 
254
resume_busy_cue(unsigned int pause)
 
255
{
 
256
    dprint((9, "resume_busy_cue\n"));
 
257
 
 
258
    if(busy_cue_on){
 
259
      busy_cue_pause = 0;
 
260
    }
 
261
}
 
262
 
 
263
 
 
264
/*
 
265
 * do_busy_cue - paint the busy cue and return how long caller
 
266
 *               should pause before calling us again
 
267
 */
 
268
int
 
269
do_busy_cue(void *data)
 
270
{
 
271
    int space_left, slots_used, period;
 
272
    char dbuf[MAX_SCREEN_COLS+1];
 
273
 
 
274
    /* Don't wipe out any displayed status message prematurely */
 
275
    if(status_message_remaining() || busy_cue_pause)
 
276
      return(BUSY_MSG_RETRY);
 
277
 
 
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));
 
281
 
 
282
    if(percent_done_ptr && slots_used >= 4){
 
283
        int completed, pd;
 
284
        char *s;
 
285
 
 
286
        pd = (*percent_done_ptr)();
 
287
        pd = MIN(MAX(0, pd), 100);
 
288
 
 
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';
 
295
 
 
296
        if(slots_used == 10){
 
297
            s = dbuf + strlen(dbuf) - 8;
 
298
            if(pd < 10){
 
299
                s++; s++;
 
300
                *s++ = '0' + pd;
 
301
            }
 
302
            else if(pd < 100){
 
303
                s++;
 
304
                *s++ = '0' + pd / 10;
 
305
                *s++ = '0' + pd % 10;
 
306
            }
 
307
            else{
 
308
                *s++ = '1';
 
309
                *s++ = '0';
 
310
                *s++ = '0';
 
311
            }
 
312
 
 
313
            *s   = '%';
 
314
        }
 
315
 
 
316
        period = BUSY_PERIOD_PERCENT;
 
317
    }
 
318
    else{
 
319
        char b[MAX_SPINNER_WIDTH + 2];
 
320
        int ind;
 
321
 
 
322
        ind = (dotcount % spinners[spinner].elements);
 
323
 
 
324
        if(space_left >= spinners[spinner].width + 1){
 
325
            b[0] = SPACE;
 
326
            strncpy(b+1,
 
327
                    (ps_global->active_status_interval > 0)
 
328
                      ? spinners[spinner].bars[ind] : "... ", sizeof(b)-1);
 
329
            b[sizeof(b)-1] = '\0';
 
330
        }
 
331
        else if(space_left >= 2 && space_left < sizeof(b)){
 
332
            b[0] = '.';
 
333
            b[1] = '.';
 
334
            b[2] = '.';
 
335
            b[space_left] = '\0';
 
336
        }
 
337
        else
 
338
          b[0] = '\0';
 
339
 
 
340
        snprintf(dbuf, sizeof(dbuf), "%s%s", busy_message, b);
 
341
        dbuf[sizeof(dbuf)-1] = '\0';
 
342
 
 
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;
 
346
    }
 
347
 
 
348
    status_message_write(dbuf, 1);
 
349
    dotcount++;
 
350
    fflush(stdout);
 
351
 
 
352
    return(period);
 
353
}
 
354
 
 
355
 
 
356
void
 
357
done_busy_cue(void *data)
 
358
{
 
359
    int space_left, slots_used;
 
360
 
 
361
    if(final_message && final_message_pri >= 0){
 
362
        char progress[MAX_SCREEN_COLS+1];
 
363
 
 
364
        /* 2 is for [] */
 
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));
 
367
 
 
368
        if(percent_done_ptr && slots_used >= 4){
 
369
            int left, right;
 
370
 
 
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);
 
379
        }
 
380
        else{
 
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);
 
387
        }
 
388
    }
 
389
 
 
390
    mark_status_dirty();
 
391
}
 
392