Пример #1
0
delwin(WINDOW *win)
{
    int result = ERR;

    T((T_CALLED("delwin(%p)"), (void *) win));

    if (_nc_try_global(curses) == 0) {
	if (win == 0
	    || cannot_delete(win)) {
	    result = ERR;
	} else {
#if NCURSES_SP_FUNCS
	    SCREEN *sp = _nc_screen_of(win);
#endif
	    if (win->_flags & _SUBWIN)
		touchwin(win->_parent);
	    else if (CurScreen(SP_PARM) != 0)
		touchwin(CurScreen(SP_PARM));

	    result = _nc_freewin(win);
	}
	_nc_unlock_global(curses);
    }
    returnCode(result);
}
Пример #2
0
NCURSES_SP_NAME(set_curterm) (NCURSES_SP_DCLx TERMINAL * termp)
{
    TERMINAL *oldterm;

    T((T_CALLED("set_curterm(%p)"), (void *) termp));

    _nc_lock_global(curses);
    oldterm = cur_term;
    if (SP_PARM)
	SP_PARM->_term = termp;
#if USE_REENTRANT
    CurTerm = termp;
#else
    cur_term = termp;
#endif
    if (termp != 0) {
#ifdef USE_TERM_DRIVER
	TERMINAL_CONTROL_BLOCK *TCB = (TERMINAL_CONTROL_BLOCK *) termp;
	ospeed = (NCURSES_OSPEED) _nc_ospeed(termp->_baudrate);
	if (TCB->drv->isTerminfo && termp->type.Strings) {
	    PC = (char) ((pad_char != NULL) ? pad_char[0] : 0);
	}
	TCB->csp = SP_PARM;
#else
	ospeed = (NCURSES_OSPEED) _nc_ospeed(termp->_baudrate);
	if (termp->type.Strings) {
	    PC = (char) ((pad_char != NULL) ? pad_char[0] : 0);
	}
#endif
    }
    _nc_unlock_global(curses);

    T((T_RETURN("%p"), (void *) oldterm));
    return (oldterm);
}
Пример #3
0
/*
 * If we have reallocated the ldat structs, we will have to repair pointers
 * used in subwindows.
 */
