150276Speter/**************************************************************************** 2176187Srafan * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/* 3050276Speter** lib_addch.c 3150276Speter** 3250276Speter** The routine waddch(). 3350276Speter** 3450276Speter*/ 3550276Speter 3650276Speter#include <curses.priv.h> 3750276Speter#include <ctype.h> 3850276Speter 39184989SrafanMODULE_ID("$Id: lib_addch.c,v 1.113 2008/08/16 19:20:04 tom Exp $") 4050276Speter 41166124Srafanstatic const NCURSES_CH_T blankchar = NewChar(BLANK_TEXT); 42166124Srafan 4350276Speter/* 4450276Speter * Ugly microtweaking alert. Everything from here to end of module is 4550276Speter * likely to be speed-critical -- profiling data sure says it is! 4650276Speter * Most of the important screen-painting functions are shells around 4750276Speter * waddch(). So we make every effort to reduce function-call overhead 4850276Speter * by inlining stuff, even at the cost of making wrapped copies for 4950276Speter * export. Also we supply some internal versions that don't call the 5050276Speter * window sync hook, for use by string-put functions. 5150276Speter */ 5250276Speter 5350276Speter/* Return bit mask for clearing color pair number if given ch has color */ 54166124Srafan#define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0)) 5550276Speter 56166124Srafanstatic NCURSES_INLINE NCURSES_CH_T 5797049Speterrender_char(WINDOW *win, NCURSES_CH_T ch) 5850276Speter/* compute a rendition of the given char correct for the current context */ 5950276Speter{ 60166124Srafan attr_t a = WINDOW_ATTRS(win); 61166124Srafan int pair = GetPair(ch); 6250276Speter 63166124Srafan if (ISBLANK(ch) 64166124Srafan && AttrOf(ch) == A_NORMAL 65166124Srafan && pair == 0) { 66166124Srafan /* color/pair in attrs has precedence over bkgrnd */ 6797049Speter ch = win->_nc_bkgd; 68166124Srafan SetAttr(ch, a | AttrOf(win->_nc_bkgd)); 69166124Srafan if ((pair = GET_WINDOW_PAIR(win)) == 0) 70166124Srafan pair = GetPair(win->_nc_bkgd); 71166124Srafan SetPair(ch, pair); 7262449Speter } else { 7397049Speter /* color in attrs has precedence over bkgrnd */ 74166124Srafan a |= AttrOf(win->_nc_bkgd) & COLOR_MASK(a); 7562449Speter /* color in ch has precedence */ 76166124Srafan if (pair == 0) { 77166124Srafan if ((pair = GET_WINDOW_PAIR(win)) == 0) 78166124Srafan pair = GetPair(win->_nc_bkgd); 79166124Srafan } 80166124Srafan#if 0 81166124Srafan if (pair > 255) { 82166124Srafan NCURSES_CH_T fixme = ch; 83166124Srafan SetPair(fixme, pair); 84166124Srafan } 85166124Srafan#endif 8697049Speter AddAttr(ch, (a & COLOR_MASK(AttrOf(ch)))); 87166124Srafan SetPair(ch, pair); 8862449Speter } 8950276Speter 90166124Srafan TR(TRACE_VIRTPUT, 91166124Srafan ("render_char bkg %s (%d), attrs %s (%d) -> ch %s (%d)", 92166124Srafan _tracech_t2(1, CHREF(win->_nc_bkgd)), 93166124Srafan GetPair(win->_nc_bkgd), 94166124Srafan _traceattr(WINDOW_ATTRS(win)), 95166124Srafan GET_WINDOW_PAIR(win), 96166124Srafan _tracech_t2(3, CHREF(ch)), 97166124Srafan GetPair(ch))); 9862449Speter 9962449Speter return (ch); 10050276Speter} 10150276Speter 10297049SpeterNCURSES_EXPORT(NCURSES_CH_T) 10397049Speter_nc_render(WINDOW *win, NCURSES_CH_T ch) 10450276Speter/* make render_char() visible while still allowing us to inline it below */ 10550276Speter{ 10662449Speter return render_char(win, ch); 10750276Speter} 10850276Speter 10950276Speter/* check if position is legal; if not, return error */ 11050276Speter#ifndef NDEBUG /* treat this like an assertion */ 11150276Speter#define CHECK_POSITION(win, x, y) \ 11250276Speter if (y > win->_maxy \ 11350276Speter || x > win->_maxx \ 11450276Speter || y < 0 \ 11550276Speter || x < 0) { \ 11650276Speter TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \ 11750276Speter "(_maxx = %d, _maxy = %d)", win, x, y, \ 11850276Speter win->_maxx, win->_maxy)); \ 11950276Speter return(ERR); \ 12050276Speter } 12150276Speter#else 12262449Speter#define CHECK_POSITION(win, x, y) /* nothing */ 12350276Speter#endif 12450276Speter 125166124Srafanstatic bool 126166124Srafannewline_forces_scroll(WINDOW *win, NCURSES_SIZE_T * ypos) 127166124Srafan{ 128166124Srafan bool result = FALSE; 129166124Srafan 130166124Srafan if (*ypos >= win->_regtop && *ypos == win->_regbottom) { 131166124Srafan *ypos = win->_regbottom; 132166124Srafan result = TRUE; 133166124Srafan } else { 134166124Srafan *ypos += 1; 135166124Srafan } 136166124Srafan return result; 137166124Srafan} 138166124Srafan 139166124Srafan/* 140166124Srafan * The _WRAPPED flag is useful only for telling an application that we've just 141166124Srafan * wrapped the cursor. We don't do anything with this flag except set it when 142166124Srafan * wrapping, and clear it whenever we move the cursor. If we try to wrap at 143166124Srafan * the lower-right corner of a window, we cannot move the cursor (since that 144166124Srafan * wouldn't be legal). So we return an error (which is what SVr4 does). 145166124Srafan * Unlike SVr4, we can successfully add a character to the lower-right corner 146166124Srafan * (Solaris 2.6 does this also, however). 147166124Srafan */ 148166124Srafanstatic int 149166124Srafanwrap_to_next_line(WINDOW *win) 150166124Srafan{ 151166124Srafan win->_flags |= _WRAPPED; 152166124Srafan if (newline_forces_scroll(win, &(win->_cury))) { 153166124Srafan win->_curx = win->_maxx; 154166124Srafan if (!win->_scroll) 155166124Srafan return (ERR); 156166124Srafan scroll(win); 157166124Srafan } 158166124Srafan win->_curx = 0; 159166124Srafan return (OK); 160166124Srafan} 161166124Srafan 162166124Srafan#if USE_WIDEC_SUPPORT 163166124Srafanstatic int waddch_literal(WINDOW *, NCURSES_CH_T); 164166124Srafan/* 165166124Srafan * Fill the given number of cells with blanks using the current background 166166124Srafan * rendition. This saves/restores the current x-position. 167166124Srafan */ 168166124Srafanstatic void 169166124Srafanfill_cells(WINDOW *win, int count) 170166124Srafan{ 171166124Srafan NCURSES_CH_T blank = blankchar; 172166124Srafan int save_x = win->_curx; 173166124Srafan int save_y = win->_cury; 174166124Srafan 175166124Srafan while (count-- > 0) { 176166124Srafan if (waddch_literal(win, blank) == ERR) 177166124Srafan break; 178166124Srafan } 179166124Srafan win->_curx = save_x; 180166124Srafan win->_cury = save_y; 181166124Srafan} 182166124Srafan#endif 183166124Srafan 184166124Srafan/* 185166124Srafan * Build up the bytes for a multibyte character, returning the length when 186166124Srafan * complete (a positive number), -1 for error and -2 for incomplete. 187166124Srafan */ 188166124Srafan#if USE_WIDEC_SUPPORT 189166124SrafanNCURSES_EXPORT(int) 190166124Srafan_nc_build_wch(WINDOW *win, ARG_CH_T ch) 191166124Srafan{ 192166124Srafan char *buffer = WINDOW_EXT(win, addch_work); 193166124Srafan int len; 194166124Srafan int x = win->_curx; 195166124Srafan int y = win->_cury; 196166124Srafan mbstate_t state; 197166124Srafan wchar_t result; 198166124Srafan 199166124Srafan if ((WINDOW_EXT(win, addch_used) != 0) && 200166124Srafan (WINDOW_EXT(win, addch_x) != x || 201166124Srafan WINDOW_EXT(win, addch_y) != y)) { 202166124Srafan /* discard the incomplete multibyte character */ 203166124Srafan WINDOW_EXT(win, addch_used) = 0; 204166124Srafan TR(TRACE_VIRTPUT, 205166124Srafan ("Alert discarded multibyte on move (%d,%d) -> (%d,%d)", 206166124Srafan WINDOW_EXT(win, addch_y), WINDOW_EXT(win, addch_x), 207166124Srafan y, x)); 208166124Srafan } 209166124Srafan WINDOW_EXT(win, addch_x) = x; 210166124Srafan WINDOW_EXT(win, addch_y) = y; 211166124Srafan 212166124Srafan init_mb(state); 213184989Srafan buffer[WINDOW_EXT(win, addch_used)] = (char) CharOf(CHDEREF(ch)); 214166124Srafan WINDOW_EXT(win, addch_used) += 1; 215166124Srafan buffer[WINDOW_EXT(win, addch_used)] = '\0'; 216166124Srafan if ((len = mbrtowc(&result, 217166124Srafan buffer, 218166124Srafan WINDOW_EXT(win, addch_used), &state)) > 0) { 219166124Srafan attr_t attrs = AttrOf(CHDEREF(ch)); 220178866Srafan if_EXT_COLORS(int pair = GetPair(CHDEREF(ch))); 221166124Srafan SetChar(CHDEREF(ch), result, attrs); 222178866Srafan if_EXT_COLORS(SetPair(CHDEREF(ch), pair)); 223166124Srafan WINDOW_EXT(win, addch_used) = 0; 224176187Srafan } else if (len == -1) { 225176187Srafan /* 226176187Srafan * An error occurred. We could either discard everything, 227176187Srafan * or assume that the error was in the previous input. 228176187Srafan * Try the latter. 229176187Srafan */ 230176187Srafan TR(TRACE_VIRTPUT, ("Alert! mbrtowc returns error")); 231176187Srafan /* handle this with unctrl() */ 232176187Srafan WINDOW_EXT(win, addch_used) = 0; 233166124Srafan } 234166124Srafan return len; 235166124Srafan} 236166124Srafan#endif /* USE_WIDEC_SUPPORT */ 237166124Srafan 238166124Srafanstatic 239166124Srafan#if !USE_WIDEC_SUPPORT /* cannot be inline if it is recursive */ 240166124SrafanNCURSES_INLINE 241166124Srafan#endif 242166124Srafanint 24397049Speterwaddch_literal(WINDOW *win, NCURSES_CH_T ch) 24450276Speter{ 24562449Speter int x; 246166124Srafan int y; 24762449Speter struct ldat *line; 24850276Speter 24962449Speter x = win->_curx; 250166124Srafan y = win->_cury; 25150276Speter 252166124Srafan CHECK_POSITION(win, x, y); 25350276Speter 25462449Speter ch = render_char(win, ch); 25550276Speter 256166124Srafan line = win->_line + y; 25750276Speter 25862449Speter CHANGED_CELL(line, x); 25962449Speter 260166124Srafan /* 261166124Srafan * Build up multibyte characters until we have a wide-character. 262166124Srafan */ 26397049Speter if_WIDEC({ 264166124Srafan if (WINDOW_EXT(win, addch_used) != 0 || !Charable(ch)) { 265166124Srafan int len = _nc_build_wch(win, CHREF(ch)); 266166124Srafan 267176187Srafan if (len >= -1) { 268176187Srafan /* handle EILSEQ */ 269166124Srafan if (is8bits(CharOf(ch))) { 270166124Srafan const char *s = unctrl((chtype) CharOf(ch)); 271166124Srafan if (s[1] != 0) { 272166124Srafan return waddstr(win, s); 273166124Srafan } 274166124Srafan } 275176187Srafan if (len == -1) 276176187Srafan return waddch(win, ' '); 277166124Srafan } else { 278166124Srafan return OK; 279166124Srafan } 280166124Srafan } 28197049Speter }); 28262449Speter 283166124Srafan /* 284166124Srafan * Non-spacing characters are added to the current cell. 285166124Srafan * 286166124Srafan * Spacing characters that are wider than one column require some display 287166124Srafan * adjustments. 288166124Srafan */ 289166124Srafan if_WIDEC({ 290166124Srafan int len = wcwidth(CharOf(ch)); 291166124Srafan int i; 292166124Srafan int j; 293184989Srafan wchar_t *chars; 294166124Srafan 295166124Srafan if (len == 0) { /* non-spacing */ 296166124Srafan if ((x > 0 && y >= 0) 297184989Srafan || (win->_maxx >= 0 && win->_cury >= 1)) { 298184989Srafan if (x > 0 && y >= 0) 299184989Srafan chars = (win->_line[y].text[x - 1].chars); 300184989Srafan else 301184989Srafan chars = (win->_line[y - 1].text[win->_maxx].chars); 302166124Srafan for (i = 0; i < CCHARW_MAX; ++i) { 303166124Srafan if (chars[i] == 0) { 304166124Srafan TR(TRACE_VIRTPUT, 305166124Srafan ("added non-spacing %d: %x", 306166124Srafan x, (int) CharOf(ch))); 307166124Srafan chars[i] = CharOf(ch); 308166124Srafan break; 309166124Srafan } 310166124Srafan } 311166124Srafan } 312166124Srafan goto testwrapping; 313166124Srafan } else if (len > 1) { /* multi-column characters */ 314166124Srafan /* 315166124Srafan * Check if the character will fit on the current line. If it does 316166124Srafan * not fit, fill in the remainder of the line with blanks. and 317166124Srafan * move to the next line. 318166124Srafan */ 319166124Srafan if (len > win->_maxx + 1) { 320166124Srafan TR(TRACE_VIRTPUT, ("character will not fit")); 321166124Srafan return ERR; 322166124Srafan } else if (x + len > win->_maxx + 1) { 323166124Srafan int count = win->_maxx + 1 - x; 324166124Srafan TR(TRACE_VIRTPUT, ("fill %d remaining cells", count)); 325166124Srafan fill_cells(win, count); 326166124Srafan if (wrap_to_next_line(win) == ERR) 327166124Srafan return ERR; 328166124Srafan x = win->_curx; 329166124Srafan y = win->_cury; 330166124Srafan } 331166124Srafan /* 332166124Srafan * Check for cells which are orphaned by adding this character, set 333166124Srafan * those to blanks. 334166124Srafan * 335166124Srafan * FIXME: this actually could fill j-i cells, more complicated to 336166124Srafan * setup though. 337166124Srafan */ 338166124Srafan for (i = 0; i < len; ++i) { 339166124Srafan if (isWidecBase(win->_line[y].text[x + i])) { 340166124Srafan break; 341166124Srafan } else if (isWidecExt(win->_line[y].text[x + i])) { 342166124Srafan for (j = i; x + j <= win->_maxx; ++j) { 343166124Srafan if (!isWidecExt(win->_line[y].text[x + j])) { 344166124Srafan TR(TRACE_VIRTPUT, ("fill %d orphan cells", j)); 345166124Srafan fill_cells(win, j); 346166124Srafan break; 347166124Srafan } 348166124Srafan } 349166124Srafan break; 350166124Srafan } 351166124Srafan } 352166124Srafan /* 353166124Srafan * Finally, add the cells for this character. 354166124Srafan */ 355166124Srafan for (i = 0; i < len; ++i) { 356166124Srafan NCURSES_CH_T value = ch; 357166124Srafan SetWidecExt(value, i); 358166124Srafan TR(TRACE_VIRTPUT, ("multicolumn %d:%d (%d,%d)", 359166124Srafan i + 1, len, 360166124Srafan win->_begy + y, win->_begx + x)); 361166124Srafan line->text[x] = value; 362166124Srafan CHANGED_CELL(line, x); 363166124Srafan ++x; 364166124Srafan } 365166124Srafan goto testwrapping; 366166124Srafan } 367166124Srafan }); 368166124Srafan 369166124Srafan /* 370166124Srafan * Single-column characters. 371166124Srafan */ 372166124Srafan line->text[x++] = ch; 373166124Srafan /* 374166124Srafan * This label is used only for wide-characters. 375166124Srafan */ 376166124Srafan if_WIDEC( 377166124Srafan testwrapping: 378166124Srafan ); 379166124Srafan 380166124Srafan TR(TRACE_VIRTPUT, ("cell (%ld, %ld..%d) = %s", 381166124Srafan (long) win->_cury, (long) win->_curx, x - 1, 382166124Srafan _tracech_t(CHREF(ch)))); 383166124Srafan 38462449Speter if (x > win->_maxx) { 385166124Srafan return wrap_to_next_line(win); 38662449Speter } 38762449Speter win->_curx = x; 38862449Speter return OK; 38950276Speter} 39050276Speter 391166124Srafanstatic NCURSES_INLINE int 39297049Speterwaddch_nosync(WINDOW *win, const NCURSES_CH_T ch) 39350276Speter/* the workhorse function -- add a character to the given window */ 39450276Speter{ 395166124Srafan NCURSES_SIZE_T x, y; 396166124Srafan chtype t = CharOf(ch); 397166124Srafan const char *s = unctrl(t); 39850276Speter 399166124Srafan /* 400166124Srafan * If we are using the alternate character set, forget about locale. 401166124Srafan * Otherwise, if unctrl() returns a single-character or the locale 402166124Srafan * claims the code is printable, treat it that way. 403166124Srafan */ 40497049Speter if ((AttrOf(ch) & A_ALTCHARSET) 405166124Srafan || ( 406166124Srafan#if USE_WIDEC_SUPPORT 407166124Srafan (SP != 0 && SP->_legacy_coding) && 408166124Srafan#endif 409166124Srafan s[1] == 0 410166124Srafan ) 411166124Srafan || ( 412166124Srafan isprint(t) 413166124Srafan#if USE_WIDEC_SUPPORT 414166124Srafan || ((SP == 0 || !SP->_legacy_coding) && 415166124Srafan (WINDOW_EXT(win, addch_used) 416166124Srafan || !_nc_is_charable(CharOf(ch)))) 417166124Srafan#endif 418166124Srafan )) 41962449Speter return waddch_literal(win, ch); 42050276Speter 421166124Srafan /* 422166124Srafan * Handle carriage control and other codes that are not printable, or are 423166124Srafan * known to expand to more than one character according to unctrl(). 424166124Srafan */ 42562449Speter x = win->_curx; 42662449Speter y = win->_cury; 42750276Speter 42862449Speter switch (t) { 42962449Speter case '\t': 43062449Speter x += (TABSIZE - (x % TABSIZE)); 43150276Speter 43262449Speter /* 43362449Speter * Space-fill the tab on the bottom line so that we'll get the 43462449Speter * "correct" cursor position. 43562449Speter */ 43662449Speter if ((!win->_scroll && (y == win->_regbottom)) 43762449Speter || (x <= win->_maxx)) { 438166124Srafan NCURSES_CH_T blank = blankchar; 43997049Speter AddAttr(blank, AttrOf(ch)); 44062449Speter while (win->_curx < x) { 44162449Speter if (waddch_literal(win, blank) == ERR) 44262449Speter return (ERR); 44362449Speter } 44462449Speter break; 44562449Speter } else { 44662449Speter wclrtoeol(win); 44762449Speter win->_flags |= _WRAPPED; 448166124Srafan if (newline_forces_scroll(win, &y)) { 44962449Speter x = win->_maxx; 45062449Speter if (win->_scroll) { 45162449Speter scroll(win); 45262449Speter x = 0; 45350276Speter } 45462449Speter } else { 45550276Speter x = 0; 45662449Speter } 45750276Speter } 45862449Speter break; 45962449Speter case '\n': 46062449Speter wclrtoeol(win); 461166124Srafan if (newline_forces_scroll(win, &y)) { 46262449Speter if (win->_scroll) 46362449Speter scroll(win); 46462449Speter else 46562449Speter return (ERR); 46662449Speter } 46762449Speter /* FALLTHRU */ 46862449Speter case '\r': 46962449Speter x = 0; 47062449Speter win->_flags &= ~_WRAPPED; 47162449Speter break; 47262449Speter case '\b': 47362449Speter if (x == 0) 47462449Speter return (OK); 47562449Speter x--; 47662449Speter win->_flags &= ~_WRAPPED; 47762449Speter break; 47862449Speter default: 47997049Speter while (*s) { 48097049Speter NCURSES_CH_T sch; 48197049Speter SetChar(sch, *s++, AttrOf(ch)); 482178866Srafan if_EXT_COLORS(SetPair(sch, GetPair(ch))); 48397049Speter if (waddch_literal(win, sch) == ERR) 48462449Speter return ERR; 48597049Speter } 48662449Speter return (OK); 48762449Speter } 48850276Speter 48962449Speter win->_curx = x; 49062449Speter win->_cury = y; 49150276Speter 49262449Speter return (OK); 49350276Speter} 49450276Speter 49576726SpeterNCURSES_EXPORT(int) 49697049Speter_nc_waddch_nosync(WINDOW *win, const NCURSES_CH_T c) 49750276Speter/* export copy of waddch_nosync() so the string-put functions can use it */ 49850276Speter{ 49962449Speter return (waddch_nosync(win, c)); 50050276Speter} 50150276Speter 50250276Speter/* 503166124Srafan * The versions below call _nc_synchook(). We wanted to avoid this in the 50450276Speter * version exported for string puts; they'll call _nc_synchook once at end 50550276Speter * of run. 50650276Speter */ 50750276Speter 50850276Speter/* These are actual entry points */ 50950276Speter 51076726SpeterNCURSES_EXPORT(int) 51197049Speterwaddch(WINDOW *win, const chtype ch) 51250276Speter{ 51362449Speter int code = ERR; 51497049Speter NCURSES_CH_T wch; 51597049Speter SetChar2(wch, ch); 51650276Speter 51762449Speter TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win, 51876726Speter _tracechtype(ch))); 51950276Speter 52097049Speter if (win && (waddch_nosync(win, wch) != ERR)) { 52162449Speter _nc_synchook(win); 52262449Speter code = OK; 52362449Speter } 52450276Speter 52562449Speter TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 52662449Speter return (code); 52750276Speter} 52850276Speter 52976726SpeterNCURSES_EXPORT(int) 53097049Speterwechochar(WINDOW *win, const chtype ch) 53150276Speter{ 53262449Speter int code = ERR; 53397049Speter NCURSES_CH_T wch; 53497049Speter SetChar2(wch, ch); 53550276Speter 53662449Speter TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win, 53776726Speter _tracechtype(ch))); 53850276Speter 53997049Speter if (win && (waddch_nosync(win, wch) != ERR)) { 54062449Speter bool save_immed = win->_immed; 54162449Speter win->_immed = TRUE; 54262449Speter _nc_synchook(win); 54362449Speter win->_immed = save_immed; 54462449Speter code = OK; 54562449Speter } 54662449Speter TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 54762449Speter return (code); 54850276Speter} 549