示例#1
0
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);
}
示例#2
0
文件: lib_getch.c 项目: ysleu/RTL8685
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;
}
示例#3
0
文件: lib_mouse.c 项目: ysleu/RTL8685
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);
}
示例#4
0
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);
}
示例#5
0
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;
}
示例#6
0
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));
}
示例#7
0
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);
		    }
		}
	    });
示例#8
0
文件: lib_acs.c 项目: 2asoft/freebsd
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
}