static void
repair_subwindows(WINDOW *cmp)
{
    WINDOWLIST *wp;
    struct ldat *pline = cmp->_line;
    int row;

    _nc_lock_global(curses);

    for (each_window(wp)) {
	WINDOW *tst = &(wp->win);

	if (tst->_parent == cmp) {

	    if (tst->_pary > cmp->_maxy)
		tst->_pary = cmp->_maxy;
	    if (tst->_parx > cmp->_maxx)
		tst->_parx = cmp->_maxx;

	    if (tst->_maxy + tst->_pary > cmp->_maxy)
		tst->_maxy = cmp->_maxy - tst->_pary;
	    if (tst->_maxx + tst->_parx > cmp->_maxx)
		tst->_maxx = cmp->_maxx - tst->_parx;

	    for (row = 0; row <= tst->_maxy; ++row) {
		tst->_line[row].text = &pline[tst->_pary + row].text[tst->_parx];
	    }
	    repair_subwindows(tst);
	}
    }
    _nc_unlock_global(curses);
}
Пример #4
0
set_curterm(TERMINAL * termp)
{
    TERMINAL *oldterm;

    T((T_CALLED("set_curterm(%p)"), termp));

    _nc_lock_global(curses);
    oldterm = cur_term;
    if (SP)
	SP->_term = termp;
#if BROKEN_LINKER || USE_REENTRANT
    _nc_prescreen._cur_term = termp;
#else
    cur_term = termp;
#endif
    if (termp != 0) {
	ospeed = _nc_ospeed(termp->_baudrate);
	if (termp->type.Strings) {
	    PC = (char) ((pad_char != NULL) ? pad_char[0] : 0);
	}
    }
    _nc_unlock_global(curses);

    T((T_RETURN("%p"), oldterm));
    return (oldterm);
}
_nc_freewin(WINDOW *win)
{
    WINDOWLIST *p, *q;
    int i;
    int result = ERR;

    T((T_CALLED("_nc_freewin(%p)"), win));

    if (win != 0) {
	if (_nc_try_global(curses) == 0) {
	    q = 0;
	    for (each_window(p)) {
		if (&(p->win) == win) {
		    remove_window_from_screen(win);
		    if (q == 0)
			_nc_windows = p->next;
		    else
			q->next = p->next;

		    if (!(win->_flags & _SUBWIN)) {
			for (i = 0; i <= win->_maxy; i++)
			    FreeIfNeeded(win->_line[i].text);
		    }
		    free(win->_line);
		    free(p);

		    result = OK;
		    T(("...deleted win=%p", win));
		    break;
		}
		q = p;
	    }
	    _nc_unlock_global(curses);
	}
    }
Пример #6
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);
}
Пример #7
0
del_curterm(TERMINAL * termp)
{
    int rc = ERR;

    _nc_lock_global(curses);
    rc = NCURSES_SP_NAME(del_curterm) (CURRENT_SCREEN, termp);
    _nc_unlock_global(curses);

    return (rc);
}
Пример #8
0
_nc_locked_tracef(const char *fmt,...)
{
    va_list ap;

    va_start(ap, fmt);
    _nc_va_tracef(fmt, ap);
    va_end(ap);

    if (--(_nc_globals.nested_tracef) == 0)
	_nc_unlock_global(tracef);
}
Пример #9
0
static int
overlap(const WINDOW *const src, WINDOW *const dst, int const flag)
{
    int rc = ERR;
    int sx1, sy1, sx2, sy2;
    int dx1, dy1, dx2, dy2;
    int sminrow, smincol;
    int dminrow, dmincol;
    int dmaxrow, dmaxcol;

    T((T_CALLED("overlap(%p,%p,%d)"), src, dst, flag));

    if (src != 0 && dst != 0) {
	_nc_lock_global(curses);

	T(("src : begy %ld, begx %ld, maxy %ld, maxx %ld",
	   (long) src->_begy,
	   (long) src->_begx,
	   (long) src->_maxy,
	   (long) src->_maxx));
	T(("dst : begy %ld, begx %ld, maxy %ld, maxx %ld",
	   (long) dst->_begy,
	   (long) dst->_begx,
	   (long) dst->_maxy,
	   (long) dst->_maxx));

	sx1 = src->_begx;
	sy1 = src->_begy;
	sx2 = sx1 + src->_maxx;
	sy2 = sy1 + src->_maxy;

	dx1 = dst->_begx;
	dy1 = dst->_begy;
	dx2 = dx1 + dst->_maxx;
	dy2 = dy1 + dst->_maxy;

	if (dx2 >= sx1 && dx1 <= sx2 && dy2 >= sy1 && dy1 <= sy2) {
	    sminrow = max(sy1, dy1) - sy1;
	    smincol = max(sx1, dx1) - sx1;
	    dminrow = max(sy1, dy1) - dy1;
	    dmincol = max(sx1, dx1) - dx1;
	    dmaxrow = min(sy2, dy2) - dy1;
	    dmaxcol = min(sx2, dx2) - dx1;

	    rc = copywin(src, dst,
			 sminrow, smincol,
			 dminrow, dmincol,
			 dmaxrow, dmaxcol,
			 flag);
	}
	_nc_unlock_global(curses);
    }
    returnCode(rc);
}
Пример #10
0
use_window(WINDOW *win, NCURSES_WINDOW_CB func, void *data)
{
    int code = OK;

    T((T_CALLED("use_window(%p,%p,%p)"), (void *) win, func, data));
    _nc_lock_global(curses);
    code = func(win, data);
    _nc_unlock_global(curses);

    returnCode(code);
}
Пример #11
0
initscr(void)
{
    WINDOW *result;

    START_TRACE();
    T((T_CALLED("initscr()")));

    _nc_init_pthreads();
    _nc_lock_global(curses);

    /* Portable applications must not call initscr() more than once */
    if (!_nc_globals.init_screen) {
	NCURSES_CONST char *name;

	_nc_globals.init_screen = TRUE;

	if ((name = getenv("TERM")) == 0
	    || *name == '\0')
	    name = "unknown";
#ifdef __CYGWIN__
	/*
	 * 2002/9/21
	 * Work around a bug in Cygwin.  Full-screen subprocesses run from
	 * bash, in turn spawned from another full-screen process, will dump
	 * core when attempting to write to stdout.  Opening /dev/tty
	 * explicitly seems to fix the problem.
	 */
	if (NC_ISATTY(fileno(stdout))) {
	    FILE *fp = fopen("/dev/tty", "w");
	    if (fp != 0 && NC_ISATTY(fileno(fp))) {
		fclose(stdout);
		dup2(fileno(fp), STDOUT_FILENO);
		stdout = fdopen(STDOUT_FILENO, "w");
	    }
	}
#endif
	if (newterm(name, stdout, stdin) == 0) {
	    fprintf(stderr, "Error opening terminal: %s.\n", name);
	    exit(EXIT_FAILURE);
	}

	/* def_shell_mode - done in newterm/_nc_setupscreen */
#if NCURSES_SP_FUNCS
	NCURSES_SP_NAME(def_prog_mode) (CURRENT_SCREEN);
#else
	def_prog_mode();
#endif
    }
    result = stdscr;
    _nc_unlock_global(curses);

    returnWin(result);
}
Пример #12
0
_nc_freeall(void)
{
    WINDOWLIST *p, *q;
    static va_list empty_va;

    T((T_CALLED("_nc_freeall()")));
#if NO_LEAKS
    if (SP != 0) {
	if (SP->_oldnum_list != 0) {
	    FreeAndNull(SP->_oldnum_list);
	}
	if (SP->_panelHook.destroy != 0) {
	    SP->_panelHook.destroy(SP->_panelHook.stdscr_pseudo_panel);
	}
    }
#endif
    if (SP != 0) {
	_nc_lock_global(curses);

	while (_nc_windows != 0) {
	    bool deleted = FALSE;

	    /* Delete only windows that're not a parent */
	    for (each_window(p)) {
		bool found = FALSE;

		for (each_window(q)) {
		    if ((p != q)
			&& (q->win._flags & _SUBWIN)
			&& (&(p->win) == q->win._parent)) {
			found = TRUE;
			break;
		    }
		}

		if (!found) {
		    if (delwin(&(p->win)) != ERR)
			deleted = TRUE;
		    break;
		}
	    }

	    /*
	     * Don't continue to loop if the list is trashed.
	     */
	    if (!deleted)
		break;
	}
	delscreen(SP);
	_nc_unlock_global(curses);
    }
Пример #13
0
static void
show_window_sizes(const char *name)
{
    WINDOWLIST *wp;

    _nc_lock_global(curses);
    _tracef("%s resizing: %2d x %2d (%2d x %2d)", name, LINES, COLS,
	    screen_lines, screen_columns);
    for (each_window(wp)) {
	_tracef("  window %p is %2ld x %2ld at %2ld,%2ld",
		&(wp->win),
		(long) wp->win._maxy + 1,
		(long) wp->win._maxx + 1,
		(long) wp->win._begy,
		(long) wp->win._begx);
    }
    _nc_unlock_global(curses);
}
Пример #14
0
del_curterm(TERMINAL * termp)
{
    int rc = ERR;

    T((T_CALLED("del_curterm(%p)"), termp));

    _nc_lock_global(curses);
    if (termp != 0) {
	_nc_free_termtype(&(termp->type));
	FreeIfNeeded(termp->_termname);
	free(termp);
	if (termp == cur_term)
	    set_curterm(0);
	rc = OK;
    }
    _nc_unlock_global(curses);

    returnCode(rc);
}
Пример #15
0
_nc_use_tracef(unsigned mask)
{
    bool result = FALSE;

    _nc_lock_global(tst_tracef);
    if (!_nc_globals.nested_tracef++) {
	if ((result = (_nc_tracing & (mask))) != 0
	    && _nc_try_global(tracef) == 0) {
	    /* we will call _nc_locked_tracef(), no nesting so far */
	} else {
	    /* we will not call _nc_locked_tracef() */
	    _nc_globals.nested_tracef = 0;
	}
    } else {
	/* we may call _nc_locked_tracef(), but with nested_tracef > 0 */
	result = (_nc_tracing & (mask));
    }
    _nc_unlock_global(tst_tracef);
    return result;
}
Пример #16
0
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;
}
Пример #17
0
use_screen(SCREEN *screen, NCURSES_SCREEN_CB func, void *data)
{
    SCREEN *save_SP;
    int code = OK;

    T((T_CALLED("use_screen(%p,%p,%p)"), screen, func, data));

    /*
     * FIXME - add a flag so a given thread can check if _it_ has already
     * recurred through this point, return an error if so.
     */
    _nc_lock_global(curses);
    save_SP = SP;
    set_term(screen);

    code = func(screen, data);

    set_term(save_SP);
    _nc_unlock_global(curses);
    returnCode(code);
}
set_term(SCREEN *screenp)
{
    SCREEN *oldSP;
    SCREEN *newSP;

    T((T_CALLED("set_term(%p)"), screenp));

    _nc_lock_global(curses);

    oldSP = SP;
    _nc_set_screen(screenp);
    newSP = SP;

    if (newSP != 0) {
	set_curterm(newSP->_term);
#if !USE_REENTRANT
	curscr = newSP->_curscr;
	newscr = newSP->_newscr;
	stdscr = newSP->_stdscr;
	COLORS = newSP->_color_count;
	COLOR_PAIRS = newSP->_pair_count;
#endif
    } else {
	set_curterm(0);
#if !USE_REENTRANT
	curscr = 0;
	newscr = 0;
	stdscr = 0;
	COLORS = 0;
	COLOR_PAIRS = 0;
#endif
    }

    _nc_unlock_global(curses);

    T((T_RETURN("%p"), oldSP));
    return (oldSP);
}
Пример #19
0
set_term(SCREEN *screenp)
{
    SCREEN *oldSP;
    SCREEN *newSP;

    T((T_CALLED("set_term(%p)"), (void *) screenp));

    _nc_lock_global(curses);

    oldSP = CURRENT_SCREEN;
    _nc_set_screen(screenp);
    newSP = screenp;

    if (newSP != 0) {
	TINFO_SET_CURTERM(newSP, newSP->_term);
#if !USE_REENTRANT
	curscr = CurScreen(newSP);
	newscr = NewScreen(newSP);
	stdscr = StdScreen(newSP);
	COLORS = newSP->_color_count;
	COLOR_PAIRS = newSP->_pair_count;
#endif
    } else {
	TINFO_SET_CURTERM(oldSP, 0);
#if !USE_REENTRANT
	curscr = 0;
	newscr = 0;
	stdscr = 0;
	COLORS = 0;
	COLOR_PAIRS = 0;
#endif
    }

    _nc_unlock_global(curses);

    T((T_RETURN("%p"), (void *) oldSP));
    return (oldSP);
}
Пример #20
0
delwin(WINDOW *win)
{
    int result = ERR;

    T((T_CALLED("delwin(%p)"), win));

    if (_nc_try_global(curses) == 0) {
	if (win == 0
	    || cannot_delete(win)) {
	    result = ERR;
	} else {

	    if (win->_flags & _SUBWIN)
		touchwin(win->_parent);
	    else if (curscr != 0)
		touchwin(curscr);

	    result = _nc_freewin(win);
	}
	_nc_unlock_global(curses);
    }
    returnCode(result);
}
Пример #21
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));
}
Пример #22
0
newterm(NCURSES_CONST char *name, FILE *ofp, FILE *ifp)
{
    int value;
    int errret;
    SCREEN *current;
    SCREEN *result = 0;
    TERMINAL *its_term;

    START_TRACE();
    T((T_CALLED("newterm(\"%s\",%p,%p)"), name, ofp, ifp));

    _nc_init_pthreads();
    _nc_lock_global(curses);

    current = SP;
    its_term = (SP ? SP->_term : 0);

    /* this loads the capability entry, then sets LINES and COLS */
    if (setupterm(name, fileno(ofp), &errret) != ERR) {
	int slk_format = _nc_globals.slk_format;

	/*
	 * This actually allocates the screen structure, and saves the original
	 * terminal settings.
	 */
	_nc_set_screen(0);

	/* allow user to set maximum escape delay from the environment */
	if ((value = _nc_getenv_num("ESCDELAY")) >= 0) {
	    set_escdelay(value);
	}

	if (_nc_setupscreen(LINES,
			    COLS,
			    ofp,
			    _nc_prescreen.filter_mode,
			    slk_format) == ERR) {
	    _nc_set_screen(current);
	    result = 0;
	} else {
	    assert(SP != 0);
	    /*
	     * In setupterm() we did a set_curterm(), but it was before we set
	     * SP.  So the "current" screen's terminal pointer was overwritten
	     * with a different terminal.  Later, in _nc_setupscreen(), we set
	     * SP and the terminal pointer in the new screen.
	     *
	     * Restore the terminal-pointer for the pre-existing screen, if
	     * any.
	     */
	    if (current)
		current->_term = its_term;

	    /* if the terminal type has real soft labels, set those up */
	    if (slk_format && num_labels > 0 && SLK_STDFMT(slk_format))
		_nc_slk_initialize(stdscr, COLS);

	    SP->_ifd = fileno(ifp);
	    typeahead(fileno(ifp));
#ifdef TERMIOS
	    SP->_use_meta = ((cur_term->Ottyb.c_cflag & CSIZE) == CS8 &&
			     !(cur_term->Ottyb.c_iflag & ISTRIP));
#else
	    SP->_use_meta = FALSE;
#endif
	    SP->_endwin = FALSE;

	    /*
	     * Check whether we can optimize scrolling under dumb terminals in
	     * case we do not have any of these capabilities, scrolling
	     * optimization will be useless.
	     */
	    SP->_scrolling = ((scroll_forward && scroll_reverse) ||
			      ((parm_rindex ||
				parm_insert_line ||
				insert_line) &&
			       (parm_index ||
				parm_delete_line ||
				delete_line)));

	    baudrate();		/* sets a field in the SP structure */

	    SP->_keytry = 0;

	    /*
	     * Check for mismatched graphic-rendition capabilities.  Most SVr4
	     * terminfo trees contain entries that have rmul or rmso equated to
	     * sgr0 (Solaris curses copes with those entries).  We do this only
	     * for curses, since many termcap applications assume that
	     * smso/rmso and smul/rmul are paired, and will not function
	     * properly if we remove rmso or rmul.  Curses applications
	     * shouldn't be looking at this detail.
	     */
#define SGR0_TEST(mode) (mode != 0) && (exit_attribute_mode == 0 || strcmp(mode, exit_attribute_mode))
	    SP->_use_rmso = SGR0_TEST(exit_standout_mode);
	    SP->_use_rmul = SGR0_TEST(exit_underline_mode);

	    /* compute movement costs so we can do better move optimization */
	    _nc_mvcur_init();

	    /* initialize terminal to a sane state */
	    _nc_screen_init();

	    /* Initialize the terminal line settings. */
	    _nc_initscr();

	    _nc_signal_handler(TRUE);

	    result = SP;
	}
    }
    _nc_unlock_global(curses);
    returnSP(result);
}
Пример #23
0
copywin(const WINDOW *src, WINDOW *dst,
	int sminrow, int smincol,
	int dminrow, int dmincol,
	int dmaxrow, int dmaxcol,
	int over)
{
    int rc = ERR;
    int sx, sy, dx, dy;
    bool touched;
    attr_t bk;
    attr_t mask;

    T((T_CALLED("copywin(%p, %p, %d, %d, %d, %d, %d, %d, %d)"),
       src, dst, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, over));

    if (src && dst) {
	_nc_lock_global(curses);

	bk = AttrOf(dst->_nc_bkgd);
	mask = ~(attr_t) ((bk & A_COLOR) ? A_COLOR : 0);

	/* make sure rectangle exists in source */
	if ((sminrow + dmaxrow - dminrow) <= (src->_maxy + 1) &&
	    (smincol + dmaxcol - dmincol) <= (src->_maxx + 1)) {

	    T(("rectangle exists in source"));

	    /* make sure rectangle fits in destination */
	    if (dmaxrow <= dst->_maxy && dmaxcol <= dst->_maxx) {

		T(("rectangle fits in destination"));

		for (dy = dminrow, sy = sminrow;
		     dy <= dmaxrow;
		     sy++, dy++) {

		    touched = FALSE;
		    for (dx = dmincol, sx = smincol;
			 dx <= dmaxcol;
			 sx++, dx++) {
			if (over) {
			    if ((CharOf(src->_line[sy].text[sx]) != L(' ')) &&
				(!CharEq(dst->_line[dy].text[dx],
					 src->_line[sy].text[sx]))) {
				dst->_line[dy].text[dx] =
				    src->_line[sy].text[sx];
				SetAttr(dst->_line[dy].text[dx],
					((AttrOf(src->_line[sy].text[sx]) &
					  mask) | bk));
				touched = TRUE;
			    }
			} else {
			    if (!CharEq(dst->_line[dy].text[dx],
					src->_line[sy].text[sx])) {
				dst->_line[dy].text[dx] =
				    src->_line[sy].text[sx];
				touched = TRUE;
			    }
			}
		    }
		    if (touched) {
			touchline(dst, dminrow, (dmaxrow - dminrow + 1));
		    }
		}
		T(("finished copywin"));
		rc = OK;
	    }
	}
	_nc_unlock_global(curses);
    }
    returnCode(rc);
}
Пример #24
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);
}
Пример #25
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;
}
Пример #26
0
wget_wch(WINDOW *win, wint_t *result)
{
    SCREEN *sp;
    int code;
    char buffer[(MB_LEN_MAX * 9) + 1];	/* allow some redundant shifts */
    int status;
    size_t count = 0;
    int value = 0;
    wchar_t wch;
#ifndef state_unused
    mbstate_t state;
#endif

    T((T_CALLED("wget_wch(%p)"), (void *) win));

    /*
     * We can get a stream of single-byte characters and KEY_xxx codes from
     * _nc_wgetch(), while we want to return a wide character or KEY_xxx code.
     */
    _nc_lock_global(curses);
    sp = _nc_screen_of(win);
    if (sp != 0) {
	for (;;) {
	    T(("reading %d of %d", (int) count + 1, (int) sizeof(buffer)));
	    code = _nc_wgetch(win, &value, TRUE EVENTLIST_2nd((_nc_eventlist
							       *) 0));
	    if (code == ERR) {
		break;
	    } else if (code == KEY_CODE_YES) {
		/*
		 * If we were processing an incomplete multibyte character,
		 * return an error since we have a KEY_xxx code which
		 * interrupts it.  For some cases, we could improve this by
		 * writing a new version of lib_getch.c(!), but it is not clear
		 * whether the improvement would be worth the effort.
		 */
		if (count != 0) {
		    safe_ungetch(SP_PARM, value);
		    code = ERR;
		}
		break;
	    } else if (count + 1 >= sizeof(buffer)) {
		safe_ungetch(SP_PARM, value);
		code = ERR;
		break;
	    } else {
		buffer[count++] = (char) UChar(value);
		reset_mbytes(state);
		status = count_mbytes(buffer, count, state);
		if (status >= 0) {
		    reset_mbytes(state);
		    if (check_mbytes(wch, buffer, count, state) != status) {
			code = ERR;	/* the two calls should match */
			safe_ungetch(SP_PARM, value);
		    }
		    value = wch;
		    break;
		}
	    }
	}
    } else {
	code = ERR;
    }
    *result = (wint_t) value;
    _nc_unlock_global(curses);
    T(("result %#o", value));
    returnCode(code);
}
Пример #27
0
delscreen(SCREEN *sp)
{
    int i;

    T((T_CALLED("delscreen(%p)"), (void *) sp));

    _nc_lock_global(curses);
    if (delink_screen(sp)) {
#ifdef USE_SP_RIPOFF
	ripoff_t *rop;
	if (safe_ripoff_sp && safe_ripoff_sp != safe_ripoff_stack) {
	    for (rop = safe_ripoff_stack;
		 rop != safe_ripoff_sp && (rop - safe_ripoff_stack) < N_RIPS;
		 rop++) {
		if (rop->win) {
		    (void) delwin(rop->win);
		    rop->win = 0;
		}
	    }
	}
#endif

	(void) _nc_freewin(CurScreen(sp));
	(void) _nc_freewin(NewScreen(sp));
	(void) _nc_freewin(StdScreen(sp));

	if (sp->_slk != 0) {
	    if (sp->_slk->ent != 0) {
		for (i = 0; i < sp->_slk->labcnt; ++i) {
		    FreeIfNeeded(sp->_slk->ent[i].ent_text);
		    FreeIfNeeded(sp->_slk->ent[i].form_text);
		}
		free(sp->_slk->ent);
	    }
	    free(sp->_slk);
	    sp->_slk = 0;
	}

	_nc_free_keytry(sp->_keytry);
	sp->_keytry = 0;

	_nc_free_keytry(sp->_key_ok);
	sp->_key_ok = 0;

	FreeIfNeeded(sp->_current_attr);

	FreeIfNeeded(sp->_color_table);
	FreeIfNeeded(sp->_color_pairs);

	FreeIfNeeded(sp->oldhash);
	FreeIfNeeded(sp->newhash);
	FreeIfNeeded(sp->hashtab);

	FreeIfNeeded(sp->_acs_map);
	FreeIfNeeded(sp->_screen_acs_map);

	NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
	NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx sp->_term);
	free(sp);

	/*
	 * If this was the current screen, reset everything that the
	 * application might try to use (except cur_term, which may have
	 * multiple references in different screens).
	 */
	if (sp == CURRENT_SCREEN) {
#if !USE_REENTRANT
	    curscr = 0;
	    newscr = 0;
	    stdscr = 0;
	    COLORS = 0;
	    COLOR_PAIRS = 0;
#endif
	    _nc_set_screen(0);
	}
    }
    _nc_unlock_global(curses);

    returnVoid;
}
Пример #28
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 *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);
}
Пример #29
0
dupwin(WINDOW *win)
/* make an exact duplicate of the given window */
{
    WINDOW *nwin = 0;
    size_t linesize;
    int i;

    T((T_CALLED("dupwin(%p)"), (void *) win));

    if (win != 0) {
#if NCURSES_SP_FUNCS
	SCREEN *sp = _nc_screen_of(win);
#endif
	_nc_lock_global(curses);
	if (win->_flags & _ISPAD) {
	    nwin = NCURSES_SP_NAME(newpad) (NCURSES_SP_ARGx
					    win->_maxy + 1,
					    win->_maxx + 1);
	} else {
	    nwin = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
					    win->_maxy + 1,
					    win->_maxx + 1,
					    win->_begy,
					    win->_begx);
	}

	if (nwin != 0) {

	    nwin->_curx = win->_curx;
	    nwin->_cury = win->_cury;
	    nwin->_maxy = win->_maxy;
	    nwin->_maxx = win->_maxx;
	    nwin->_begy = win->_begy;
	    nwin->_begx = win->_begx;
	    nwin->_yoffset = win->_yoffset;

	    nwin->_flags = win->_flags & ~_SUBWIN;
	    /* Due to the use of newwin(), the clone is not a subwindow.
	     * The text is really copied into the clone.
	     */

	    WINDOW_ATTRS(nwin) = WINDOW_ATTRS(win);
	    nwin->_nc_bkgd = win->_nc_bkgd;

	    nwin->_notimeout = win->_notimeout;
	    nwin->_clear = win->_clear;
	    nwin->_leaveok = win->_leaveok;
	    nwin->_scroll = win->_scroll;
	    nwin->_idlok = win->_idlok;
	    nwin->_idcok = win->_idcok;
	    nwin->_immed = win->_immed;
	    nwin->_sync = win->_sync;
	    nwin->_use_keypad = win->_use_keypad;
	    nwin->_delay = win->_delay;

	    nwin->_parx = 0;
	    nwin->_pary = 0;
	    nwin->_parent = (WINDOW *) 0;
	    /* See above: the clone isn't a subwindow! */

	    nwin->_regtop = win->_regtop;
	    nwin->_regbottom = win->_regbottom;

	    if (win->_flags & _ISPAD)
		nwin->_pad = win->_pad;

	    linesize = (unsigned) (win->_maxx + 1) * sizeof(NCURSES_CH_T);
	    for (i = 0; i <= nwin->_maxy; i++) {
		memcpy(nwin->_line[i].text, win->_line[i].text, linesize);
		nwin->_line[i].firstchar = win->_line[i].firstchar;
		nwin->_line[i].lastchar = win->_line[i].lastchar;
	    }
	}
	_nc_unlock_global(curses);
    }
    returnWin(nwin);
}
delscreen(SCREEN *sp)
{
    int i;

    T((T_CALLED("delscreen(%p)"), sp));

    _nc_lock_global(curses);
    if (delink_screen(sp)) {

	(void) _nc_freewin(sp->_curscr);
	(void) _nc_freewin(sp->_newscr);
	(void) _nc_freewin(sp->_stdscr);

	if (sp->_slk != 0) {
	    if (sp->_slk->ent != 0) {
		for (i = 0; i < sp->_slk->labcnt; ++i) {
		    FreeIfNeeded(sp->_slk->ent[i].ent_text);
		    FreeIfNeeded(sp->_slk->ent[i].form_text);
		}
		free(sp->_slk->ent);
	    }
	    free(sp->_slk);
	    sp->_slk = 0;
	}

	_nc_free_keytry(sp->_keytry);
	sp->_keytry = 0;

	_nc_free_keytry(sp->_key_ok);
	sp->_key_ok = 0;

	FreeIfNeeded(sp->_current_attr);

	FreeIfNeeded(sp->_color_table);
	FreeIfNeeded(sp->_color_pairs);

	FreeIfNeeded(sp->oldhash);
	FreeIfNeeded(sp->newhash);
	FreeIfNeeded(sp->hashtab);

	FreeIfNeeded(sp->_acs_map);
	FreeIfNeeded(sp->_screen_acs_map);

	/*
	 * If the associated output stream has been closed, we can discard the
	 * set-buffer.  Limit the error check to EBADF, since fflush may fail
	 * for other reasons than trying to operate upon a closed stream.
	 */
	if (sp->_ofp != 0
	    && sp->_setbuf != 0
	    && fflush(sp->_ofp) != 0
	    && errno == EBADF) {
	    free(sp->_setbuf);
	}

	del_curterm(sp->_term);
	free(sp);

	/*
	 * If this was the current screen, reset everything that the
	 * application might try to use (except cur_term, which may have
	 * multiple references in different screens).
	 */
	if (sp == SP) {
#if !USE_REENTRANT
	    curscr = 0;
	    newscr = 0;
	    stdscr = 0;
	    COLORS = 0;
	    COLOR_PAIRS = 0;
#endif
	    _nc_set_screen(0);
	}
    }
    _nc_unlock_global(curses);

    returnVoid;
}