2
3
4
5
6
7
8
9
10
11
12
13
16
17
33int win_new(
int,
int,
int,
int,
char *,
int);
42void abend(
int,
char *);
64int mb_to_cc(cchar_t *,
char *, attr_t,
int,
int *,
int);
71int xwgetch(WINDOW *, Chyron *,
int);
80
81
83 {0, 0, 0}, {128, 0, 0}, {0, 128, 0}, {128, 128, 0},
84 {0, 0, 128}, {128, 0, 128}, {0, 128, 128}, {192, 192, 192},
85 {128, 128, 128}, {255, 0, 0}, {0, 255, 0}, {255, 255, 0},
86 {0, 0, 255}, {255, 0, 255}, {0, 255, 255}, {255, 255, 255}};
88
89
90
92 "black",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
93 "white",
"orange",
"bg",
"abg",
"bblack",
"bred",
"bgreen",
94 "byellow",
"bblue",
"bcyan",
"bmagenta",
"bwhite",
"borange",
""};
157
158
159
160
161
165
166
169
170
171
172
173
174
175
176
177
178
179
180
181
182
184 Chyron *chyron = (Chyron *)calloc(1,
sizeof(Chyron));
190 chyron
->key[i] = (ChyronKey *)calloc(1,
sizeof(ChyronKey));
194
195
196
197
205 free(chyron
->key[i]);
213
214
215
216
224
225
226
227
228
229
230
231
232
233
234
235
236
254
255
256
257
260
261
262
263
264
265
266
267
302 wmove(win, line, col);
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321int mb_to_cc(cchar_t *cmplx_buf,
char *str, attr_t attr,
int cpx,
int *pos,
326 wchar_t wstr[2] = {L'\0', L'\0'};
328 memset(&mbstate, 0,
sizeof(mbstate));
330 if (*pos >= maxlen - 1)
332 while (str[i] !=
'\0') {
334 len = mbrtowc(wstr, s, MB_CUR_MAX, &mbstate);
341 if (*pos >= maxlen - 1)
343 if (setcchar(&cc, wstr, attr, cpx,
nullptr) != ERR) {
344 if (len > 0 && (*pos + len) <
MAXLEN - 1)
345 cmplx_buf[(*pos)++] = cc;
351 setcchar(&cc, wstr, attr, cpx,
nullptr);
352 cmplx_buf[*pos] = cc;
356
357
358
359
360
361
362
363
364
365
366
367
368
377
378
379
380
381
382
383
384
385
387 cchar_t *cmplx_buf = (cchar_t *)calloc(
MAXLEN,
sizeof(cchar_t));
390 attr_t attr = WA_NORMAL;
395 memset(&mbstate, 0,
sizeof(mbstate));
396 len = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate);
401 if (setcchar(&cc, &wc, attr, cpx,
nullptr) != ERR) {
402 if (len > 0 && (j + len) <
MAXLEN - 1) {
410
411
412
413
414
415
416
417
418
419
420
421
428 strerror_r(errno, tmp_str,
MAXLEN - 1);
431 fprintf(stderr,
"%s\n", tmp_str);
437 strerror_r(errno, tmp_str,
MAXLEN - 1);
440 fprintf(stderr,
"%s\n", tmp_str);
447 strerror_r(errno, tmp_str,
MAXLEN - 1);
450 fprintf(stderr,
"%s\n", tmp_str);
457 abend(-1
, "Terminal color support required");
460 if (!can_change_color()) {
462 fprintf(stderr,
"Terminal cannot change colors\n");
463 fprintf(stderr,
"Check TERM environment variable\n");
464 fprintf(stderr,
"Check terminfo for missing \"ccc\"\n");
490 keypad(stdscr, true);
491 idlok(stdscr, false);
492 idcok(stdscr, false);
496 immedok(stdscr, true);
502
503
504
506
507
508
509
513 extended_pair_content(i, &pfg, &pbg);
514 if (pfg == fg && pbg == bg)
517 if (i >= COLOR_PAIRS) {
523 return (EXIT_FAILURE);
525 if (i < COLOR_PAIRS) {
526 rc = init_extended_pair(i, fg, bg);
535
536
537
538
539
540
545 rgb
->r = (rgb
->r * 1000) / 255;
546 rgb
->g = (rgb
->g * 1000) / 255;
547 rgb
->b = (rgb
->b * 1000) / 255;
548 for (i = 0; i <
clr_cnt; i++) {
549 extended_color_content(i, &r, &g, &b);
550 if (rgb
->r == r && rgb
->g == g && rgb
->b == b) {
555 init_extended_color(i, rgb
->r, rgb
->g, rgb
->b);
562
563
564
565
566
567
568
575 return ((rgb
->r - 8) / 10) + 231;
577 int r_index = (rgb
->r < 45) ? 0 : (rgb
->r - 60) / 40 + 1;
578 int g_index = (rgb
->g < 45) ? 0 : (rgb
->g - 60) / 40 + 1;
579 int b_index = (rgb
->b < 45) ? 0 : (rgb
->b - 60) / 40 + 1;
580 return 16 + (36 * r_index) + (6 * g_index) + b_index;
584
585
586
587
588
589
592
593
599 rgb
.r = rgb
.g = rgb
.b = 0;
604 }
else if (idx >= 16 && idx <= 231) {
606 rgb
.r = (idx / 36) % 6 * 51;
607 rgb
.g = (idx / 6) % 6 * 51;
608 rgb
.b = (idx % 6) * 51;
609 }
else if (idx >= 232 && idx <= 255) {
610 int gray = (idx - 232) * 11;
611 rgb
.r = rgb
.g = rgb
.b = gray;
617
618
619
620
621
622
623
641
642
643
644
645
646
647
648
649
650
700
701
702
703
704
705
706
707
717 rgb
.r = (rgb
.r * 1000) / 255;
718 rgb
.g = (rgb
.g * 1000) / 255;
719 rgb
.b = (rgb
.b * 1000) / 255;
720 init_extended_color(idx, rgb
.r, rgb
.g, rgb
.b);
723
724
727 sscanf(s,
"#%02x%02x%02x", &rgb
.r, &rgb
.g, &rgb
.b);
731
732
733
734
735
736
737
762
763
764
765
769 setcchar(&cc, &wc, WA_NORMAL, cp,
nullptr);
773
774
775
776
777
778
779
780
781
782
783int win_new(
int wlines,
int wcols,
int wbegy,
int wbegx,
char *wtitle,
788 if (wbegy != 0 || wbegx != 0 || wlines < LINES - 2 ||
796 immedok(win_box[win_ptr], true);
805 int s = strlen(wtitle);
819 immedok(win_box[win_ptr], true);
824 if (!(flag &
W_BOX)) {
831 immedok(win_win[win_ptr], true);
843
844
845
846
847
848
849
850
858 if (title !=
nullptr && *title !=
'\0') {
867 int s = strlen(title);
882 immedok(win_win[win_ptr], true);
886
887
888
889
890
896
897
898
899
900
901
920 for (i = 0; i <
win_ptr; i++) {
932
933
934
935
936
937
941 wnoutrefresh(stdscr);
943 for (i = 0; i <=
win_ptr; i++) {
953
954
955
956
957
958
959
967 mvwaddnwstr(box, 0, 0, &
bw_tl, 1);
968 for (x = 1; x < maxx; x++)
969 waddnwstr(box, &
bw_ho, 1);
970 waddnwstr(box, &
bw_tr, 1);
973 for (y = 1; y < maxy; y++) {
974 mvwaddnwstr(box, y, 0, &
bw_ve, 1);
975 mvwaddnwstr(box, y, maxx, &
bw_ve, 1);
977 mvwaddnwstr(box, maxy, 0, &
bw_bl, 1);
978 for (x = 1; x < maxx; x++)
979 waddnwstr(box, &
bw_ho, 1);
980 waddnwstr(box, &
bw_br, 1);
984
985
988
989
990
991
992
993
994int answer_yn(
char *em0,
char *em1,
char *em2,
char *em3) {
996 int line, pos, em_l, em0_l, em1_l, em2_l, em3_l;
1000 fprintf(stderr,
"\n\n%s\n%s\n%s\n%s\n\n", em0, em1, em2, em3);
1014 em_l =
max(em0_l, em1_l);
1015 em_l =
max(em_l, em2_l);
1016 em_l =
max(em_l, em3_l);
1017 em_l =
max(em_l, chyron
->l);
1018 em_l =
min(em_l, COLS - 4);
1020 pos = ((COLS - em_l) - 4) / 2;
1021 line = (LINES - 6) / 2;
1025 5
, em_l + 2
, line
, pos
, title
, 0
);
1030 mvwaddstr(error_win, 0, 1, em0);
1031 mvwaddstr(error_win, 1, 1, em1);
1032 mvwaddstr(error_win, 2, 1, em2);
1033 mvwaddstr(error_win, 3, 1, em3);
1048
1049
1050
1051
1052
1053
1056 int line, pos, em_l, em0_l, em1_l, em2_l, em3_l;
1060 fprintf(stderr,
"\n\n%s\n%s\n%s\n%s\n\n", em0, em1, em2, em3);
1074 em_l =
max(em0_l, em1_l);
1075 em_l =
max(em_l, em2_l);
1076 em_l =
max(em_l, em3_l);
1077 em_l =
max(em_l, chyron
->l);
1078 em_l =
min(em_l, COLS - 4);
1080 pos = ((COLS - em_l) - 4) / 2;
1081 line = (LINES - 6) / 2;
1085 5
, em_l + 2
, line
, pos
, title
, 0
);
1090 mvwaddstr(error_win, 0, 1, em0);
1091 mvwaddstr(error_win, 1, 1, em1);
1092 mvwaddstr(error_win, 2, 1, em2);
1093 mvwaddstr(error_win, 3, 1, em3);
1107
1108
1109
1112 int emsg_max_len = 80;
1117 bool f_xwgetch = true;
1118 if (emsg_str[0] ==
'␛' && emsg_str[1] ==
'w') {
1124 fprintf(stderr,
"\n%s\n", emsg);
1132 len =
max(strlen(title), strlen(emsg));
1133 len =
max(len, chyron
->l);
1135 pos = (COLS - len - 4) / 2;
1136 line = (LINES - 4) / 2;
1140 4
, line
, line
, pos
, title
, 0
);
1145 mvwaddstr(error_win, 0, 1, emsg);
1153 cmd_key = KEY_F(10);
1159
1160
1168
1169
1170
1171
1173 char wm1[] =
"Seconds remaining:";
1179 fprintf(stderr,
"\n%s\n", title);
1180 fprintf(stderr,
"%s\n", wm1);
1183 len =
max(strlen(title), strlen(wm1));
1184 len =
max(len, chyron
->l);
1186 col = (COLS - len - 4) / 2;
1187 line = (LINES - 4) / 2;
1190 4
, line
, line
, col
, title
, 0
);
1194 mvwaddstr(wait_win, 0, 1, wm1);
1196 wmove(wait_win, 1, chyron
->l);
1200
1201
1202
1209
1210
1211
1212
1213
1214
1218 mvwaddstr(wait_win, 0, 21, time_str);
1220 wmove(wait_win, 1, chyron
->l);
1227 WINDOW *action_disposition_win;
1230 fprintf(stderr,
"\n%s\n", title);
1231 fprintf(stderr,
"%s\n", action_str);
1237 len =
max(strlen(title), strlen(action_str));
1238 col = (COLS - len - 4) / 2;
1239 line = (LINES - 4) / 2;
1242 line
, line
, col
, title
, 0
);
1246 mvwaddstr(action_disposition_win, 0, 1, action_str);
1248 wmove(action_disposition_win, 1, chyron
->l);
1256
1257
1258
1259
1260
1261
1271 if (*s ==
'\0' || *s ==
'\n')
1276 mvwaddstr(w, y, x, tmp_str);
1279
1280
1281
1297
1298
1299
1303 for (i = 0, col = 0; i < 16; i++, col++) {
1305 fprintf(stderr,
" ");
1309 fprintf(stderr,
"\n");
1311 fprintf(stderr,
" ");
1314 fprintf(stderr,
"\n");
1317
1318
1319
1321 fprintf(stderr,
"ERROR: %s code: %d\n", s, ec);
1322 fprintf(stderr,
"Press a key to continue");
1324 fprintf(stderr,
"\n");
1328
1329
1330
1335 fprintf(stderr,
"\n\nABEND: %s (code: %d)\n", s, ec);
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1362 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON4_PRESSED |
1365 event.y = event.x = -1;
1369 struct termios raw_tioctl;
1375 halfdelay(
min(255,
max(0, n * 10)));
1376 tcflush(2, TCIFLUSH);
1383 if (c ==
'q' || c ==
'Q' || c == KEY_F(9))
1386 if (n > 0 && c == ERR) {
1392 if (c == KEY_MOUSE) {
1393 if (getmouse(&event) != OK) {
1397 if (event.bstate & BUTTON4_PRESSED) {
1400 }
else if (event.bstate & BUTTON5_PRESSED) {
1404 if (event.bstate & BUTTON1_CLICKED ||
1405 event.bstate & BUTTON1_DOUBLE_CLICKED) {
1406 if (!wenclose(win, event.y, event.x)) {
1410 wmouse_trafo(win, &event.y, &event.x, false);
1411 if (event.y < 0 || event.x < 0 || event.x >= getmaxx(win) ||
1412 event.y >= getmaxy(win)) {
1418 if (chyron && event.y == getmaxy(win) - 1) {
1434 Chyron *wait_chyron;
1436 int remaining = timeout;
1439 rc = waitpid(pid, &status, WNOHANG);
1451 while (rc == 0 && remaining > 0 &&
cmd_key != KEY_F(9)) {
volatile sig_atomic_t sig_received
bool handle_signal(sig_atomic_t)
struct termios shell_tioctl curses_tioctl
#define CHYRON_KEY_MAXLEN
#define min(x, y)
min macro evaluates two expressions, returning least result
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
bool waitpid_with_timeout(pid_t pid, int timeout)
bool action_disposition(char *title, char *action_str)
void display_chyron(WINDOW *win, Chyron *chyron, int line, int col)
cchar_t CCC_REVERSE_HIGHLIGHT
char const colors_text[][10]
void set_chyron_key(Chyron *, int, char *, int)
bool open_curses(SIO *)
Initialize NCurses and color settings.
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
void restore_wins()
Restore all windows after a screen resize.
int win_new(int, int, int, int, char *, int)
Create a new window with optional box and title.
void win_init_attrs()
Initialize window attributes.
WINDOW * win_del()
Delete the current window and its associated box window.
void mvwaddstr_fill(WINDOW *, int, int, char *, int)
For lines shorter than their display area, fill the rest with spaces.
void cbox(WINDOW *)
Draw a box around the specified window.
void win_resize(int, int, char *)
Resize the current window and its box, and update the title.
void destroy_curses()
Gracefully shut down NCurses and restore terminal settings.
void win_redraw(WINDOW *)
Redraw the specified window.
bool is_set_chyron_key(Chyron *, int)
Check if function key label is set.
Chyron * destroy_chyron(Chyron *chyron)
Destroy Chyron structure.
int get_chyron_key(Chyron *, int)
Get keycode from chyron.
void set_chyron_key_cp(Chyron *, int, char *, int, int)
Set chyron key.
void compile_chyron(Chyron *)
construct the chyron string from the chyron structure
void unset_chyron_key(Chyron *, int)
Unset chyron key.
int mb_to_cc(cchar_t *, char *, attr_t, int, int *, int)
Convert multibyte string to complex character array.
Chyron * new_chyron()
Create and initialize Chyron structure.
cchar_t * mk_cmplx_buf(const char *s)
Create complex character buffer from multibyte string.
cchar_t mkccc(int)
Create a cchar_t with the specified color pair index.
RGB xterm256_idx_to_rgb(int)
Convert XTerm 256 color index to RGB color.
int clr_name_to_idx(char *)
Get color index from color name.
void list_colors()
list colors to stderr
int rgb_to_curses_clr(RGB *)
Get color index for RGB color.
void init_hex_clr(int, char *)
Initialize extended ncurses color from HTML style hex string.
bool init_clr_palette(SIO *)
Initialize color palette based on SIO settings.
RGB hex_clr_str_to_rgb(char *)
Convert six-digit HTML style hex color code to RGB struct.
void apply_gamma(RGB *)
Apply gamma correction to RGB color.
int rgb_to_xterm256_idx(RGB *)
Convert RGB color to XTerm 256 color index.
int get_clr_pair(int fg, int bg)
Get color pair index for foreground and background colors.
bool wait_destroy(Chyron *)
Destroy the waiting message window and chyron.
int nf_error(int, char *)
Display error message and wait for key press.
int wait_continue(WINDOW *, Chyron *, int)
Update the waiting message with remaining time and check for user input.
int answer_yn(char *em0, char *em1, char *em2, char *em3)
Accept a single letter answer.
WINDOW * wait_mk_win(Chyron *, char *)
Display a popup waiting message.
int Perror(char *)
Display a simple error message window or print to stderr.
int display_error(char *em0, char *em1, char *em2, char *em3)
Display an error message window or print to stderr.
void abend(int, char *)
Abnormal program termination.
Chyron * wait_mk_chyron()
Create a Chyron struct for the waiting message.
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
bool str_to_lower(char *)
Converts a string to lowercase.
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
char di_getch()
sget single character from terminal in raw mode
bool restore_curses_tioctl()
restore_curses_tioctl() - restore curses terminal settings
bool mk_raw_tioctl(struct termios *)
mk_raw_tioctl() - set terminal to raw mode
bool restore_shell_tioctl()
restore_shell_tioctl() - restore shell terminal settings
void sig_dfl_mode()
Set signal handlers to default behavior.
char text[CHYRON_KEY_MAXLEN]
cchar_t cmplx_buf[MAXLEN]
ChyronKey * key[CHYRON_KEYS]
char ln_bg_clr_x[COLOR_LEN]