ARB
AW_status.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AW_status.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include <aw_root.hxx>
12 #include <aw_question.hxx>
13 #include <aw_awars.hxx>
14 #include <aw_window.hxx>
15 #include "aw_msg.hxx"
16 #include "aw_status.hxx"
17 #include "aw_preset.hxx"
18 
19 #include <arbdbt.h>
20 #include <arb_strbuf.h>
21 #include <arb_sleep.h>
22 #include <SigHandler.h>
23 
24 #include <cerrno>
25 #include <cstdarg>
26 #include <ctime>
27 #include <unistd.h>
28 
29 using namespace std;
30 
31 #define FD_SET_TYPE
32 
33 // Globals
34 #define AW_GAUGE_SIZE 40 // length of gauge display (in characters)
35 #define AW_GAUGE_GRANULARITY 10000 // how fine the gauge is transported to status (no of steps) [old value = 1000]
36 
37 #define AW_STATUS_KILL_DELAY 4000 // in ms
38 #define AW_STATUS_LISTEN_DELAY 300 // in ms
39 #define AW_STATUS_HIDE_DELAY 60 // in sec
40 #define AW_STATUS_PIPE_CHECK_DELAY 1000*2 // in ms (a pipe check every 2 seconds)
41 
42 #define AWAR_STATUS "tmp/status/"
43 #define AWAR_STATUS_TITLE AWAR_STATUS "title"
44 #define AWAR_STATUS_TEXT AWAR_STATUS "text"
45 #define AWAR_STATUS_GAUGE AWAR_STATUS "gauge"
46 #define AWAR_STATUS_ELAPSED AWAR_STATUS "elapsed"
47 
48 #define AW_MESSAGE_LINES 500
49 
50 #if defined(DEBUG)
51 
52 // ARB_LOGGING should always be undefined in SVN version!
53 // #define ARB_LOGGING
54 // #define TRACE_STATUS // // // enable debug output for status window (which runs forked!)
55 // #define TRACE_STATUS_MORE // // enable more debug output
56 // #define PIPE_DEBUGGING // // enable debug output for pipes (for write commands)
57 
58 // Note: basic logging of progress information is done to console
59 
60 #endif // DEBUG
61 
62 #if !defined(DEVEL_RELEASE)
63 # define FORCE_WEIGHTED_ESTIMATION // see also ../CORE/arb_progress.h@FORCEWEIGHTEDESTIMATION
64 #endif
65 
67  // messages send from status-process to main-process :
70  // messages send from main-process to status-process :
78 };
79 
80 #define AW_EST_BUFFER 5 // size of buffer used to smoothen estimations
81 
82 struct aw_stg_struct {
83  int fd_to[2];
84  int fd_from[2];
85  bool mode;
86  int hide;
87  int hide_delay; // in seconds
88  pid_t pid;
89  bool is_child; // true in status window process
91  int err_no;
95  char *lines[AW_MESSAGE_LINES];
96  bool need_refresh; // if true -> message list needs to refresh
100  time_t last_start; // time of last status start
102  long last_estimation[AW_EST_BUFFER];
103  long last_used_est; // most recent estimation (overall runtime in seconds)
104 };
105 
107  { 0, 0 }, // fd_to
108  { 0, 0 }, // fd_from
109  AW_STATUS_OK, // mode
110  0, // hide
111  0, // hide_delay
112  0, // pid
113  false, // is_child
114  0, // pipe_broken
115  0, // errno
116  NULp, // aws
117  NULp, // awm
118  false, // status_initialized
119  { NULp, NULp, NULp }, // lines
120  false, // need_refresh
121  0, // last_refresh_time
122  0, // last_message_time
123  0, // local_message
124  0, // last_start
125  0, // last_est_count
126  { 0 }, // last_estimation
127  -1, // last_used_est
128 };
129 
130 // timeouts :
131 
132 #define POLL_TIMEOUT 0 // idle wait POLL_TIMEOUT microseconds before returning EOF when polling
133 
134 #if defined(DEBUG)
135 #define WRITE_TIMEOUT 1000 // 1 second for debug version (short because it always reaches timeout inside debugger)
136 #else
137 #define WRITE_TIMEOUT 10000 // 10 seconds for release
138 #endif // DEBUG
139 
140 static void mark_pipe_broken(int err_no) {
141 #if defined(PIPE_DEBUGGING)
142  if (aw_stg.pipe_broken != 0) {
143  fprintf(stderr,
144  "Pipe already broken in mark_pipe_broken(); pipe_broken=%i aw_stg.errno=%i errno=%i\n",
145  aw_stg.pipe_broken, aw_stg.err_no, err_no);
146  }
147 
148  fprintf(stderr, "Marking pipe as broken (errno=%i)\n", err_no);
149 #endif // PIPE_DEBUGGING
150 
151  aw_stg.err_no = err_no;
152  aw_stg.pipe_broken = 1;
153 
154  static bool error_shown = false;
155  if (!error_shown) {
156  fprintf(stderr,
157  "******************************************************************\n"
158  "The connection to the status window was blocked unexpectedly!\n"
159  "This happens if you run the program from inside the debugger\n"
160  "or when the process is blocked longer than %5.2f seconds.\n"
161  "Further communication with the status window is suppressed.\n"
162  "******************************************************************\n"
163  , WRITE_TIMEOUT/1000.0);
164  }
165 }
166 
167 static ssize_t safe_write(int fd, const char *buf, int count) {
168  if (aw_stg.pipe_broken != 0) {
169 #if defined(PIPE_DEBUGGING)
170  fprintf(stderr, "pipe is broken -- avoiding write of %i bytes\n", count);
171 #endif // PIPE_DEBUGGING
172  return -1;
173  }
174 
175  aw_assert(count>0); // write nothing - bad idea
176 
177  ssize_t result = -1;
178  {
179  fd_set set;
180  struct timeval timeout;
181  timeout.tv_sec = WRITE_TIMEOUT/1000;
182  timeout.tv_usec = WRITE_TIMEOUT%1000;
183 
184  FD_ZERO(&set);
185  FD_SET(fd, &set);
186 
187  int sel_res = select(fd+1, NULp, &set, NULp, &timeout);
188 
189  if (sel_res == -1) {
190  fprintf(stderr, "select (before write) returned error (errno=%i)\n", errno);
191  exit(EXIT_FAILURE);
192  }
193 
194  bool pipe_would_block = !FD_ISSET(fd, &set);
195 
196 #if defined(PIPE_DEBUGGING)
197  fprintf(stderr, "select returned %i, pipe_would_block=%i (errno=%i)\n",
198  sel_res, int(pipe_would_block), errno);
199 
200  if (pipe_would_block) {
201  fprintf(stderr, " Avoiding to write to pipe (because it would block!)\n");
202  }
203  else {
204  fprintf(stderr, " Write %i bytes to pipe.\n", count);
205  }
206 #endif // PIPE_DEBUGGING
207 
208  if (!pipe_would_block) {
209  result = write(fd, buf, count);
210  }
211  }
212 
213  if (result<0) {
214  mark_pipe_broken(errno);
215  }
216  else if (result != count) {
217 #if defined(PIPE_DEBUGGING)
218  fprintf(stderr, "write wrote %i bytes instead of %i as requested.\n", result, count);
219 #endif // PIPE_DEBUGGING
220  mark_pipe_broken(0);
221  }
222 
223  return result;
224 }
225 
226 static void aw_status_write(int fd, int cmd) {
227  char buf = cmd;
228  safe_write(fd, &buf, 1);
229 }
230 
231 static int aw_status_read_byte(int fd, int poll_flag) {
232  /* read one byte from the pipe,
233  * if poll ==1 then don't wait for any data, but return EOF */
234  int erg;
235  unsigned char buffer[2];
236 
237  if (poll_flag) {
238  fd_set set;
239  struct timeval timeout;
240  timeout.tv_sec = POLL_TIMEOUT/1000;
241  timeout.tv_usec = POLL_TIMEOUT%1000;
242 
243  FD_ZERO (&set);
244  FD_SET (fd, &set);
245 
246  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
247  if (erg == 0) return EOF;
248  }
249  erg = read(fd, (char *)&(buffer[0]), 1);
250  if (erg<=0) {
251  // process died
252  fprintf(stderr, "father died, now i kill myself\n");
253  exit(EXIT_FAILURE);
254  }
255  return buffer[0];
256 }
257 
258 static int aw_status_read_int(int fd, int poll_flag) {
259  /* read one integer from the pipe,
260  * if poll ==1 then don't wait for any data, but return EOF */
261 
262  int erg;
263 
264  if (poll_flag) {
265  fd_set set;
266  struct timeval timeout;
267  timeout.tv_sec = POLL_TIMEOUT/1000;
268  timeout.tv_usec = POLL_TIMEOUT%1000;
269 
270  FD_ZERO (&set);
271  FD_SET (fd, &set);
272 
273  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
274  if (erg == 0) return EOF;
275  }
276  union {
277  unsigned char buffer[sizeof(int)+1];
278  int as_int;
279  } input;
280 
281  erg = read(fd, input.buffer, sizeof(int));
282  if (erg<=0) { // process died
283  fprintf(stderr, "father died, now i kill myself\n");
284  exit(EXIT_FAILURE);
285  }
286  return input.as_int;
287 }
288 
289 static int aw_status_read_command(int fd, int poll_flag, char*& str, int *gaugePtr = NULp) {
290  char buffer[1024];
291  int cmd = aw_status_read_byte(fd, poll_flag);
292 
293  if (cmd == AW_STATUS_CMD_TEXT ||
294  cmd == AW_STATUS_CMD_OPEN ||
295  cmd == AW_STATUS_CMD_NEW_TITLE ||
296  cmd == AW_STATUS_CMD_MESSAGE) {
297  char *p = buffer;
298  int c;
299  for (
300  c = aw_status_read_byte(fd, 0);
301  c;
302  c = aw_status_read_byte(fd, 0)) {
303  *(p++) = c;
304  }
305  *(p++) = c;
306 
307  str = strdup(buffer);
308  }
309  else if (cmd == AW_STATUS_CMD_GAUGE) {
310  int gauge = aw_status_read_int(fd, 0);
311  if (gaugePtr) *gaugePtr = gauge;
312 
313  char *p = buffer;
314  int i = 0;
315 
316  int rough_gauge = (gauge*AW_GAUGE_SIZE)/AW_GAUGE_GRANULARITY;
317  for (; i<rough_gauge && i<AW_GAUGE_SIZE; ++i) *p++ = '*';
318  for (; i<AW_GAUGE_SIZE; ++i) *p++ = '-';
319 
320  if (rough_gauge<AW_GAUGE_SIZE) {
321  int fine_gauge = (gauge*AW_GAUGE_SIZE*4)/AW_GAUGE_GRANULARITY;
322  buffer[rough_gauge] = "-\\|/"[fine_gauge%4];
323  }
324 
325  *p = 0;
326  str = strdup(buffer);
327  }
328  else {
329  str = NULp;
330  }
331  return cmd;
332 }
333 
334 static void aw_status_check_pipe() {
335  if (getppid() <= 1) {
336 #if defined(TRACE_STATUS)
337  fprintf(stderr, "Terminating status process.\n");
338 #endif // TRACE_STATUS
339  exit(EXIT_FAILURE);
340  }
341 }
342 
343 static void aw_status_wait_for_open(int fd) {
344  char *str = NULp;
345  int cmd;
346  int erg;
347 
348  for (cmd = 0; cmd != AW_STATUS_CMD_INIT;) {
349  for (erg = 0; !erg;) {
350  struct timeval timeout;
351  timeout.tv_sec = AW_STATUS_PIPE_CHECK_DELAY / 1000;
352  timeout.tv_usec = AW_STATUS_PIPE_CHECK_DELAY % 1000;
353 
354  fd_set set;
355 
356  FD_ZERO (&set);
357  FD_SET (fd, &set);
358 
359 #if defined(TRACE_STATUS)
360  fprintf(stderr, "Waiting for status open command..\n"); fflush(stderr);
361 #endif // TRACE_STATUS
362  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
363  if (!erg) aw_status_check_pipe(); // time out
364  }
365  freenull(str);
366  cmd = aw_status_read_command(fd, 0, str);
367  }
368  aw_stg.mode = AW_STATUS_OK;
369  freenull(str);
370 
371 #if defined(TRACE_STATUS)
372  fprintf(stderr, "OK got status open command!\n"); fflush(stderr);
373 #endif // TRACE_STATUS
374 }
375 
376 
378  if (aw_stg.hide) {
379  aw_stg.aws->show();
380  aw_stg.hide = 0;
381  }
382  return 0; // do not recall
383 }
384 
385 static void aw_status_hide(AW_window *aws) {
386  aw_stg.hide = 1;
387  aws->hide();
388 
389  // install timer event
390  aws->get_root()->add_timed_callback(aw_stg.hide_delay*1000, makeTimedCallback(aw_status_timer_hide_event));
391 
392  // increase hide delay for next press of hide button
393  if (aw_stg.hide_delay < (60*60)) { // max hide delay is 1 hour
394  aw_stg.hide_delay *= 3; // initial: 60sec -> 3min -> 9min -> 27min -> 60min (max)
395  }
396  else {
397  aw_stg.hide_delay = 60*60;
398  }
399 }
400 
401 
402 static unsigned aw_status_timer_event(AW_root *awr) {
403 #if defined(TRACE_STATUS_MORE)
404  fprintf(stderr, "in aw_status_timer_event\n"); fflush(stdout);
405 #endif // TRACE_STATUS_MORE
406  if (aw_stg.mode == AW_STATUS_ABORT) {
407  int action = aw_question(NULp,
408  "Couldn't quit properly in time.\n"
409  "Now you can either\n"
410  "- wait again (recommended),\n"
411  "- kill the whole application(!) or\n"
412  "- continue.",
413  "Wait again,Kill application!,Continue");
414 
415  switch (action) {
416  case 0:
417  break;
418  case 1: {
419  char buf[255];
420  sprintf(buf, "kill -9 %i", aw_stg.pid);
422  exit(EXIT_SUCCESS);
423  }
424  case 2: {
425  char *title = awr->awar(AWAR_STATUS_TITLE)->read_string();
426  char *subtitle = awr->awar(AWAR_STATUS_TEXT)->read_string();
427 
428  aw_message(GBS_global_string("If you think the process should be made abortable,\n"
429  "please send the following information to devel@arb-home.de:\n"
430  "\n"
431  "Calculation not abortable from status window.\n"
432  "Title: %s\n"
433  "Subtitle: %s\n",
434  title, subtitle));
435  aw_stg.mode = AW_STATUS_OK;
436 
437  free(subtitle);
438  free(title);
439  break;
440  }
441  }
442  }
443  return 0; // do not recall
444 }
445 
446 static void aw_status_kill(AW_window *aws) {
447  if (aw_stg.mode == AW_STATUS_ABORT) {
449  if (aw_stg.mode == AW_STATUS_OK) { // continue
450  return;
451  }
452  }
453  else {
454  if (!aw_ask_sure("aw_status_kill", "Are you sure to abort running calculation?")) {
455  return; // don't abort
456  }
457  aw_stg.mode = AW_STATUS_ABORT;
458  }
459  aw_status_write(aw_stg.fd_from[1], aw_stg.mode);
460 
461  if (aw_stg.mode == AW_STATUS_ABORT) {
462 #if defined(TRACE_STATUS_MORE)
463  fprintf(stderr, "add aw_status_timer_event with delay = %i\n", AW_STATUS_KILL_DELAY); fflush(stdout);
464 #endif // TRACE_STATUS_MORE
465  aws->get_root()->add_timed_callback(AW_STATUS_KILL_DELAY, makeTimedCallback(aw_status_timer_event)); // install timer event
466  }
467 }
468 
471 
472  for (int i = AW_MESSAGE_LINES-1; i>=0; i--) {
473  if (aw_stg.lines[i]) {
474  msgs.cat(aw_stg.lines[i]);
475  msgs.put('\n');
476  }
477  };
478 
480 
481  aw_stg.need_refresh = false;
482  aw_stg.last_refresh_time = aw_stg.last_message_time;
483 }
484 
486  free(aw_stg.lines[0]);
487  for (int i = 1; i< AW_MESSAGE_LINES; i++) {
488  aw_stg.lines[i-1] = aw_stg.lines[i];
489  };
490 
491  time_t t = time(NULp);
492  struct tm *lt = localtime(&t);
493  const char *lf = strchr(message, '\n');
494  char *copy = NULp;
495 
496  if (lf) { // contains linefeeds
497  const int indentation = 10;
498  int count = 1;
499 
500  while (lf) { lf = strchr(lf+1, '\n'); ++count; }
501 
502  int newsize = strlen(message)+count*indentation+1;
503  ARB_alloc(copy, newsize);
504 
505  lf = strchr(message, '\n');
506  char *cp = copy;
507  while (lf) {
508  int len = lf-message;
509  memcpy(cp, message, len+1);
510  cp += len+1;
511  memset(cp, ' ', indentation);
512  cp += indentation;
513 
514  message = lf+1;
515  lf = strchr(message, '\n');
516  }
517 
518  strcpy(cp, message);
519 
520  message = copy;
521  }
522 
523  aw_stg.lines[AW_MESSAGE_LINES-1] = GBS_global_string_copy("%02i:%02i.%02i %s",
524  lt->tm_hour, lt->tm_min, lt->tm_sec,
525  message);
526  aw_stg.last_message_time = t;
527  free(copy);
528 
529  aw_stg.need_refresh = true;
530 }
531 
532 static void aw_insert_message_in_tmp_message(AW_root *awr, const char *message) {
535 }
536 
537 #define MAX_SEC_WIDTH 7 // max width reported from sec2disp
538 #define MAX_SEC_WIDTH_STR stringize_pscan(MAX_SEC_WIDTH)
539 
540 #define plural(unit) ("s"+((unit) == 1))
541 
542 inline const char *sec2disp(long seconds) { // @@@ pass seconds as double (=return value from difftime)
543  static char buffer[50];
544 
545  if (seconds<0) seconds = 0;
546  if (seconds<100) {
547  sprintf(buffer, "%li sec", seconds);
548  }
549  else {
550  long minutes = (seconds+30)/60;
551 
552  if (minutes<60) {
553  sprintf(buffer, "%li min", minutes);
554  }
555  else {
556  long hours = minutes/60;
557  if (hours<24) {
558  minutes = minutes%60;
559  if (minutes == 0 && hours<10) sprintf(buffer, "%li hour%s", hours, plural(hours));
560  else sprintf(buffer, "%lih:%02lim", hours, minutes);
561  }
562  else {
563  long days = hours/24;
564  if (days<7) {
565  hours = hours%24;
566  if (hours == 0) sprintf(buffer, "%li day%s", days, plural(days));
567  else sprintf(buffer, "%lid:%02lih", days, hours);
568  }
569  else {
570  long weeks = days/7;
571  if (days<31) {
572  days = days%7;
573  if (days == 0) sprintf(buffer, "%li week%s", weeks, plural(weeks));
574  else sprintf(buffer, "%liw:%02lid", weeks, days);
575  }
576  else {
577  const double MEAN_MONTH_DAYS = 365/12.0;
578  long months = days/MEAN_MONTH_DAYS;
579  if (days<365) {
580  days = days - long(months*MEAN_MONTH_DAYS);
581  weeks = days/7;
582  if (weeks == 0) {
583  if (months == 1) strcpy(buffer, "1 month");
584  else sprintf(buffer, "%li mon", months);
585  }
586  else sprintf(buffer, "%liM:%02liw", months, weeks);
587  }
588  else {
589  long years = days/365;
590  days = days%365;
591  months = days/MEAN_MONTH_DAYS;
592 
593  if (months == 0) sprintf(buffer, "%li year%s", years, plural(years));
594  else sprintf(buffer, "%liy:%02liM", years, months);
595  }
596  }
597  }
598  }
599  }
600  }
601  arb_assert(strlen(buffer)<=MAX_SEC_WIDTH);
602  return buffer;
603 }
604 
605 
606 static time_t status_started; // @@@ later use 'aw_stg.last_start' instead!
607 static bool timer_ok = false; // @@@ put a similar flag into 'aw_stg'!
608 
609 enum LogLevel {
616 };
617 
618 inline const char *readableTime(const time_t& t) {
619  char *timestr = ctime(&t);
620  char *nl = strchr(timestr, '\n');
621  if (nl) nl[0] = 0; // cut off LF
622  return timestr;
623 }
624 
625 inline void LOG_STATUS(const char *txt1, const char *txt2, LogLevel level) { // @@@ rename
626  time_t now;
627  bool hide = false;
628 
629  if (time(&now) != -1 && timer_ok) {
630  static time_t last_minute = 0;
631  static time_t last_second = 0;
632 
633  if (level == LOG_ONCE_PER_SECOND) {
634  double since_last_second = difftime(now, last_second);
635  if (since_last_second<1) hide = true;
636  else last_second = now;
637  }
638  else if (level == LOG_ONCE_PER_MINUTE_WITH_ESTIMATION) {
639  double since_last_minute = difftime(now, last_minute);
640  if (since_last_minute<60) hide = true;
641  else last_minute = now;
642  }
643  else if (level == LOG_ONCE_PER_15_MINUTES_WITH_ESTIMATION) {
644  double since_last_minute = difftime(now, last_minute);
645  if (since_last_minute<(15*60)) hide = true;
646  else last_minute = now;
647  }
648  else if (level == LOG_ALWAYS_RESET_ONCE_LIMITS) {
649  last_second = 0; // used to show subtitles
650  last_minute = now; // used to show progress %
651  }
652 
653  if (!hide) {
654  const char *nowstr = readableTime(now);
655  double sec_elapsed = difftime(now, status_started);
656  const char *elapsed = sec2disp(sec_elapsed);
657 
658  fprintf(stderr, "[ %s - %" MAX_SEC_WIDTH_STR "s ", nowstr, elapsed);
659 
660  // show estimation?
664  {
665  if (aw_stg.last_used_est != -1) {
666  time_t finish = status_started + aw_stg.last_used_est; // estimated finish time
667  // @@@ move functionality above into a global function 'time_t addtime(time_t t0, double diffsec) - opposed to difftime()
668 
669  double sec_ahead = aw_stg.last_used_est - sec_elapsed;
670  const char *finstr = readableTime(finish);
671  const char *ahead = sec2disp(sec_ahead);
672 
673  fprintf(stderr, "| Rest: %" MAX_SEC_WIDTH_STR "s - %s ", ahead, finstr);
674  }
675  }
676 
677  fputc(']', stderr);
678  }
679  }
680  else {
681  fputs("[unknown time + duration]", stderr);
682  }
683  if (!hide) {
684  fputc(' ', stderr);
685  fputs(txt1, stderr);
686  fputs(txt2, stderr);
687  fputc('\n', stderr);
688  }
689 }
690 
691 #ifdef ARB_LOGGING
692 static void aw_status_append_to_log(const char* str) {
693  static const char *logname = 0;
694  if (!logname) {
695  logname = GBS_global_string_copy("%s/arb.log", GB_getenvHOME());
696  }
697 
698  int fd = open(logname, O_WRONLY|O_APPEND);
699  if (fd == -1) fd = open(logname, O_CREAT|O_WRONLY|O_APPEND, S_IWUSR | S_IRUSR);
700  if (fd == -1) return;
701 
702  write(fd, str, strlen(str));
703  write(fd, "\n", 1);
704  close(fd);
705 }
706 #endif
707 
708 
709 static unsigned aw_status_timer_listen_event(AW_root *awr) {
710  static int delay = AW_STATUS_LISTEN_DELAY;
711  int cmd;
712  char *str = NULp;
713  int gaugeValue = 0;
714 
715 #if defined(TRACE_STATUS_MORE)
716  fprintf(stderr, "in aw_status_timer_listen_event (aw_stg.is_child=%i)\n", (int)aw_stg.is_child); fflush(stdout);
717 #endif // TRACE_STATUS_MORE
718 
719  if (aw_stg.need_refresh && aw_stg.last_refresh_time != aw_stg.last_message_time) {
720  aw_refresh_tmp_message_display(awr); // force refresh each second
721  }
722 
723  cmd = aw_status_read_command(aw_stg.fd_to[0], 1, str, &gaugeValue);
724  if (cmd == EOF) {
726  delay = delay*3/2+1; // wait a longer time
727  if (aw_stg.need_refresh) aw_refresh_tmp_message_display(awr); // and do the refresh here
728  }
729  else {
730  delay = delay*2/3+1; // shorten time (was *2/3+1)
731  }
732  char *gauge = NULp;
733  while (cmd != EOF) {
734  switch (cmd) {
735  case AW_STATUS_CMD_OPEN:
736 #if defined(TRACE_STATUS)
737  fprintf(stderr, "received AW_STATUS_CMD_OPEN\n"); fflush(stdout);
738 #endif // TRACE_STATUS
739  aw_stg.mode = AW_STATUS_OK;
740  aw_stg.last_start = time(NULp);
741  aw_stg.last_est_count = 0;
742  aw_stg.last_used_est = -1;
743  aw_stg.aws->show();
744  aw_stg.hide = 0;
746 
747  timer_ok = time(&status_started) != -1;
748  LOG_STATUS("start /", str, LOG_ALWAYS_RESET_ONCE_LIMITS);
749 
750 #if defined(ARB_LOGGING)
751  aw_status_append_to_log("----------------------------");
752 #endif // ARB_LOGGING
753  awr->awar(AWAR_STATUS_TITLE)->write_string(str);
754  awr->awar(AWAR_STATUS_GAUGE)->write_string("----------------------------");
757  cmd = EOF;
758  freenull(str);
759  continue; // break while loop
760 
761  case AW_STATUS_CMD_CLOSE:
762  if (aw_stg.mode == AW_STATUS_ABORT) {
763  LOG_STATUS("user abort", "", LOG_ALWAYS);
764  }
766 #if defined(TRACE_STATUS)
767  fprintf(stderr, "received AW_STATUS_CMD_CLOSE\n"); fflush(stdout);
768 #endif // TRACE_STATUS
769  aw_stg.mode = AW_STATUS_OK;
770  aw_stg.aws->hide();
771  break;
772 
773  case AW_STATUS_CMD_TEXT:
774 #if defined(FORCE_WEIGHTED_ESTIMATION)
775  if (strcmp(str, "REQUEST_ESTIMATION") == 0) {
776  if (aw_stg.last_used_est != -1) { // suppress if not possible (yet)
777  LOG_STATUS("forced estimation", "", LOG_ALWAYS_WITH_ESTIMATION);
778  }
779  break;
780  }
781 #endif
782  LOG_STATUS(" ", str, LOG_ONCE_PER_SECOND);
783 #if defined(TRACE_STATUS)
784  fprintf(stderr, "received AW_STATUS_CMD_TEXT\n"); fflush(stdout);
785 #endif // TRACE_STATUS
786 #if defined(ARB_LOGGING)
787  aw_status_append_to_log(str);
788 #endif // ARB_LOGGING
789  awr->awar(AWAR_STATUS_TEXT)->write_string(str);
790  break;
791 
793  LOG_STATUS("start+/", str, LOG_ALWAYS_RESET_ONCE_LIMITS);
794 #if defined(TRACE_STATUS)
795  fprintf(stderr, "received AW_STATUS_CMD_NEW_TITLE\n"); fflush(stdout);
796 #endif // TRACE_STATUS
797 #if defined(ARB_LOGGING)
798  aw_status_append_to_log(str);
799 #endif // ARB_LOGGING
800  awr->awar(AWAR_STATUS_TITLE)->write_string(str);
801  break;
802 
803  case AW_STATUS_CMD_GAUGE: {
804 #if defined(TRACE_STATUS)
805  fprintf(stderr, "received AW_STATUS_CMD_GAUGE\n"); fflush(stdout);
806 #endif // TRACE_STATUS
807 
808  reassign(gauge, str);
809 
810  if (gaugeValue>0) {
811  // @@@ use double here?
812  long sec_elapsed = time(NULp)-aw_stg.last_start; // @@@ better use difftime
813  long sec_estimated = (sec_elapsed*AW_GAUGE_GRANULARITY)/gaugeValue; // guess overall time
814  int gaugePercent = gaugeValue*100/AW_GAUGE_GRANULARITY;
815 
816  char buffer[200];
817  int off = 0;
818  off += sprintf(buffer+off, "%i%% ", gaugePercent);
819  off += sprintf(buffer+off, "Elapsed: %s ", sec2disp(sec_elapsed));
820 
821  // rotate estimations
822  memmove(aw_stg.last_estimation, aw_stg.last_estimation+1, sizeof(aw_stg.last_estimation[0])*(AW_EST_BUFFER-1));
823  aw_stg.last_estimation[AW_EST_BUFFER-1] = sec_estimated;
824 
825  if (aw_stg.last_est_count == AW_EST_BUFFER) { // now we can estimate!
826  long used_estimation = 0;
827  int i;
828 
829  for (i = 0; i<AW_EST_BUFFER; ++i) {
830  used_estimation += aw_stg.last_estimation[i];
831  }
832  used_estimation /= AW_EST_BUFFER;
833 
834  if (aw_stg.last_used_est != -1) {
835  long diff = labs(aw_stg.last_used_est-used_estimation);
836  if (diff <= 1) { used_estimation = aw_stg.last_used_est; } // fake away low frequency changes
837  }
838 
839  long sec_rest = used_estimation-sec_elapsed;
840  off += sprintf(buffer+off, "Rest: %s", sec2disp(sec_rest));
841  aw_stg.last_used_est = used_estimation;
842  }
843  else {
844  if (sec_elapsed>0) aw_stg.last_est_count++;
845  off += sprintf(buffer+off, "Rest: ???");
846  }
847 
848  awr->awar(AWAR_STATUS_ELAPSED)->write_string(buffer);
849 
850 #if defined(TRACE_STATUS)
851  fprintf(stderr, "gauge=%i\n", gaugeValue); fflush(stdout);
852 #endif // TRACE_STATUS
853 
854  static int last_logged_gaugePercent = 0;
855 
856  if (gaugePercent != last_logged_gaugePercent && // do not show repeated
857  gaugePercent>0 && gaugePercent<100) // do not show begin/end gauge
858  {
859  sprintf(buffer, "%i%%", gaugePercent);
860  LOG_STATUS("progress ", buffer,
861  (gaugePercent%5) == 0
862  ? LOG_ONCE_PER_MINUTE_WITH_ESTIMATION // show 5% steps each minute
863  : LOG_ONCE_PER_15_MINUTES_WITH_ESTIMATION // show 1% steps each 15 minutes
864  );
865 
866  last_logged_gaugePercent = gaugePercent;
867  }
868  }
869  else if (gaugeValue == 0) { // restart timer
870  aw_stg.last_start = time(NULp);
871  aw_stg.last_est_count = 0;
872  aw_stg.last_used_est = -1;
873 #if defined(TRACE_STATUS)
874  fprintf(stderr, "reset status timer (gauge=0)\n"); fflush(stdout);
875 #endif // TRACE_STATUS
876  timer_ok = time(&status_started) != -1;
877  }
878  break;
879  }
881 #if defined(TRACE_STATUS)
882  fprintf(stderr, "received AW_STATUS_CMD_MESSAGE\n"); fflush(stdout);
883 #endif // TRACE_STATUS
884 #if defined(ARB_LOGGING)
885  aw_status_append_to_log(str);
886 #endif // ARB_LOGGING
887  aw_stg.awm->activate();
889  break;
890 
891  default:
892  break;
893  }
894  freenull(str);
895  cmd = aw_status_read_command(aw_stg.fd_to[0], 1, str, &gaugeValue);
896  }
897  freenull(str);
898 
899 #if defined(TRACE_STATUS_MORE)
900  fprintf(stderr, "exited while loop\n"); fflush(stdout);
901 #endif // TRACE_STATUS_MORE
902 
903  if (gauge) {
904  awr->awar(AWAR_STATUS_GAUGE)->write_string(gauge);
905  free(gauge);
906  }
908  else if (delay<0) delay = 0;
909 #if defined(TRACE_STATUS_MORE)
910  fprintf(stderr, "add aw_status_timer_listen_event with delay = %i\n", delay); fflush(stdout);
911 #endif // TRACE_STATUS_MORE
912  aw_assert(delay>0);
913  return delay;
914 }
915 
917  AW_root *awr = aww->get_root();
918  for (int i = 0; i< AW_MESSAGE_LINES; i++) freenull(aw_stg.lines[i]);
920 }
921 
923  aw_clear_message_cb(aww);
924  AW_POPDOWN(aww);
925 }
926 
927 static void save_messagebox_content_to(const char *name) {
928  const char *fullname = GB_path_in_HOME(name);
929  FILE *out = fopen(fullname, "wt");
930  GB_ERROR error = NULp;
931  if (!out) {
932  error = GB_IO_error("saving message box content to", fullname);
933  }
934  for (int i = 0; i<AW_MESSAGE_LINES; ++i) {
935  const char *line = aw_stg.lines[i];
936  if (line) {
937  fputs(line, out);
938  fputc('\n', out);
939  }
940  }
941  if (fclose(out) != 0) {
942  error = GB_IO_error("saving message box content to", fullname);
943  }
944  aw_message_if(error);
945 }
946 
947 static void aw_message_save_cb(AW_window *aww) {
948  const char *name = "arb-message-box.txt";
949  char *msg = GBS_global_string_copy("Saving content to ~/%s", name);
950 
951  aw_insert_message_in_tmp_message(aww->get_root(), "Saving properties.");
952  AW_save_properties(aww);
953 
956 
957  free(msg);
958 }
959 
960 static void create_status_awars(AW_root *aw_root) {
961  aw_root->awar_string(AWAR_STATUS_TITLE, "------------------------------------");
962  aw_root->awar_string(AWAR_STATUS_TEXT, "");
963  aw_root->awar_string(AWAR_STATUS_GAUGE, "------------------------------------");
964  aw_root->awar_string(AWAR_STATUS_ELAPSED, "");
965  aw_root->awar_string(AWAR_ERROR_MESSAGES, "");
966 }
967 
969  // fork status window.
970  // Note: call this function once as early as possible
971 
972  aw_assert(aw_stg.pid == 0); // do not init status twice!
973  aw_assert(!AW_root::SINGLETON); // aw_initstatus has to be called before constructing AW_root
974  aw_assert(GB_open_DBs() == 0); // aw_initstatus has to be called before opening the first ARB-DB
975 
976  int error = pipe(aw_stg.fd_to);
977  if (error) GBK_terminate("Cannot create socketpair [1]");
978  error = pipe(aw_stg.fd_from);
979  if (error) GBK_terminate("Cannot create socketpair [2]");
980 
981  aw_stg.pid = getpid();
982  GB_install_pid(1);
983  pid_t clientid = fork();
984 
985  if (clientid) { // i am the father
986 #if defined(TRACE_STATUS)
987  fprintf(stderr, "Forked status! (i am the father)\n"); fflush(stderr);
988 #endif // TRACE_STATUS
989  return;
990  }
991  else {
992  GB_install_pid(1);
993 
994 #if defined(TRACE_STATUS)
995  fprintf(stderr, "Forked status! (i am the child)\n"); fflush(stderr);
996 #endif // TRACE_STATUS
997 
998  aw_stg.is_child = true; // mark as child
999 
1000  GB_shell shell;
1001  AW_root *aw_root = new AW_root("status.arb", "ARB_STATUS", true, new NullTracker); // uses_pix_res("icons/ARB_STATUS.xpm"); see ../SOURCE_TOOLS/check_resources.pl@uses_pix_res
1002  create_status_awars(aw_root);
1003 
1004  {
1005  // create progress window
1006  AW_window_simple *aws = new AW_window_simple;
1007  aws->init(aw_root, "PROGRESS_BAR", "ARB PROGRESS");
1008  aws->load_xfig("status.fig");
1009 
1010  aws->button_length(AW_GAUGE_SIZE+4);
1011  aws->at("Titel");
1012  aws->create_button(NULp, AWAR_STATUS_TITLE);
1013 
1014  aws->at("Text");
1015  aws->create_button(NULp, AWAR_STATUS_TEXT);
1016 
1017  aws->at("Gauge");
1018  aws->create_button(NULp, AWAR_STATUS_GAUGE);
1019 
1020  aws->at("elapsed");
1021  aws->create_button(NULp, AWAR_STATUS_ELAPSED);
1022 
1023  aws->at("Hide");
1024  aws->callback(aw_status_hide);
1025  aws->create_button("HIDE", "Hide", "h");
1026 
1027  aws->at("Kill");
1028  aws->callback(aw_status_kill);
1029  aws->create_button("ABORT", "Abort", "k");
1030 
1031  aw_stg.hide = 0;
1032  aw_stg.aws = aws;
1033  }
1034 
1035  {
1036  // create message box
1037  AW_window_simple *awm = new AW_window_simple;
1038  awm->init(aw_root, "MESSAGE_BOX", "MESSAGE BOX");
1039  awm->load_xfig("message.fig");
1040 
1041  awm->button_length(8);
1042  awm->auto_space(5, 5);
1043 
1044  awm->at("Message");
1045  awm->create_text_field(AWAR_ERROR_MESSAGES, 10, 2);
1046 
1047  awm->at("buttons");
1048  awm->callback(AW_POPDOWN);
1049  awm->create_button("HIDE", "Hide", "h");
1050 
1051  awm->callback(aw_message_save_cb);
1052  awm->create_button("SAVE_PROPS", "Save", "S");
1053 
1054  awm->callback(aw_clear_message_cb);
1055  awm->create_button("CLEAR", "Clear", "C");
1056 
1057  awm->callback(aw_clear_and_hide_message_cb);
1058  awm->create_button("HIDE_CLEAR", "Ok", "O");
1059 
1060  aw_stg.awm = awm;
1061  }
1062 
1063 #if defined(TRACE_STATUS)
1064  fprintf(stderr, "Created status window!\n"); fflush(stderr);
1065 #endif // TRACE_STATUS
1066 
1067  aw_status_wait_for_open(aw_stg.fd_to[0]);
1068 
1069  // install callback
1070  aw_root->add_timed_callback_never_disabled(30, makeTimedCallback(aw_status_timer_listen_event)); // use short delay for first callback
1071 
1072  // do NOT AWT_install_cb_guards here!
1073  aw_root->main_loop(); // never returns
1074  }
1075 }
1076 
1077 static void status_write_cmd_and_text(StatusCommand cmd, const char *text, int textlen) {
1078  aw_status_write(aw_stg.fd_to[1], cmd);
1079  safe_write(aw_stg.fd_to[1], text, textlen+1);
1080 }
1081 static void status_write_cmd_and_text(StatusCommand cmd, const char *text) {
1082  if (!text) text = "";
1083  status_write_cmd_and_text(cmd, text, strlen(text));
1084 }
1085 
1086 void aw_openstatus(const char *title) {
1087  aw_stg.mode = AW_STATUS_OK;
1088  if (!aw_stg.status_initialized) {
1089  aw_stg.status_initialized = true;
1091  }
1093 }
1094 
1097 }
1098 
1099 void aw_status_title(const char *new_title) {
1101 }
1102 void aw_status_subtitle(const char *text) {
1104 }
1105 
1106 void aw_status_gauge(double gauge) {
1107  static int last_val = -1;
1108  int val = (int)(gauge*AW_GAUGE_GRANULARITY);
1109 
1110  if (val != last_val) {
1111  if (val>0 || gauge == 0.0) { // only write 0 if gauge really is 0 (cause 0 resets the timer)
1112  aw_assert(gauge <= 1.0); // please fix the gauge calculation in caller!
1114  safe_write(aw_stg.fd_to[1], (char*)&val, sizeof(int));
1115  }
1116  last_val = val;
1117  }
1118 }
1119 
1121  if (aw_stg.mode != AW_STATUS_ABORT) {
1122  // check if user has pressed the 'Abort' button
1123  static ARB_timestamp last_check;
1124  if (last_check.sec_since() >= 1) { // perform check not more often than every second!
1125  char *str = NULp;
1126  for (int cmd = 0; cmd != EOF; cmd = aw_status_read_command(aw_stg.fd_from[0], 1, str)) {
1127  freenull(str);
1128  if (cmd == AW_STATUS_ABORT) aw_stg.mode = AW_STATUS_ABORT;
1129  }
1130  last_check.update();
1131  }
1132  }
1133  return aw_stg.mode;
1134 }
1135 
1136 // -------------------
1137 // aw_message
1138 
1140  aw_stg.local_message = 1;
1141 }
1142 
1143 
1144 void aw_message(const char *msg) {
1145  aw_assert(!RUNNING_TEST()); // aw_message hangs when called from nightly builds
1146 #if defined(DEBUG)
1147  printf("aw_message: '%s'\n", msg);
1148 #endif // DEBUG
1149  if (aw_stg.local_message) {
1151  }
1152  else {
1153  if (!aw_stg.status_initialized) {
1154  aw_stg.status_initialized = true;
1156  }
1158  }
1159 }
1160 
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:505
#define arb_assert(cond)
Definition: arb_assert.h:245
#define FD_SET_TYPE
Definition: AW_status.cxx:31
#define AW_STATUS_PIPE_CHECK_DELAY
Definition: AW_status.cxx:40
string result
static ssize_t safe_write(int fd, const char *buf, int count)
Definition: AW_status.cxx:167
int fd_from[2]
Definition: AW_status.cxx:84
static void status_write_cmd_and_text(StatusCommand cmd, const char *text, int textlen)
Definition: AW_status.cxx:1077
#define AW_STATUS_HIDE_DELAY
Definition: AW_status.cxx:39
static aw_stg_struct aw_stg
Definition: AW_status.cxx:106
void aw_openstatus(const char *title)
Definition: AW_status.cxx:1086
#define AWAR_STATUS_GAUGE
Definition: AW_status.cxx:45
#define AW_GAUGE_SIZE
Definition: AW_status.cxx:34
#define AW_GAUGE_GRANULARITY
Definition: AW_status.cxx:35
#define MAX_SEC_WIDTH_STR
Definition: AW_status.cxx:538
#define AWAR_STATUS_TITLE
Definition: AW_status.cxx:43
long
Definition: AW_awar.cxx:152
static void aw_status_hide(AW_window *aws)
Definition: AW_status.cxx:385
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:284
void aw_status_title(const char *new_title)
Definition: AW_status.cxx:1099
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:202
const char * title
Definition: readseq.c:22
static int aw_status_read_byte(int fd, int poll_flag)
Definition: AW_status.cxx:231
STL namespace.
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
void add_timed_callback_never_disabled(int ms, const TimedCallback &tcb)
Definition: AW_root.cxx:541
int GB_open_DBs(void)
Definition: arbdb.cxx:522
void cat(const char *from)
Definition: arb_strbuf.h:158
void add_timed_callback(int ms, const TimedCallback &tcb)
Definition: AW_root.cxx:538
static void aw_status_write(int fd, int cmd)
Definition: AW_status.cxx:226
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
bool need_refresh
Definition: AW_status.cxx:96
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
long sec_since() const
Definition: arb_sleep.h:117
void activate()
Definition: aw_window.hxx:356
static void save_messagebox_content_to(const char *name)
Definition: AW_status.cxx:927
void LOG_STATUS(const char *txt1, const char *txt2, LogLevel level)
Definition: AW_status.cxx:625
void aw_closestatus()
Definition: AW_status.cxx:1095
StatusCommand
Definition: AW_status.cxx:66
void update()
Definition: arb_sleep.h:109
AW_window * aws
Definition: AW_status.cxx:92
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
static AW_root * SINGLETON
Definition: aw_root.hxx:102
void show()
Definition: AW_window.cxx:1670
static int diff(int v1, int v2, int v3, int v4, int st, int en)
Definition: ClustalV.cxx:534
void aw_clear_message_cb(AW_window *aww)
Definition: AW_status.cxx:916
#define AWAR_STATUS_TEXT
Definition: AW_status.cxx:44
fflush(stdout)
static unsigned aw_status_timer_event(AW_root *awr)
Definition: AW_status.cxx:402
static void mark_pipe_broken(int err_no)
Definition: AW_status.cxx:140
static unsigned aw_status_timer_hide_event(AW_root *)
Definition: AW_status.cxx:377
static void aw_message_save_cb(AW_window *aww)
Definition: AW_status.cxx:947
GB_ERROR GB_install_pid(int mode)
Definition: adcomm.cxx:1957
#define AW_STATUS_KILL_DELAY
Definition: AW_status.cxx:37
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
const char * sec2disp(long seconds)
Definition: AW_status.cxx:542
bool status_initialized
Definition: AW_status.cxx:94
#define MAX_SEC_WIDTH
Definition: AW_status.cxx:537
static GB_CSTR GB_getenvHOME()
Definition: adsocket.cxx:563
static bool timer_ok
Definition: AW_status.cxx:607
static void aw_status_kill(AW_window *aws)
Definition: AW_status.cxx:446
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:450
const char * readableTime(const time_t &t)
Definition: AW_status.cxx:618
#define AW_STATUS_LISTEN_DELAY
Definition: AW_status.cxx:38
void AW_save_properties(AW_window *aw)
Definition: AW_preset.cxx:1452
#define aw_assert(bed)
Definition: aw_position.hxx:29
LogLevel
Definition: AW_status.cxx:609
long last_estimation[AW_EST_BUFFER]
Definition: AW_status.cxx:102
void message(char *errortext)
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define WRITE_TIMEOUT
Definition: AW_status.cxx:137
fputc('\n', stderr)
#define AW_EST_BUFFER
Definition: AW_status.cxx:80
virtual void init(AW_root *root, const char *wid, const char *windowname, int width, int height)
void aw_status_subtitle(const char *text)
Definition: AW_status.cxx:1102
long last_est_count
Definition: AW_status.cxx:101
#define plural(unit)
Definition: AW_status.cxx:540
char * read_string() const
Definition: AW_awar.cxx:198
static void aw_insert_message_in_tmp_message_delayed(const char *message)
Definition: AW_status.cxx:485
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
#define RUNNING_TEST()
Definition: arb_assert.h:278
int fd_to[2]
Definition: AW_status.cxx:83
time_t last_start
Definition: AW_status.cxx:100
void nl()
Definition: test_unit.h:404
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
static AW_window_menu_modes_opengl * awm
#define POLL_TIMEOUT
Definition: AW_status.cxx:132
time_t last_refresh_time
Definition: AW_status.cxx:97
static time_t status_started
Definition: AW_status.cxx:606
bool aw_ask_sure(const char *unique_id, const char *msg)
void main_loop()
Definition: AW_root.cxx:625
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
fputs(TRACE_PREFIX, stderr)
time_t last_message_time
Definition: AW_status.cxx:98
static void copy(double **i, double **j)
Definition: trnsprob.cxx:32
static void create_status_awars(AW_root *aw_root)
Definition: AW_status.cxx:960
static int aw_status_read_int(int fd, int poll_flag)
Definition: AW_status.cxx:258
#define AWAR_ERROR_MESSAGES
static unsigned aw_status_timer_listen_event(AW_root *awr)
Definition: AW_status.cxx:709
GB_CSTR GB_path_in_HOME(const char *relative_path)
Definition: adsocket.cxx:1163
bool aw_status_aborted()
Definition: AW_status.cxx:1120
void aw_message(const char *msg)
Definition: AW_status.cxx:1144
void hide()
Definition: AW_window.cxx:1822
void aw_status_gauge(double gauge)
Definition: AW_status.cxx:1106
AW_root * get_root()
Definition: aw_window.hxx:350
static void aw_status_wait_for_open(int fd)
Definition: AW_status.cxx:343
static int line
Definition: arb_a2ps.c:296
#define NULp
Definition: cxxforward.h:114
static void aw_status_check_pipe()
Definition: AW_status.cxx:334
static void aw_refresh_tmp_message_display(AW_root *awr)
Definition: AW_status.cxx:469
GB_ERROR write_string(const char *aw_string)
#define AW_MESSAGE_LINES
Definition: AW_status.cxx:48
const char * get_data() const
Definition: arb_strbuf.h:70
static void aw_clear_and_hide_message_cb(AW_window *aww)
Definition: AW_status.cxx:922
static void aw_insert_message_in_tmp_message(AW_root *awr, const char *message)
Definition: AW_status.cxx:532
AW_window * awm
Definition: AW_status.cxx:93
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
long last_used_est
Definition: AW_status.cxx:103
#define AWAR_STATUS_ELAPSED
Definition: AW_status.cxx:46
void aw_initstatus()
Definition: AW_status.cxx:968
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
static int aw_status_read_command(int fd, int poll_flag, char *&str, int *gaugePtr=NULp)
Definition: AW_status.cxx:289
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:193
void aw_set_local_message()
Definition: AW_status.cxx:1139
char * lines[AW_MESSAGE_LINES]
Definition: AW_status.cxx:95
void put(char c)
Definition: arb_strbuf.h:138