/* * Copyright 2000, 2001, 2002, 2004, 2005 by Paul Mattes. * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * c3270 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the file LICENSE for more details. */ /* * screen.c * A curses-based 3270 Terminal Emulator * Screen drawing */ #include "globals.h" #include #include "appres.h" #include "3270ds.h" #include "resources.h" #include "ctlr.h" #include "actionsc.h" #include "ctlrc.h" #include "hostc.h" #include "keymapc.h" #include "kybdc.h" #include "macrosc.h" #include "screenc.h" #include "tablesc.h" #include "trace_dsc.h" #include "utilc.h" #include "widec.h" #include "xioc.h" #undef COLS extern int cCOLS; #undef COLOR_BLACK #undef COLOR_RED #undef COLOR_GREEN #undef COLOR_YELLOW #undef COLOR_BLUE #undef COLOR_WHITE #if defined(HAVE_NCURSES_H) /*[*/ #include #else /*][*/ #include #endif /*]*/ static int cp[8][8][2]; static int cmap[16] = { COLOR_BLACK, /* neutral black */ COLOR_BLUE, /* blue */ COLOR_RED, /* red */ COLOR_MAGENTA, /* pink */ COLOR_GREEN, /* green */ COLOR_CYAN, /* turquoise */ COLOR_YELLOW, /* yellow */ COLOR_WHITE, /* neutral white */ COLOR_BLACK, /* black */ COLOR_BLUE, /* deep blue */ COLOR_YELLOW, /* orange */ COLOR_BLUE, /* deep blue */ COLOR_GREEN, /* pale green */ COLOR_CYAN, /* pale turquoise */ COLOR_BLACK, /* grey */ COLOR_WHITE /* white */ }; static int defattr = A_NORMAL; static unsigned long input_id; Boolean escaped = True; enum ts { TS_AUTO, TS_ON, TS_OFF }; enum ts me_mode = TS_AUTO; enum ts ab_mode = TS_AUTO; #if defined(C3270_80_132) /*[*/ struct screen_spec { int rows, cols; char *mode_switch; } screen_spec; struct screen_spec altscreen_spec, defscreen_spec; static SCREEN *def_screen = NULL, *alt_screen = NULL; static SCREEN *cur_screen = NULL; static void parse_screen_spec(const char *str, struct screen_spec *spec); #endif /*]*/ static int status_row = 0; /* Row to display the status line on */ static int status_skip = 0; /* Row to blank above the status line */ static Boolean curses_alt = False; static void kybd_input(void); static void kybd_input2(int k, Boolean derived); static void draw_oia(void); static void status_connect(Boolean ignored); static void status_3270_mode(Boolean ignored); static void status_printer(Boolean on); static int get_color_pair(int fg, int bg); static int color_from_fa(unsigned char); static void screen_init2(void); static void set_status_row(int screen_rows, int emulator_rows); static Boolean ts_value(const char *s, enum ts *tsp); static int linedraw_to_acs(unsigned char c); static int apl_to_acs(unsigned char c); /* Initialize the screen. */ void screen_init(void) { int want_ov_rows = ov_rows; int want_ov_cols = ov_cols; Boolean oversize = False; #if !defined(C3270_80_132) /*[*/ /* Disallow altscreen/defscreen. */ if ((appres.altscreen != CN) || (appres.defscreen != CN)) { (void) fprintf(stderr, "altscreen/defscreen not supported\n"); exit(1); } /* Initialize curses. */ if (initscr() == NULL) { (void) fprintf(stderr, "Can't initialize terminal.\n"); exit(1); } #else /*][*/ /* Parse altscreen/defscreen. */ if ((appres.altscreen != CN) ^ (appres.defscreen != CN)) { (void) fprintf(stderr, "Must specify both altscreen and defscreen\n"); exit(1); } if (appres.altscreen != CN) { parse_screen_spec(appres.altscreen, &altscreen_spec); if (altscreen_spec.rows < 27 || altscreen_spec.cols < 132) { (void) fprintf(stderr, "Rows and/or cols too small on " "alternate screen (mininum 27x132)\n"); exit(1); } parse_screen_spec(appres.defscreen, &defscreen_spec); if (defscreen_spec.rows < 24 || defscreen_spec.cols < 80) { (void) fprintf(stderr, "Rows and/or cols too small on " "default screen (mininum 24x80)\n"); exit(1); } } /* Set up ncurses, and see if it's within bounds. */ if (appres.defscreen != CN) { char nbuf[64]; (void) sprintf(nbuf, "COLUMNS=%d", defscreen_spec.cols); putenv(NewString(nbuf)); (void) sprintf(nbuf, "LINES=%d", defscreen_spec.rows); putenv(NewString(nbuf)); def_screen = newterm(NULL, stdout, stdin); if (def_screen == NULL) { (void) fprintf(stderr, "Can't initialize %dx%d defscreen terminal.\n", defscreen_spec.rows, defscreen_spec.cols); exit(1); } (void) write(1, defscreen_spec.mode_switch, strlen(defscreen_spec.mode_switch)); } if (appres.altscreen) { char nbuf[64]; (void) sprintf(nbuf, "COLUMNS=%d", altscreen_spec.cols); putenv(NewString(nbuf)); (void) sprintf(nbuf, "LINES=%d", altscreen_spec.rows); putenv(NewString(nbuf)); } alt_screen = newterm(NULL, stdout, stdin); if (alt_screen == NULL) { (void) fprintf(stderr, "Can't initialize terminal.\n"); exit(1); } if (appres.altscreen) { set_term(alt_screen); cur_screen = alt_screen; } /* If they want 80/132 switching, then they want a model 5. */ if (def_screen != NULL && model_num != 5) { appres.model = NewString("5"); set_rows_cols(5, 0, 0); } #endif /*]*/ while (LINES < maxROWS || COLS < maxCOLS) { char buf[2]; /* * First, cancel any oversize. This will get us to the correct * model number, if there is any. */ if ((ov_cols && ov_cols > COLS) || (ov_rows && ov_rows > LINES)) { ov_cols = 0; ov_rows = 0; oversize = True; continue; } /* If we're at the smallest screen now, give up. */ if (model_num == 2) { (void) fprintf(stderr, "Emulator won't fit on a %dx%d " "display.\n", LINES, COLS); exit(1); } /* Try a smaller model. */ (void) sprintf(buf, "%d", model_num - 1); appres.model = NewString(buf); set_rows_cols(model_num - 1, 0, 0); } /* * Now, if they wanted an oversize, but didn't get it, try applying it * again. */ if (oversize) { if (want_ov_rows > LINES - 2) want_ov_rows = LINES - 2; if (want_ov_rows < maxROWS) want_ov_rows = maxROWS; if (want_ov_cols > COLS) want_ov_cols = COLS; set_rows_cols(model_num, want_ov_cols, want_ov_rows); } /* Figure out where the status line goes, if it fits. */ #if defined(C3270_80_132) /*[*/ if (def_screen != NULL) { /* Start out in defscreen mode. */ set_status_row(defscreen_spec.rows, 24); } else #endif /*]*/ { /* Start out in altscreen mode. */ set_status_row(LINES, maxROWS); } /* Set up callbacks for state changes. */ register_schange(ST_CONNECT, status_connect); register_schange(ST_3270_MODE, status_3270_mode); register_schange(ST_PRINTER, status_printer); /* Play with curses color. */ if (appres.m3279) { start_color(); if (has_colors() && COLORS >= 8) { defattr = get_color_pair(COLOR_BLUE, COLOR_BLACK); #if defined(C3270_80_132) && defined(NCURSES_VERSION) /*[*/ if (def_screen != NULL) { SCREEN *s = cur_screen; /* * Initialize the colors for the other * screen. */ if (s == def_screen) set_term(alt_screen); else set_term(def_screen); start_color(); curses_alt = !curses_alt; (void) get_color_pair(COLOR_BLUE, COLOR_BLACK); curses_alt = !curses_alt; set_term(s); } #endif /*]*/ } else { appres.m3279 = False; /* Get the terminal name right. */ set_rows_cols(model_num, want_ov_cols, want_ov_rows); } } /* See about keyboard Meta-key behavior. */ if (!ts_value(appres.meta_escape, &me_mode)) (void) fprintf(stderr, "invalid %s value: '%s', " "assuming 'auto'\n", ResMetaEscape, appres.meta_escape); if (me_mode == TS_AUTO) me_mode = tigetflag("km")? TS_OFF: TS_ON; /* See about all-bold behavior. */ if (appres.all_bold_on) ab_mode = TS_ON; else if (!ts_value(appres.all_bold, &ab_mode)) (void) fprintf(stderr, "invalid %s value: '%s', " "assuming 'auto'\n", ResAllBold, appres.all_bold); if (ab_mode == TS_AUTO) ab_mode = appres.m3279? TS_ON: TS_OFF; if (ab_mode == TS_ON) defattr |= A_BOLD; /* Set up the controller. */ ctlr_init(-1); ctlr_reinit(-1); /* Finish screen initialization. */ screen_init2(); screen_suspend(); } /* Configure the TTY settings for a curses screen. */ static void setup_tty(void) { if (appres.cbreak_mode) cbreak(); else raw(); noecho(); nonl(); intrflush(stdscr,FALSE); if (appres.curses_keypad) keypad(stdscr, TRUE); meta(stdscr, TRUE); nodelay(stdscr, TRUE); refresh(); } #if defined(C3270_80_132) /*[*/ static void swap_screens(SCREEN *new_screen) { set_term(new_screen); cur_screen = new_screen; } #endif /*]*/ /* Secondary screen initialization. */ static void screen_init2(void) { /* * Finish initializing ncurses. This should be the first time that it * will send anything to the terminal. */ escaped = False; /* Set up the keyboard. */ setup_tty(); #if defined(C3270_80_132) /*[*/ if (def_screen != NULL) { /* * The first setup_tty() set up altscreen. * Set up defscreen now, and leave it as the * current curses screen. */ swap_screens(def_screen); setup_tty(); } #endif /*]*/ /* Subscribe to input events. */ input_id = AddInput(0, kybd_input); /* Ignore SIGINT and SIGTSTP. */ signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); #if defined(C3270_80_132) /*[*/ /* Ignore SIGWINCH -- it might happen when we do 80/132 changes. */ if (def_screen != NULL) signal(SIGWINCH, SIG_IGN); #endif /*]*/ } /* Calculate where the status line goes now. */ static void set_status_row(int screen_rows, int emulator_rows) { if (screen_rows < emulator_rows + 1) { status_row = status_skip = 0; } else if (screen_rows == emulator_rows + 1) { status_skip = 0; status_row = emulator_rows; } else { status_skip = screen_rows - 2; status_row = screen_rows - 1; } } /* * Parse a tri-state resource value. * Returns True for success, False for failure. */ static Boolean ts_value(const char *s, enum ts *tsp) { *tsp = TS_AUTO; if (s != CN && s[0]) { int sl = strlen(s); if (!strncasecmp(s, "true", sl)) *tsp = TS_ON; else if (!strncasecmp(s, "false", sl)) *tsp = TS_OFF; else if (strncasecmp(s, "auto", sl)) return False; } return True; } /* Allocate a color pair. */ static int get_color_pair(int fg, int bg) { static int next_pair[2] = { 1, 1 }; int pair; #if defined(C3270_80_132) && defined(NCURSES_VERSION) /*[*/ /* ncurses allocates colors for each screen. */ int pair_index = !!curses_alt; #else /*][*/ /* curses allocates colors globally. */ const int pair_index = 0; #endif /*]*/ if ((pair = cp[fg][bg][pair_index])) return COLOR_PAIR(pair); if (next_pair[pair_index] >= COLOR_PAIRS) return 0; if (init_pair(next_pair[pair_index], fg, bg) != OK) return 0; pair = cp[fg][bg][pair_index] = next_pair[pair_index]++; return COLOR_PAIR(pair); } static int color_from_fa(unsigned char fa) { static int field_colors[4] = { COLOR_GREEN, /* default */ COLOR_RED, /* intensified */ COLOR_BLUE, /* protected */ COLOR_WHITE /* protected, intensified */ # define DEFCOLOR_MAP(f) \ ((((f) & FA_PROTECT) >> 4) | (((f) & FA_INT_HIGH_SEL) >> 3)) }; if (appres.m3279) { int fg; fg = field_colors[DEFCOLOR_MAP(fa)]; return get_color_pair(fg, COLOR_BLACK) | (((ab_mode == TS_ON) || FA_IS_HIGH(fa))? A_BOLD: A_NORMAL); } else return ((ab_mode == TS_ON) || FA_IS_HIGH(fa))? A_BOLD: A_NORMAL; } /* Display what's in the buffer. */ void screen_disp(Boolean erasing unused) { int row, col; int a; int c; unsigned char fa; extern Boolean screen_alt; struct screen_spec *cur_spec; #if defined(X3270_DBCS) /*[*/ enum dbcs_state d; #endif /*]*/ /* This may be called when it isn't time. */ if (escaped) return; #if defined(C3270_80_132) /*[*/ /* See if they've switched screens on us. */ if (def_screen != NULL && screen_alt != curses_alt) { if (screen_alt) { (void) write(1, altscreen_spec.mode_switch, strlen(altscreen_spec.mode_switch)); trace_event("Switching to alt (%dx%d) screen.\n", altscreen_spec.rows, altscreen_spec.cols); swap_screens(alt_screen); cur_spec = &altscreen_spec; } else { (void) write(1, defscreen_spec.mode_switch, strlen(defscreen_spec.mode_switch)); trace_event("Switching to default (%dx%d) screen.\n", defscreen_spec.rows, defscreen_spec.cols); swap_screens(def_screen); cur_spec = &defscreen_spec; } /* Figure out where the status line goes now, if it fits. */ set_status_row(cur_spec->rows, ROWS); curses_alt = screen_alt; /* Tell curses to forget what may be on the screen already. */ endwin(); erase(); } #endif /*]*/ fa = get_field_attribute(0); a = color_from_fa(fa); for (row = 0; row < ROWS; row++) { int baddr; if (!flipped) move(row, 0); for (col = 0; col < cCOLS; col++) { if (flipped) move(row, cCOLS-1 - col); baddr = row*cCOLS+col; if (ea_buf[baddr].fa) { fa = ea_buf[baddr].fa; if (appres.m3279) { if (ea_buf[baddr].fg || ea_buf[baddr].bg) { int fg, bg; if (ea_buf[baddr].fg) fg = cmap[ea_buf[baddr].fg & 0x0f]; else fg = COLOR_WHITE; if (ea_buf[baddr].bg) bg = cmap[ea_buf[baddr].bg & 0x0f]; else bg = COLOR_BLACK; a = get_color_pair(fg, bg) | ((ab_mode == TS_ON)? A_BOLD: A_NORMAL); } else { a = color_from_fa(fa); } } else { a = FA_IS_HIGH(fa)? A_BOLD: A_NORMAL; } if (ea_buf[baddr].gr & GR_BLINK) a |= A_BLINK; if (ea_buf[baddr].gr & GR_REVERSE) a |= A_REVERSE; if (ea_buf[baddr].gr & GR_UNDERLINE) a |= A_UNDERLINE; if (ea_buf[baddr].gr & GR_INTENSIFY) a |= A_BOLD; attrset(defattr); addch(' '); } else if (FA_IS_ZERO(fa)) { attrset(a); addch(' '); } else { if (ea_buf[baddr].gr || ea_buf[baddr].fg || ea_buf[baddr].bg) { int b = ((ab_mode == TS_ON) || FA_IS_HIGH(fa))? A_BOLD: A_NORMAL; if (ea_buf[baddr].gr & GR_BLINK) b |= A_BLINK; if (ea_buf[baddr].gr & GR_REVERSE) b |= A_REVERSE; if (ea_buf[baddr].gr & GR_UNDERLINE) b |= A_UNDERLINE; if (ea_buf[baddr].gr & GR_INTENSIFY) b |= A_BOLD; if (appres.m3279 && (ea_buf[baddr].fg || ea_buf[baddr].bg)) { int fg, bg; if (ea_buf[baddr].fg) fg = cmap[ea_buf[baddr].fg & 0x0f]; else fg = COLOR_WHITE; if (ea_buf[baddr].bg) bg = cmap[ea_buf[baddr].bg & 0x0f]; else bg = COLOR_BLACK; b |= get_color_pair(fg, bg); } else b |= a; attrset(b); } else { (void) attrset(a); } #if defined(X3270_DBCS) /*[*/ d = ctlr_dbcs_state(baddr); if (IS_LEFT(d)) { int xaddr = baddr; char mb[16]; int len; int i; INC_BA(xaddr); len = dbcs_to_mb(ea_buf[baddr].cc, ea_buf[xaddr].cc, mb); for (i = 0; i < len; i++) { addch(mb[i] & 0xff); } } else if (!IS_RIGHT(d)) { #endif /*]*/ if (ea_buf[baddr].cs == CS_LINEDRAW) { c = linedraw_to_acs(ea_buf[baddr].cc); if (c != -1) addch(c); else addch(' '); } else if (ea_buf[baddr].cs == CS_APL || (ea_buf[baddr].cs & CS_GE)) { c = apl_to_acs(ea_buf[baddr].cc); if (c != -1) addch(c); else addch(' '); } else { if (toggled(MONOCASE)) addch(asc2uc[ebc2asc[ea_buf[baddr].cc]]); else addch(ebc2asc[ea_buf[baddr].cc]); } #if defined(X3270_DBCS) /*[*/ } #endif /*]*/ } } } if (status_row) draw_oia(); (void) attrset(defattr); if (flipped) move(cursor_addr / cCOLS, cCOLS-1 - (cursor_addr % cCOLS)); else move(cursor_addr / cCOLS, cursor_addr % cCOLS); refresh(); } /* ESC processing. */ static unsigned long eto = 0L; static Boolean meta_escape = False; static void escape_timeout(void) { trace_event("Timeout waiting for key following Escape, processing " "separately\n"); eto = 0L; meta_escape = False; kybd_input2(0x1b, False); } /* Keyboard input. */ static void kybd_input(void) { int k; Boolean first = True; static Boolean failed_first = False; for (;;) { Boolean derived = False; char dbuf[128]; if (isendwin()) return; k = wgetch(stdscr); if (k == ERR) { if (first) { if (failed_first) { trace_event("End of File, exiting.\n"); x3270_exit(1); } failed_first = True; } return; } else { failed_first = False; } trace_event("Key %s (0x%x)\n", decode_key(k, 0, dbuf), k); /* Handle Meta-Escapes. */ if (meta_escape) { if (eto != 0L) { RemoveTimeOut(eto); eto = 0L; } meta_escape = False; k |= 0x80; derived = True; } else if (me_mode == TS_ON && k == 0x1b) { eto = AddTimeOut(100L, escape_timeout); trace_event(" waiting to see if Escape is followed by" " another key\n"); meta_escape = True; continue; } kybd_input2(k, derived); first = False; } } static void kybd_input2(int k, Boolean derived) { char buf[16]; char *action; char dbuf1[128], dbuf2[128]; if (derived) trace_event(" combining Escape and %s into %s (0x%x)\n", decode_key(k & 0x7f, 0, dbuf1), decode_key(k, KM_META, dbuf2), k); action = lookup_key(k); if (action != CN) { if (strcmp(action, "[ignore]")) push_keymap_action(action); return; } ia_cause = IA_DEFAULT; /* These first cases apply to both 3270 and NVT modes. */ switch (k) { case 0x1d: action_internal(Escape_action, IA_DEFAULT, CN, CN); return; case KEY_UP: action_internal(Up_action, IA_DEFAULT, CN, CN); return; case KEY_DOWN: action_internal(Down_action, IA_DEFAULT, CN, CN); return; case KEY_LEFT: action_internal(Left_action, IA_DEFAULT, CN, CN); return; case KEY_RIGHT: action_internal(Right_action, IA_DEFAULT, CN, CN); return; case KEY_HOME: action_internal(Home_action, IA_DEFAULT, CN, CN); return; default: break; } /* Then look for 3270-only cases. */ if (IN_3270) switch(k) { /* These cases apply only to 3270 mode. */ case 0x03: action_internal(Clear_action, IA_DEFAULT, CN, CN); return; case 0x12: action_internal(Reset_action, IA_DEFAULT, CN, CN); return; case 'L' & 0x1f: action_internal(Redraw_action, IA_DEFAULT, CN, CN); return; case '\t': action_internal(Tab_action, IA_DEFAULT, CN, CN); return; case 0177: case KEY_DC: action_internal(Delete_action, IA_DEFAULT, CN, CN); return; case '\b': case KEY_BACKSPACE: action_internal(BackSpace_action, IA_DEFAULT, CN, CN); return; case '\r': action_internal(Enter_action, IA_DEFAULT, CN, CN); return; case '\n': action_internal(Newline_action, IA_DEFAULT, CN, CN); return; case KEY_HOME: action_internal(Home_action, IA_DEFAULT, CN, CN); return; default: break; } /* Do some NVT-only translations. */ if (IN_ANSI) switch(k) { case KEY_DC: k = 0x7f; break; case KEY_BACKSPACE: k = '\b'; break; } /* Catch PF keys. */ if (k >= KEY_F(1) && k <= KEY_F(24)) { (void) sprintf(buf, "%d", k - KEY_F0); action_internal(PF_action, IA_DEFAULT, buf, CN); return; } /* Then any other 8-bit ASCII character. */ if (!(k & ~0xff)) { char ks[6]; String params[2]; Cardinal one; if (k >= ' ') { ks[0] = k; ks[1] = '\0'; } else { (void) sprintf(ks, "0x%x", k); } params[0] = ks; params[1] = CN; one = 1; Key_action(NULL, NULL, params, &one); return; } trace_event(" dropped (no default)\n"); } void screen_suspend(void) { static Boolean need_to_scroll = False; if (!escaped) { escaped = True; #if defined(C3270_80_132) /*[*/ if (def_screen != NULL) { /* * Call endwin() for the last-defined screen * (altscreen) first. Note that this will leave * the curses screen set to defscreen when this * function exits; if the 3270 is really in altscreen * mode, we will have to switch it back when we resume * the screen, below. */ if (!curses_alt) swap_screens(alt_screen); endwin(); swap_screens(def_screen); endwin(); } else { endwin(); } #else /*][*/ endwin(); #endif /*]*/ if (need_to_scroll) printf("\n"); else need_to_scroll = True; #if defined(C3270_80_132) /*[*/ if (curses_alt && def_screen != NULL) { (void) write(1, defscreen_spec.mode_switch, strlen(defscreen_spec.mode_switch)); } #endif /*]*/ RemoveInput(input_id); } } void screen_resume(void) { escaped = False; #if defined(C3270_80_132) /*[*/ if (def_screen != NULL && curses_alt) { /* * When we suspended the screen, we switched to defscreen so * that endwin() got called in the right order. Switch back. */ swap_screens(alt_screen); (void) write(1, altscreen_spec.mode_switch, strlen(altscreen_spec.mode_switch)); } #endif /*]*/ screen_disp(False); refresh(); input_id = AddInput(0, kybd_input); } void cursor_move(int baddr) { cursor_addr = baddr; } void toggle_monocase(struct toggle *t unused, enum toggle_type tt unused) { screen_disp(False); } /* Status line stuff. */ static Boolean status_ta = False; static Boolean status_rm = False; static Boolean status_im = False; static Boolean oia_boxsolid = False; static Boolean oia_undera = True; static Boolean oia_compose = False; static Boolean oia_printer = False; static unsigned char oia_compose_char = 0; static enum keytype oia_compose_keytype = KT_STD; #define LUCNT 8 static char oia_lu[LUCNT+1]; static char *status_msg = ""; void status_ctlr_done(void) { oia_undera = True; } void status_insert_mode(Boolean on) { status_im = on; } void status_minus(void) { status_msg = "X -f"; } void status_oerr(int error_type) { switch (error_type) { case KL_OERR_PROTECTED: status_msg = "X Protected"; break; case KL_OERR_NUMERIC: status_msg = "X Numeric"; break; case KL_OERR_OVERFLOW: status_msg = "X Overflow"; break; } } void status_reset(void) { if (kybdlock & KL_ENTER_INHIBIT) status_msg = "X Inhibit"; else if (kybdlock & KL_DEFERRED_UNLOCK) status_msg = "X"; else status_msg = ""; } void status_reverse_mode(Boolean on) { status_rm = on; } void status_syswait(void) { status_msg = "X SYSTEM"; } void status_twait(void) { oia_undera = False; status_msg = "X Wait"; } void status_typeahead(Boolean on) { status_ta = on; } void status_compose(Boolean on, unsigned char c, enum keytype keytype) { oia_compose = on; oia_compose_char = c; oia_compose_keytype = keytype; } void status_lu(const char *lu) { if (lu != NULL) { (void) strncpy(oia_lu, lu, LUCNT); oia_lu[LUCNT] = '\0'; } else (void) memset(oia_lu, '\0', sizeof(oia_lu)); } static void status_connect(Boolean connected) { if (connected) { oia_boxsolid = IN_3270 && !IN_SSCP; if (kybdlock & KL_AWAITING_FIRST) status_msg = "X"; else status_msg = ""; } else { oia_boxsolid = False; status_msg = "X Disconnected"; } } static void status_3270_mode(Boolean ignored unused) { oia_boxsolid = IN_3270 && !IN_SSCP; if (oia_boxsolid) oia_undera = True; } static void status_printer(Boolean on) { oia_printer = on; } static void draw_oia(void) { int rmargin; #if defined(C3270_80_132) /*[*/ if (def_screen != NULL) { if (curses_alt) rmargin = altscreen_spec.cols - 1; else rmargin = defscreen_spec.cols - 1; } else #endif /*]*/ { rmargin = maxCOLS - 1; } /* Make sure the status line region is filled in properly. */ if (appres.m3279) { int i; attrset(defattr); if (status_skip) { move(status_skip, 0); for (i = 0; i < rmargin; i++) { printw(" "); } } move(status_row, 0); for (i = 0; i < rmargin; i++) { printw(" "); } } (void) attrset(A_REVERSE | defattr); mvprintw(status_row, 0, "4"); (void) attrset(A_UNDERLINE | defattr); if (oia_undera) printw("%c", IN_E? 'B': 'A'); else printw(" "); (void) attrset(A_REVERSE | defattr); if (IN_ANSI) printw("N"); else if (oia_boxsolid) printw(" "); else if (IN_SSCP) printw("S"); else printw("?"); (void) attrset(defattr); mvprintw(status_row, 8, "%-11s", status_msg); mvprintw(status_row, rmargin-36, "%c%c %c %c%c%c", oia_compose? 'C': ' ', oia_compose? oia_compose_char: ' ', status_ta? 'T': ' ', status_rm? 'R': ' ', status_im? 'I': ' ', oia_printer? 'P': ' '); mvprintw(status_row, rmargin-25, "%s", oia_lu); mvprintw(status_row, rmargin-7, "%03d/%03d", cursor_addr/cCOLS + 1, cursor_addr%cCOLS + 1); } void Redraw_action(Widget w unused, XEvent *event unused, String *params unused, Cardinal *num_params unused) { if (!escaped) { endwin(); refresh(); } } void ring_bell(void) { beep(); } void screen_flip(void) { flipped = !flipped; screen_disp(False); } #if defined(C3270_80_132) /*[*/ /* Alt/default screen spec parsing. */ static void parse_screen_spec(const char *str, struct screen_spec *spec) { char msbuf[3]; char *s, *t, c; Boolean escaped = False; if (sscanf(str, "%dx%d=%2s", &spec->rows, &spec->cols, msbuf) != 3) { (void) fprintf(stderr, "Invalid screen screen spec '%s', must " "be 'x='\n", str); exit(1); } s = strchr(str, '=') + 1; spec->mode_switch = Malloc(strlen(s) + 1); t = spec->mode_switch; while ((c = *s++)) { if (escaped) { switch (c) { case 'E': *t++ = 0x1b; break; case 'n': *t++ = '\n'; break; case 'r': *t++ = '\r'; break; case 'b': *t++ = '\b'; break; case 't': *t++ = '\t'; break; case '\\': *t++ = '\\'; break; default: *t++ = c; break; } escaped = False; } else if (c == '\\') escaped = True; else *t++ = c; } *t = '\0'; } #endif /*]*/ void screen_132(void) { #if defined(C3270_80_132) /*[*/ if (cur_screen != alt_screen) { swap_screens(alt_screen); (void) write(1, altscreen_spec.mode_switch, strlen(altscreen_spec.mode_switch)); ctlr_erase(True); screen_disp(True); } #endif /*]*/ } void screen_80(void) { #if defined(C3270_80_132) /*[*/ if (cur_screen != def_screen) { swap_screens(def_screen); (void) write(1, defscreen_spec.mode_switch, strlen(defscreen_spec.mode_switch)); ctlr_erase(False); screen_disp(True); } #endif /*]*/ } /* * Translate an x3270 font line-drawing character (the first two rows of a * standard X11 fixed-width font) to a curses ACS character. * * Returns -1 if there is no translation. */ static int linedraw_to_acs(unsigned char c) { switch (c) { #if defined(ACS_BLOCK) /*[*/ case 0x0: return ACS_BLOCK; #endif /*]*/ #if defined(ACS_DIAMOND) /*[*/ case 0x1: return ACS_DIAMOND; #endif /*]*/ #if defined(ACS_CKBOARD) /*[*/ case 0x2: return ACS_CKBOARD; #endif /*]*/ #if defined(ACS_DEGREE) /*[*/ case 0x7: return ACS_DEGREE; #endif /*]*/ #if defined(ACS_PLMINUS) /*[*/ case 0x8: return ACS_PLMINUS; #endif /*]*/ #if defined(ACS_BOARD) /*[*/ case 0x9: return ACS_BOARD; #endif /*]*/ #if defined(ACS_LANTERN) /*[*/ case 0xa: return ACS_LANTERN; #endif /*]*/ #if defined(ACS_LRCORNER) /*[*/ case 0xb: return ACS_LRCORNER; #endif /*]*/ #if defined(ACS_URCORNER) /*[*/ case 0xc: return ACS_URCORNER; #endif /*]*/ #if defined(ACS_ULCORNER) /*[*/ case 0xd: return ACS_ULCORNER; #endif /*]*/ #if defined(ACS_LLCORNER) /*[*/ case 0xe: return ACS_LLCORNER; #endif /*]*/ #if defined(ACS_PLUS) /*[*/ case 0xf: return ACS_PLUS; #endif /*]*/ #if defined(ACS_S1) /*[*/ case 0x10: return ACS_S1; #endif /*]*/ #if defined(ACS_S3) /*[*/ case 0x11: return ACS_S3; #endif /*]*/ #if defined(ACS_HLINE) /*[*/ case 0x12: return ACS_HLINE; #endif /*]*/ #if defined(ACS_S7) /*[*/ case 0x13: return ACS_S7; #endif /*]*/ #if defined(ACS_S9) /*[*/ case 0x14: return ACS_S9; #endif /*]*/ #if defined(ACS_LTEE) /*[*/ case 0x15: return ACS_LTEE; #endif /*]*/ #if defined(ACS_RTEE) /*[*/ case 0x16: return ACS_RTEE; #endif /*]*/ #if defined(ACS_BTEE) /*[*/ case 0x17: return ACS_BTEE; #endif /*]*/ #if defined(ACS_TTEE) /*[*/ case 0x18: return ACS_TTEE; #endif /*]*/ #if defined(ACS_VLINE) /*[*/ case 0x19: return ACS_VLINE; #endif /*]*/ #if defined(ACS_LEQUAL) /*[*/ case 0x1a: return ACS_LEQUAL; #endif /*]*/ #if defined(ACS_GEQUAL) /*[*/ case 0x1b: return ACS_GEQUAL; #endif /*]*/ #if defined(ACS_PI) /*[*/ case 0x1c: return ACS_PI; #endif /*]*/ #if defined(ACS_NEQUAL) /*[*/ case 0x1d: return ACS_NEQUAL; #endif /*]*/ #if defined(ACS_STERLING) /*[*/ case 0x1e: return ACS_STERLING; #endif /*]*/ #if defined(ACS_BULLET) /*[*/ case 0x1f: return ACS_BULLET; #endif /*]*/ default: return -1; } } static int apl_to_acs(unsigned char c) { switch (c) { #if defined(ACS_DEGREE) /*[*/ case 0xaf: /* CG 0xd1 */ return ACS_DEGREE; #endif /*]*/ #if defined(ACS_LRCORNER) /*[*/ case 0xd4: /* CG 0xac */ return ACS_LRCORNER; #endif /*]*/ #if defined(ACS_URCORNER) /*[*/ case 0xd5: /* CG 0xad */ return ACS_URCORNER; #endif /*]*/ #if defined(ACS_ULCORNER) /*[*/ case 0xc5: /* CG 0xa4 */ return ACS_ULCORNER; #endif /*]*/ #if defined(ACS_LLCORNER) /*[*/ case 0xc4: /* CG 0xa3 */ return ACS_LLCORNER; #endif /*]*/ #if defined(ACS_PLUS) /*[*/ case 0xd3: /* CG 0xab */ return ACS_PLUS; #endif /*]*/ #if defined(ACS_HLINE) /*[*/ case 0xa2: /* CG 0x92 */ return ACS_HLINE; #endif /*]*/ #if defined(ACS_LTEE) /*[*/ case 0xc6: /* CG 0xa5 */ return ACS_LTEE; #endif /*]*/ #if defined(ACS_RTEE) /*[*/ case 0xd6: /* CG 0xae */ return ACS_RTEE; #endif /*]*/ #if defined(ACS_BTEE) /*[*/ case 0xc7: /* CG 0xa6 */ return ACS_BTEE; #endif /*]*/ #if defined(ACS_TTEE) /*[*/ case 0xd7: /* CG 0xaf */ return ACS_TTEE; #endif /*]*/ #if defined(ACS_VLINE) /*[*/ case 0x85: /* CG 0xa84? */ return ACS_VLINE; #endif /*]*/ #if defined(ACS_LEQUAL) /*[*/ case 0x8c: /* CG 0xf7 */ return ACS_LEQUAL; #endif /*]*/ #if defined(ACS_GEQUAL) /*[*/ case 0xae: /* CG 0xd9 */ return ACS_GEQUAL; #endif /*]*/ #if defined(ACS_NEQUAL) /*[*/ case 0xbe: /* CG 0x3e */ return ACS_NEQUAL; #endif /*]*/ #if defined(ACS_BULLET) /*[*/ case 0xa3: /* CG 0x93 */ return ACS_BULLET; #endif /*]*/ case 0xad: return '['; case 0xbd: return ']'; default: return -1; } }