safe_ungetch(SCREEN *sp, int ch) { int rc = ERR; T((T_CALLED("ungetch(%p,%s)"), (void *) sp, _nc_tracechar(sp, ch))); if (tail != -1) { if (head == -1) { head = 0; t_inc(); peek = tail; /* no raw keys */ } else h_dec(); sp->_fifo[head] = ch; T(("ungetch %s ok", _nc_tracechar(sp, ch))); #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _nc_fifo_dump(sp); _nc_unlock_global(tracef); } #endif rc = OK; } returnCode(rc); }
static NCURSES_INLINE int fifo_pull(SCREEN *sp) { int ch; ch = sp->_fifo[head]; TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head)); if (peek == head) { h_inc(); peek = head; } else h_inc(); #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _nc_fifo_dump(sp); _nc_unlock_global(tracef); } #endif return ch; }
static bool _nc_mouse_parse(SCREEN *sp, int runcount) /* parse a run of atomic mouse events into a gesture */ { MEVENT *eventp = sp->_mouse_eventp; MEVENT *ep, *runp, *next, *prev = PREV(eventp); int n; int b; bool merge; TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount)); /* * When we enter this routine, the event list next-free pointer * points just past a run of mouse events that we know were separated * in time by less than the critical click interval. The job of this * routine is to collapse this run into a single higher-level event * or gesture. * * We accomplish this in two passes. The first pass merges press/release * pairs into click events. The second merges runs of click events into * double or triple-click events. * * It's possible that the run may not resolve to a single event (for * example, if the user quadruple-clicks). If so, leading events * in the run are ignored. * * Note that this routine is independent of the format of the specific * format of the pointing-device's reports. We can use it to parse * gestures on anything that reports press/release events on a per- * button basis, as long as the device-dependent mouse code puts stuff * on the queue in MEVENT format. */ if (runcount == 1) { TR(MY_TRACE, ("_nc_mouse_parse: returning simple mouse event %s at slot %ld", _nc_tracemouse(sp, prev), (long) IndexEV(sp, prev))); return (prev->id >= NORMAL_EVENT) ? ((prev->bstate & sp->_mouse_mask) ? TRUE : FALSE) : FALSE; } /* find the start of the run */ runp = eventp; for (n = runcount; n > 0; n--) { runp = PREV(runp); } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "before mouse press/release merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, runp), runcount); _nc_unlock_global(tracef); } #endif /* TRACE */ /* first pass; merge press/release pairs */ do { merge = FALSE; for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) { #define MASK_CHANGED(x) (!(ep->bstate & MASK_PRESS(x)) \ == !(next->bstate & MASK_RELEASE(x))) if (ep->x == next->x && ep->y == next->y && (ep->bstate & BUTTON_PRESSED) && MASK_CHANGED(1) && MASK_CHANGED(2) && MASK_CHANGED(3) && MASK_CHANGED(4) #if NCURSES_MOUSE_VERSION == 2 && MASK_CHANGED(5) #endif ) { for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_CLICK(b)) && (ep->bstate & MASK_PRESS(b))) { ep->bstate &= ~MASK_PRESS(b); ep->bstate |= MASK_CLICK(b); merge = TRUE; } } if (merge) next->id = INVALID_EVENT; } } } while (merge); #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "before mouse click merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, runp), runcount); _nc_unlock_global(tracef); } #endif /* TRACE */ /* * Second pass; merge click runs. At this point, click events are * each followed by one invalid event. We merge click events * forward in the queue. * * NOTE: There is a problem with this design! If the application * allows enough click events to pile up in the circular queue so * they wrap around, it will cheerfully merge the newest forward * into the oldest, creating a bogus doubleclick and confusing * the queue-traversal logic rather badly. Generally this won't * happen, because calling getmouse() marks old events invalid and * ineligible for merges. The true solution to this problem would * be to timestamp each MEVENT and perform the obvious sanity check, * but the timer element would have to have sub-second resolution, * which would get us into portability trouble. */ do { MEVENT *follower; merge = FALSE; for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) if (ep->id != INVALID_EVENT) { if (next->id != INVALID_EVENT) continue; follower = NEXT(next); if (follower->id == INVALID_EVENT) continue; /* merge click events forward */ if ((ep->bstate & BUTTON_CLICKED) && (follower->bstate & BUTTON_CLICKED)) { for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_DOUBLE_CLICK(b)) && (follower->bstate & MASK_CLICK(b))) { follower->bstate &= ~MASK_CLICK(b); follower->bstate |= MASK_DOUBLE_CLICK(b); merge = TRUE; } } if (merge) ep->id = INVALID_EVENT; } /* merge double-click events forward */ if ((ep->bstate & BUTTON_DOUBLE_CLICKED) && (follower->bstate & BUTTON_CLICKED)) { for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_TRIPLE_CLICK(b)) && (follower->bstate & MASK_CLICK(b))) { follower->bstate &= ~MASK_CLICK(b); follower->bstate |= MASK_TRIPLE_CLICK(b); merge = TRUE; } } if (merge) ep->id = INVALID_EVENT; } } } while (merge); #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "before mouse event queue compaction:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, runp), runcount); _nc_unlock_global(tracef); } #endif /* TRACE */ /* * Now try to throw away trailing events flagged invalid, or that * don't match the current event mask. */ for (; runcount; prev = PREV(eventp), runcount--) if (prev->id == INVALID_EVENT || !(prev->bstate & sp->_mouse_mask)) { sp->_mouse_eventp = eventp = prev; } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "after mouse event queue compaction:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, runp), runcount); _nc_unlock_global(tracef); } for (ep = runp; ep != eventp; ep = NEXT(ep)) if (ep->id != INVALID_EVENT) TR(MY_TRACE, ("_nc_mouse_parse: returning composite mouse event %s at slot %ld", _nc_tracemouse(sp, ep), (long) IndexEV(sp, ep))); #endif /* TRACE */ /* after all this, do we have a valid event? */ return (PREV(eventp)->id != INVALID_EVENT); }
wresize(WINDOW *win, int ToLines, int ToCols) { int col, row, size_x, size_y; struct ldat *pline; struct ldat *new_lines = 0; #ifdef TRACE T((T_CALLED("wresize(%p,%d,%d)"), win, ToLines, ToCols)); if (win) { TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", (long) win->_begy, (long) win->_begx, (long) win->_maxy, (long) win->_maxx, (long) win->_regtop, (long) win->_regbottom)); if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...before", win); _nc_unlock_global(tracef); } } #endif if (!win || --ToLines < 0 || --ToCols < 0) returnCode(ERR); size_x = win->_maxx; size_y = win->_maxy; if (ToLines == size_y && ToCols == size_x) returnCode(OK); if ((win->_flags & _SUBWIN)) { /* * Check if the new limits will fit into the parent window's size. If * not, do not resize. We could adjust the location of the subwindow, * but the application may not like that. */ if (win->_pary + ToLines > win->_parent->_maxy || win->_parx + ToCols > win->_parent->_maxx) { returnCode(ERR); } pline = win->_parent->_line; } else { pline = 0; } /* * Allocate new memory as needed. Do the allocations without modifying * the original window, in case an allocation fails. Always allocate * (at least temporarily) the array pointing to the individual lines. */ new_lines = typeCalloc(struct ldat, (unsigned) (ToLines + 1)); if (new_lines == 0) returnCode(ERR); /* * For each line in the target, allocate or adjust pointers for the * corresponding text, depending on whether this is a window or a * subwindow. */ for (row = 0; row <= ToLines; ++row) { int begin = (row > size_y) ? 0 : (size_x + 1); int end = ToCols; NCURSES_CH_T *s; if (!(win->_flags & _SUBWIN)) { if (row <= size_y) { if (ToCols != size_x) { if ((s = typeMalloc(NCURSES_CH_T, ToCols + 1)) == 0) returnCode(cleanup_lines(new_lines, row)); for (col = 0; col <= ToCols; ++col) { s[col] = (col <= size_x ? win->_line[row].text[col] : win->_nc_bkgd); } } else { s = win->_line[row].text; } } else { if ((s = typeMalloc(NCURSES_CH_T, ToCols + 1)) == 0) returnCode(cleanup_lines(new_lines, row)); for (col = 0; col <= ToCols; ++col) s[col] = win->_nc_bkgd; } } else { s = &pline[win->_pary + row].text[win->_parx]; } if_USE_SCROLL_HINTS(new_lines[row].oldindex = row); if (row <= size_y) { new_lines[row].firstchar = win->_line[row].firstchar; new_lines[row].lastchar = win->_line[row].lastchar; } if ((ToCols != size_x) || (row > size_y)) { if (end >= begin) { /* growing */ if (new_lines[row].firstchar < begin) new_lines[row].firstchar = begin; } else { /* shrinking */ new_lines[row].firstchar = 0; } new_lines[row].lastchar = ToCols; } new_lines[row].text = s; } /* * Dispose of unwanted memory. */ if (!(win->_flags & _SUBWIN)) { if (ToCols == size_x) { for (row = ToLines + 1; row <= size_y; row++) { free(win->_line[row].text); } } else { for (row = 0; row <= size_y; row++) { free(win->_line[row].text); } } } free(win->_line); win->_line = new_lines; /* * Finally, adjust the parameters showing screen size and cursor * position: */ win->_maxx = ToCols; win->_maxy = ToLines; if (win->_regtop > win->_maxy) win->_regtop = win->_maxy; if (win->_regbottom > win->_maxy || win->_regbottom == size_y) win->_regbottom = win->_maxy; if (win->_curx > win->_maxx) win->_curx = win->_maxx; if (win->_cury > win->_maxy) win->_cury = win->_maxy; /* * Check for subwindows of this one, and readjust pointers to our text, * if needed. */ repair_subwindows(win); #ifdef TRACE TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", (long) win->_begy, (long) win->_begx, (long) win->_maxy, (long) win->_maxx, (long) win->_regtop, (long) win->_regbottom)); if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...after:", win); _nc_unlock_global(tracef); } #endif returnCode(OK); }
tputs(const char *string, int affcnt, int (*outc) (int)) { bool always_delay; bool normal_delay; int number; #if BSD_TPUTS int trailpad; #endif /* BSD_TPUTS */ #ifdef TRACE char addrbuf[32]; if (USE_TRACEF(TRACE_TPUTS)) { if (outc == _nc_outch) (void) strcpy(addrbuf, "_nc_outch"); else (void) sprintf(addrbuf, "%p", outc); if (_nc_tputs_trace) { _tracef("tputs(%s = %s, %d, %s) called", _nc_tputs_trace, _nc_visbuf(string), affcnt, addrbuf); } else { _tracef("tputs(%s, %d, %s) called", _nc_visbuf(string), affcnt, addrbuf); } TPUTS_TRACE(NULL); _nc_unlock_global(tracef); } #endif /* TRACE */ if (!VALID_STRING(string)) return ERR; if (cur_term == 0) { always_delay = FALSE; normal_delay = TRUE; } else { always_delay = (string == bell) || (string == flash_screen); normal_delay = !xon_xoff && padding_baud_rate #if NCURSES_NO_PADDING && !GetNoPadding(SP) #endif && (_nc_baudrate(ospeed) >= padding_baud_rate); } #if BSD_TPUTS /* * This ugly kluge deals with the fact that some ancient BSD programs * (like nethack) actually do the likes of tputs("50") to get delays. */ trailpad = 0; if (isdigit(UChar(*string))) { while (isdigit(UChar(*string))) { trailpad = trailpad * 10 + (*string - '0'); string++; } trailpad *= 10; if (*string == '.') { string++; if (isdigit(UChar(*string))) { trailpad += (*string - '0'); string++; } while (isdigit(UChar(*string))) string++; } if (*string == '*') { trailpad *= affcnt; string++; } } #endif /* BSD_TPUTS */ my_outch = outc; /* redirect delay_output() */ while (*string) { if (*string != '$') (*outc) (*string); else { string++; if (*string != '<') { (*outc) ('$'); if (*string) (*outc) (*string); } else { bool mandatory; string++; if ((!isdigit(UChar(*string)) && *string != '.') || !strchr(string, '>')) { (*outc) ('$'); (*outc) ('<'); continue; } number = 0; while (isdigit(UChar(*string))) { number = number * 10 + (*string - '0'); string++; } number *= 10; if (*string == '.') { string++; if (isdigit(UChar(*string))) { number += (*string - '0'); string++; } while (isdigit(UChar(*string))) string++; } mandatory = FALSE; while (*string == '*' || *string == '/') { if (*string == '*') { number *= affcnt; string++; } else { /* if (*string == '/') */ mandatory = TRUE; string++; } } if (number > 0 && (always_delay || normal_delay || mandatory)) delay_output(number / 10); } /* endelse (*string == '<') */ } /* endelse (*string == '$') */ if (*string == '\0') break; string++; } #if BSD_TPUTS /* * Emit any BSD-style prefix padding that we've accumulated now. */ if (trailpad > 0 && (always_delay || normal_delay)) delay_output(trailpad / 10); #endif /* BSD_TPUTS */ my_outch = _nc_outch; return OK; }
static bool _nc_mouse_parse(SCREEN *sp, int runcount) /* parse a run of atomic mouse events into a gesture */ { MEVENT *eventp = sp->_mouse_eventp; MEVENT *next, *ep; MEVENT *first_valid = NULL; MEVENT *first_invalid = NULL; int n; int b; bool merge; bool endLoop; TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount)); /* * When we enter this routine, the event list next-free pointer * points just past a run of mouse events that we know were separated * in time by less than the critical click interval. The job of this * routine is to collapse this run into a single higher-level event * or gesture. * * We accomplish this in two passes. The first pass merges press/release * pairs into click events. The second merges runs of click events into * double or triple-click events. * * It's possible that the run may not resolve to a single event (for * example, if the user quadruple-clicks). If so, leading events * in the run are ignored if user does not call getmouse in a loop (getting * them from newest to older). * * Note that this routine is independent of the format of the specific * format of the pointing-device's reports. We can use it to parse * gestures on anything that reports press/release events on a per- * button basis, as long as the device-dependent mouse code puts stuff * on the queue in MEVENT format. */ /* * Reset all events that were not set, in case the user sometimes calls * getmouse only once and other times until there are no more events in * queue. * * This also allows reaching the beginning of the run. */ ep = eventp; for (n = runcount; n < EV_MAX; n++) { Invalidate(ep); ep = NEXT(ep); } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "before mouse press/release merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, ep), runcount); _nc_unlock_global(tracef); } #endif /* TRACE */ /* first pass; merge press/release pairs */ endLoop = FALSE; while (!endLoop) { next = NEXT(ep); if (next == eventp) { /* Will end the loop, but compact before */ endLoop = TRUE; } else { #define MASK_CHANGED(x) (!(ep->bstate & MASK_PRESS(x)) \ == !(next->bstate & MASK_RELEASE(x))) if (ValidEvent(ep) && ValidEvent(next) && ep->x == next->x && ep->y == next->y && (ep->bstate & BUTTON_PRESSED) && (!(next->bstate & BUTTON_PRESSED))) { bool changed = TRUE; for (b = 1; b <= MAX_BUTTONS; ++b) { if (!MASK_CHANGED(b)) { changed = FALSE; break; } } if (changed) { merge = FALSE; for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_CLICK(b)) && (ep->bstate & MASK_PRESS(b))) { next->bstate &= ~MASK_RELEASE(b); next->bstate |= MASK_CLICK(b); merge = TRUE; } } if (merge) { Invalidate(ep); } } } } /* Compact valid events */ if (!ValidEvent(ep)) { if ((first_valid != NULL) && (first_invalid == NULL)) { first_invalid = ep; } } else { if (first_valid == NULL) { first_valid = ep; } else if (first_invalid != NULL) { *first_invalid = *ep; Invalidate(ep); first_invalid = NEXT(first_invalid); } } ep = next; } if (first_invalid != NULL) { eventp = first_invalid; } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "before mouse click merge:"); if (first_valid == NULL) { _tracef("_nc_mouse_parse: no valid event"); } else { _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, eventp, first_valid), runcount); _nc_unlock_global(tracef); } } #endif /* TRACE */ /* * Second pass; merge click runs. We merge click events forward in the * queue. For example, double click can be changed to triple click. * * NOTE: There is a problem with this design! If the application * allows enough click events to pile up in the circular queue so * they wrap around, it will cheerfully merge the newest forward * into the oldest, creating a bogus doubleclick and confusing * the queue-traversal logic rather badly. Generally this won't * happen, because calling getmouse() marks old events invalid and * ineligible for merges. The true solution to this problem would * be to timestamp each MEVENT and perform the obvious sanity check, * but the timer element would have to have sub-second resolution, * which would get us into portability trouble. */ first_invalid = NULL; endLoop = (first_valid == NULL); ep = first_valid; while (!endLoop) { next = NEXT(ep); if (next == eventp) { /* Will end the loop, but check event type and compact before */ endLoop = TRUE; } else if (!ValidEvent(next)) { continue; } else { /* merge click events forward */ if ((ep->bstate & BUTTON_CLICKED) && (next->bstate & BUTTON_CLICKED)) { merge = FALSE; for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_DOUBLE_CLICK(b)) && (ep->bstate & MASK_CLICK(b)) && (next->bstate & MASK_CLICK(b))) { next->bstate &= ~MASK_CLICK(b); next->bstate |= MASK_DOUBLE_CLICK(b); merge = TRUE; } } if (merge) { Invalidate(ep); } } /* merge double-click events forward */ if ((ep->bstate & BUTTON_DOUBLE_CLICKED) && (next->bstate & BUTTON_CLICKED)) { merge = FALSE; for (b = 1; b <= MAX_BUTTONS; ++b) { if ((sp->_mouse_mask & MASK_TRIPLE_CLICK(b)) && (ep->bstate & MASK_DOUBLE_CLICK(b)) && (next->bstate & MASK_CLICK(b))) { next->bstate &= ~MASK_CLICK(b); next->bstate |= MASK_TRIPLE_CLICK(b); merge = TRUE; } } if (merge) { Invalidate(ep); } } } /* Discard event if it does not match event mask */ if (!(ep->bstate & sp->_mouse_mask2)) { Invalidate(ep); } /* Compact valid events */ if (!ValidEvent(ep)) { if (ep == first_valid) { first_valid = next; } else if (first_invalid == NULL) { first_invalid = ep; } } else if (first_invalid != NULL) { *first_invalid = *ep; Invalidate(ep); first_invalid = NEXT(first_invalid); } ep = next; } if (first_invalid == NULL) { first_invalid = eventp; } sp->_mouse_eventp = first_invalid; #ifdef TRACE if (first_valid != NULL) { if (USE_TRACEF(TRACE_IEVENT)) { _trace_slot(sp, "after mouse event queue compaction:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", RunParams(sp, first_invalid, first_valid), runcount); _nc_unlock_global(tracef); } for (ep = first_valid; ep != first_invalid; ep = NEXT(ep)) { if (ValidEvent(ep)) TR(MY_TRACE, ("_nc_mouse_parse: returning composite mouse event %s at slot %ld", _nc_tracemouse(sp, ep), (long) IndexEV(sp, ep))); } } #endif /* TRACE */ /* after all this, do we have a valid event? */ return ValidEvent(PREV(first_invalid)); }
wnoutrefresh(WINDOW *win) { int limit_x; int src_row, src_col; int begx; int begy; int dst_row, dst_col; #if USE_SCROLL_HINTS bool wide; #endif #if NCURSES_SP_FUNCS SCREEN *SP_PARM = _nc_screen_of(win); #endif T((T_CALLED("wnoutrefresh(%p)"), (void *) win)); #ifdef TRACE if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...win", win); _nc_unlock_global(tracef); } #endif /* TRACE */ /* * This function will break badly if we try to refresh a pad. */ if ((win == 0) || (win->_flags & _ISPAD)) returnCode(ERR); /* put them here so "win == 0" won't break our code */ begx = win->_begx; begy = win->_begy; NewScreen(SP_PARM)->_nc_bkgd = win->_nc_bkgd; WINDOW_ATTRS(NewScreen(SP_PARM)) = WINDOW_ATTRS(win); /* merge in change information from all subwindows of this window */ wsyncdown(win); #if USE_SCROLL_HINTS /* * For pure efficiency, we'd want to transfer scrolling information * from the window to newscr whenever the window is wide enough that * its update will dominate the cost of the update for the horizontal * band of newscr that it occupies. Unfortunately, this threshold * tends to be complex to estimate, and in any case scrolling the * whole band and rewriting the parts outside win's image would look * really ugly. So. What we do is consider the window "wide" if it * either (a) occupies the whole width of newscr, or (b) occupies * all but at most one column on either vertical edge of the screen * (this caters to fussy people who put boxes around full-screen * windows). Note that changing this formula will not break any code, * merely change the costs of various update cases. */ wide = (begx <= 1 && win->_maxx >= (NewScreen(SP_PARM)->_maxx - 1)); #endif win->_flags &= ~_HASMOVED; /* * Microtweaking alert! This double loop is one of the genuine * hot spots in the code. Even gcc doesn't seem to do enough * common-subexpression chunking to make it really tense, * so we'll force the issue. */ /* limit(dst_col) */ limit_x = win->_maxx; /* limit(src_col) */ if (limit_x > NewScreen(SP_PARM)->_maxx - begx) limit_x = NewScreen(SP_PARM)->_maxx - begx; for (src_row = 0, dst_row = begy + win->_yoffset; src_row <= win->_maxy && dst_row <= NewScreen(SP_PARM)->_maxy; src_row++, dst_row++) { struct ldat *nline = &(NewScreen(SP_PARM)->_line[dst_row]); struct ldat *oline = &win->_line[src_row]; if (oline->firstchar != _NOCHANGE) { int last_src = oline->lastchar; if (last_src > limit_x) last_src = limit_x; src_col = oline->firstchar; dst_col = src_col + begx; if_WIDEC({ int j; /* * Ensure that we will copy complete multi-column characters * on the left-boundary. */ if (isWidecExt(oline->text[src_col])) { j = 1 + dst_col - WidecExt(oline->text[src_col]); if (j < 0) j = 0; if (dst_col > j) { src_col -= (dst_col - j); dst_col = j; } } /* * Ensure that we will copy complete multi-column characters * on the right-boundary. */ j = last_src; if (WidecExt(oline->text[j])) { ++j; while (j <= limit_x) { if (isWidecBase(oline->text[j])) { break; } else { last_src = j; } ++j; } } }); if_WIDEC({ static cchar_t blank = BLANK; int last_dst = begx + ((last_src < win->_maxx) ? last_src : win->_maxx); int fix_left = dst_col; int fix_right = last_dst; int j; /* * Check for boundary cases where we may overwrite part of a * multi-column character. For those, wipe the remainder of * the character to blanks. */ j = dst_col; if (isWidecExt(nline->text[j])) { /* * On the left, we only care about multi-column characters * that extend into the changed region. */ fix_left = 1 + j - WidecExt(nline->text[j]); if (fix_left < 0) fix_left = 0; /* only if cell is corrupt */ } j = last_dst; if (WidecExt(nline->text[j]) != 0) { /* * On the right, any multi-column character is a problem, * unless it happens to be contained in the change, and * ending at the right boundary of the change. The * computation for 'fix_left' accounts for the left-side of * this character. Find the end of the character. */ ++j; while (j <= NewScreen(SP_PARM)->_maxx && isWidecExt(nline->text[j])) { fix_right = j++; } } /* * The analysis is simpler if we do the clearing afterwards. * Do that now. */ if (fix_left < dst_col || fix_right > last_dst) { for (j = fix_left; j <= fix_right; ++j) { nline->text[j] = blank; CHANGED_CELL(nline, j); } } });
NCURSES_SP_NAME(_nc_init_acs) (NCURSES_SP_DCL0) { chtype *fake_map = acs_map; chtype *real_map = SP_PARM != 0 ? SP_PARM->_acs_map : fake_map; int j; T(("initializing ACS map")); /* * If we're using this from curses (rather than terminfo), we are storing * the mapping information in the SCREEN struct so we can decide how to * render it. */ if (real_map != fake_map) { for (j = 1; j < ACS_LEN; ++j) { real_map[j] = 0; fake_map[j] = A_ALTCHARSET | (chtype) j; if (SP_PARM) SP_PARM->_screen_acs_map[j] = FALSE; } } else { for (j = 1; j < ACS_LEN; ++j) { real_map[j] = 0; } } /* * Initializations for a UNIX-like multi-terminal environment. Use * ASCII chars and count on the terminfo description to do better. */ real_map['l'] = '+'; /* should be upper left corner */ real_map['m'] = '+'; /* should be lower left corner */ real_map['k'] = '+'; /* should be upper right corner */ real_map['j'] = '+'; /* should be lower right corner */ real_map['u'] = '+'; /* should be tee pointing left */ real_map['t'] = '+'; /* should be tee pointing right */ real_map['v'] = '+'; /* should be tee pointing up */ real_map['w'] = '+'; /* should be tee pointing down */ real_map['q'] = '-'; /* should be horizontal line */ real_map['x'] = '|'; /* should be vertical line */ real_map['n'] = '+'; /* should be large plus or crossover */ real_map['o'] = '~'; /* should be scan line 1 */ real_map['s'] = '_'; /* should be scan line 9 */ real_map['`'] = '+'; /* should be diamond */ real_map['a'] = ':'; /* should be checker board (stipple) */ real_map['f'] = '\''; /* should be degree symbol */ real_map['g'] = '#'; /* should be plus/minus */ real_map['~'] = 'o'; /* should be bullet */ real_map[','] = '<'; /* should be arrow pointing left */ real_map['+'] = '>'; /* should be arrow pointing right */ real_map['.'] = 'v'; /* should be arrow pointing down */ real_map['-'] = '^'; /* should be arrow pointing up */ real_map['h'] = '#'; /* should be board of squares */ real_map['i'] = '#'; /* should be lantern symbol */ real_map['0'] = '#'; /* should be solid square block */ /* these defaults were invented for ncurses */ real_map['p'] = '-'; /* should be scan line 3 */ real_map['r'] = '-'; /* should be scan line 7 */ real_map['y'] = '<'; /* should be less-than-or-equal-to */ real_map['z'] = '>'; /* should be greater-than-or-equal-to */ real_map['{'] = '*'; /* should be greek pi */ real_map['|'] = '!'; /* should be not-equal */ real_map['}'] = 'f'; /* should be pound-sterling symbol */ /* thick-line-drawing */ real_map['L'] = '+'; /* upper left corner */ real_map['M'] = '+'; /* lower left corner */ real_map['K'] = '+'; /* upper right corner */ real_map['J'] = '+'; /* lower right corner */ real_map['T'] = '+'; /* tee pointing left */ real_map['U'] = '+'; /* tee pointing right */ real_map['V'] = '+'; /* tee pointing up */ real_map['W'] = '+'; /* tee pointing down */ real_map['Q'] = '-'; /* horizontal line */ real_map['X'] = '|'; /* vertical line */ real_map['N'] = '+'; /* large plus or crossover */ /* double-line-drawing */ real_map['C'] = '+'; /* upper left corner */ real_map['D'] = '+'; /* lower left corner */ real_map['B'] = '+'; /* upper right corner */ real_map['A'] = '+'; /* lower right corner */ real_map['G'] = '+'; /* tee pointing left */ real_map['F'] = '+'; /* tee pointing right */ real_map['H'] = '+'; /* tee pointing up */ real_map['I'] = '+'; /* tee pointing down */ real_map['R'] = '-'; /* horizontal line */ real_map['Y'] = '|'; /* vertical line */ real_map['E'] = '+'; /* large plus or crossover */ #ifdef USE_TERM_DRIVER CallDriver_2(SP_PARM, initacs, real_map, fake_map); #else if (ena_acs != NULL) { NCURSES_PUTP2("ena_acs", ena_acs); } #if NCURSES_EXT_FUNCS /* * Linux console "supports" the "PC ROM" character set by the coincidence * that smpch/rmpch and smacs/rmacs have the same values. ncurses has * no codepage support (see SCO Merge for an example). Outside of the * values defined in acsc, there are no definitions for the "PC ROM" * character set (assumed by some applications to be codepage 437), but we * allow those applications to use those codepoints. * * test/blue.c uses this feature. */ #define PCH_KLUDGE(a,b) (a != 0 && b != 0 && !strcmp(a,b)) if (PCH_KLUDGE(enter_pc_charset_mode, enter_alt_charset_mode) && PCH_KLUDGE(exit_pc_charset_mode, exit_alt_charset_mode)) { size_t i; for (i = 1; i < ACS_LEN; ++i) { if (real_map[i] == 0) { real_map[i] = (chtype) i; if (real_map != fake_map) { if (SP != 0) SP->_screen_acs_map[i] = TRUE; } } } } #endif if (acs_chars != NULL) { size_t i = 0; size_t length = strlen(acs_chars); while (i + 1 < length) { if (acs_chars[i] != 0 && UChar(acs_chars[i]) < ACS_LEN) { real_map[UChar(acs_chars[i])] = UChar(acs_chars[i + 1]) | A_ALTCHARSET; if (SP != 0) SP->_screen_acs_map[UChar(acs_chars[i])] = TRUE; } i += 2; } } #ifdef TRACE /* Show the equivalent mapping, noting if it does not match the * given attribute, whether by re-ordering or duplication. */ if (USE_TRACEF(TRACE_CALLS)) { size_t n, m; char show[ACS_LEN * 2 + 1]; for (n = 1, m = 0; n < ACS_LEN; n++) { if (real_map[n] != 0) { show[m++] = (char) n; show[m++] = (char) ChCharOf(real_map[n]); } } show[m] = 0; if (acs_chars == NULL || strcmp(acs_chars, show)) _tracef("%s acs_chars %s", (acs_chars == NULL) ? "NULL" : "READ", _nc_visbuf(acs_chars)); _tracef("%s acs_chars %s", (acs_chars == NULL) ? "NULL" : (strcmp(acs_chars, show) ? "DIFF" : "SAME"), _nc_visbuf(show)); _nc_unlock_global(tracef); } #endif /* TRACE */ #endif }