📄 window.c
字号:
/* * window.c Very portable window routines. * Currently this code is used in _both_ the BBS * system and minicom. * * This file is part of the minicom communications package, * Copyright 1991-1996 Miquel van Smoorenburg. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * 01.01.98 dickey@clark.net: fix for a history window closing bug * fmg 8/20/97: Added support for Search of History Buffer */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "rcsid.h"RCSID("$Id: window.c,v 1.18 2005/11/06 19:20:57 al-guest Exp $")#include <limits.h>#include <stdarg.h>#include <wchar.h>#include "port.h"#include "minicom.h"#include "intl.h"/* Status line code on/off. */#define ST_LINE 1/* fmg 2/20/94 macros - Length of Macros */#ifndef MAC_LEN#define MAC_LEN 257#endif/* Don't want to include all header stuff for three prototypes from sysdep.c */#ifdef __STDC__ int setcbreak(int); int wxgetch(void); void getrowcols(int *rows, int *cols);#else int setcbreak(); int wxgetch(); void getrowcols();#endif#ifndef BBS#include "config.h"#endif#define BUFFERSIZE 2048#define swap(x, y) { int d = (x); (x) = (y); (y) = d; }/* Terminal capabilities */static const char *CM, *IS, *RS, *AC, *EA;static const char *ME, *SE, *UE, *AE;static const char *AS, *MB, *MD, *MR, *SO, *US;static const char *CE, *Al, *Dl, *AL, *DL;static const char *CS, *SF, *SR, *VB, *BL;static const char *VE, *VI, *KS, *KE;static const char *CD, *CL, *IC, *DC;static const char *CR, *NL;#ifdef ST_LINEstatic const char *TS, *FS, *DS;#endif/* Special characters */static char D_UL;static char D_HOR;static char D_UR;static char D_LL;static char D_VER;static char D_LR;static char S_UL;static char S_HOR;static char S_UR;static char S_LL;static char S_VER;static char S_LR;static char _bufstart[BUFFERSIZE];static char *_bufpos = _bufstart;static char *_buffend;static ELM *gmap;static char curattr = -1;static char curcolor = -1;static int curx = -1;static int cury = -1;static int _intern = 0;static int _curstype = CNORMAL;static int _has_am = 0;static int _mv_standout = 0;static ELM oldc;static int sflag = 0;/* * Smooth is only defined for slow machines running Minicom. * With this defined, Minicom will buffer only per-line * and the output will look much less 'jerky'. (I hope :-) */#ifdef SMOOTHstatic WIN *curwin = NULL;WIN *us;#endifint useattr = 1;int dirflush = 1;int LINES, COLS;int usecolor = 0;WIN *stdwin;/* * The following is an external pointer to the termcap info. * If it's NOT zero then the main program has already * read the termcap for us. No sense in doing it twice. */char *_tptr = NULL;int screen_ibmpc = 0;int screen_iso = 0;int w_init = 0;int use_status = 0; /* Turned on in main() *//* Standard vt100 map (ac cpability) */static const char *def_ac = "+\273,\253aaffggjjkkllmmnnooqqssttuuvvwwxx";#ifdef DEBUG/* * Debug to stdout */int debug(char *s, ...){ char lala[80]; va_list ap; va_start(ap, s); vsnprintf(lala, sizeof(lala), s, ap); va_end(ap); write(2, lala, strlen(lala)); return 0;}#endif/* ===== Low level routines ===== *//* * Flush the screen buffer */void wflush(void){ int todo, done; todo = _bufpos - _bufstart; _bufpos = _bufstart; while (todo > 0) { done = write(1, _bufpos, todo); if (done > 0) { todo -= done; _bufpos += done; } if (done < 0 && errno != EINTR) break; } _bufpos = _bufstart;}/* * Output a raw character to the screen */static int outchar(int c){ *_bufpos++ = c; if (_bufpos >= _buffend) wflush();#if defined(SMOOTH) if (curwin == us && (c == '\n' || c == '\r')) wflush();#endif return 0;}/* * Output a raw string to the screen. */static void outstr(const char *s){ tputs(s, 1, outchar);}/* * Turn off all attributes */static void _attroff(void){ if (ME != NULL) outstr(ME); else { if (SE != NULL) outstr(SE); if (UE != NULL) outstr(UE); } if (AE != NULL) outstr(AE);}/* * Turn some attributes on */static void _attron(char attr){ if (!usecolor || (attr & XA_REVERSE) == 0) { /* Reverse standout does not look too good.. */ if (attr & XA_BOLD && MD != NULL) outstr(MD); if (attr & XA_STANDOUT && SO != NULL) outstr(SO); if (attr & XA_UNDERLINE && US != NULL) outstr(US); } if (attr & XA_REVERSE && MR != NULL) outstr(MR); if (attr & XA_BLINK && MB != NULL) outstr(MB); if (attr & XA_ALTCHARSET && AS != NULL) outstr(AS);}/* * Set the colors */static void _colson(char color){ char buf[12]; sprintf(buf, "\033[%d;%dm", COLFG(color) + 30, COLBG(color) + 40); outstr(buf);}/* * Set global attributes, if different. */static void _setattr(char attr, char color){ if (!useattr) return; if (!usecolor) { curcolor = color; if (attr == curattr) return; curattr = attr; _attroff(); _attron(attr); return; } if (attr == curattr && color == curcolor) return; _attroff(); _colson(color); _attron(attr); curattr = attr; curcolor = color;}/* * Goto (x, y) in stdwin */static void _gotoxy(int x, int y){ int oldattr = -1;#ifdef ST_LINE int tmp; /* Sanity check. */ if (x >= COLS || y > LINES || (x == curx && y == cury)) return; if (use_status) { /* Leaving status line? */ if (cury == LINES && y < cury) { outstr(FS); /* Re-set attributes. */ tmp = curattr; curattr = -1; _setattr(tmp, curcolor); outstr(tgoto(CM, x, y)); curx = x; cury = y; return; } /* Writing on status line? */ else if (y == LINES) { /* From normal screen? */ if (cury < y) { outstr(tgoto(TS, x, x)); curx = x; cury = y; /* Set the right attributes. */ tmp = curattr; curattr = -1; _setattr(tmp, curcolor); return; } } }#else /* Sanity check. */ if (x >= COLS || y >= LINES || (x == curx && y == cury)) {# if 0 if (x >= COLS || y >= LINES) fprintf(stderr, "OOPS: (x, y) == (%d, %d)\n", COLS, LINES);# endif return; }#endif if (!_mv_standout && curattr != XA_NORMAL) { oldattr = curattr; _setattr(XA_NORMAL, curcolor); } if (CR != NULL && y == cury && x == 0) outstr(CR);#if 0 /* Hmm, sometimes NL only works in the first column */ else if (NL != NULL && x == curx && y == cury + 1) outstr(NL);#else else if (NL != NULL && x == 0 && x == curx && y == cury + 1) outstr(NL);#endif else if (BC != NULL && y == cury && x == curx - 1) outstr(BC); else outstr(tgoto(CM, x, y)); curx = x; cury = y; if (oldattr != -1) _setattr(oldattr, curcolor);}/* * Write a character in stdwin at x, y with attr & color * 'doit' can be -1: only write to screen, not to memory * 0: only write to memory, not to screen * 1: write to both screen and memory */static void _write(wchar_t c, int doit, int x, int y, char attr, char color){ ELM *e; /* If the terminal has automatic margins, we can't write to the * last line, last character. After scrolling, this "invisible" * character is automatically restored. */ if (_has_am && y >= LINES - 1 && x >= COLS - 1) { doit = 0; sflag = 1; oldc.value = c; oldc.attr = attr; oldc.color = color; }#ifdef ST_LINE if (x < COLS && y <= LINES)#else if (x < COLS && y < LINES)#endif { if (doit != 0) { static int x0 = -1, y0 = -1, c0 = 0; static char attr0, color0; if (x!=x0+1 || y!=y0 || attr!=attr0 || color!=color0 || !(c0&128)) { _gotoxy(x, y); _setattr(attr, color); } x0 = x; y0 = y; attr0 = attr; color0 = color; c0 = c; if ((attr & XA_ALTCHARSET) != 0) outchar((char)c); else { char buf[MB_LEN_MAX]; size_t i, len; len = one_wctomb(buf, c); for (i = 0; i < (size_t)len; i++) outchar(buf[i]); } curx++; } if (doit >= 0) { e = &gmap[x + y * COLS]; e->value = c; e->attr = attr; e->color = color; } }}/* * Set cursor type. */static void _cursor(int type){ _curstype = type; if (type == CNORMAL && VE != NULL) outstr(VE); if (type == CNONE && VE != NULL && VI != NULL) outstr(VI);}/* ==== High level routines ==== */#if 0/* This code is functional, but not yet used. * It might be one day.... *//* * Resize a window */void wresize(WIN *win, int lines, int cols){ int x, y; ELM *oldmap, *newmap, *e, *n; if ((newmap = malloc((lines + 1) * cols * sizeof(ELM))) == NULL) return; if (win == stdwin) oldmap = gmap; else oldmap = win->map; for (y = 0; y < lines; y++) for (x = 0; x < cols; x++) { n = &newmap[y + x * cols]; if (x < win->xs && y < win->ys) { e = &oldmap[y + x * COLS]; n->value = e->value; n->color = e->color; n->attr = e->attr; } else { n->value = ' '; n->color = win->color; n->attr = win->attr; } } if (win->sy2 == win->y2) win->sy2 = win->y1 + lines - 1; win->y2 = win->y1 + lines - 1; win->ys = lines; win->xs = cols; free(oldmap); if (win == stdwin) { gmap = newmap; LINES = lines; COLS = cols; } else win->map = newmap;}#endif/* * Create a new window. */WIN *wopen(int x1, int y1, int x2, int y2, int border, int attr, int fg, int bg, int direct, int histlines, int doclr){ WIN *w; ELM *e; int bytes; int x, y; int color; int offs; int xattr;#ifdef SMOOTH curwin = NULL;#endif if ((w = malloc(sizeof(WIN))) == NULL) return w; offs = (border != BNONE); if (!screen_ibmpc && AS) xattr = attr | XA_ALTCHARSET; else xattr = attr; if (x1 > x2) swap(x1, x2); if (y1 > y2) swap(y1, y2); if (x1 < offs) x1 = offs; if (y1 < offs) y1 = offs;#if 0 if (x2 >= COLS - offs) x2 = COLS - offs - 1; if (y2 >= LINES - offs) y2 = LINES - offs - 1;#endif w->xs = x2 - x1 + 1; w->ys = y2 - y1 + 1; w->x1 = x1; w->x2 = x2; w->y1 = w->sy1 = y1; w->y2 = w->sy2 = y2; w->doscroll = 1; w->border = border; w->cursor = CNORMAL; w->attr = attr; w->autocr = 1; w->wrap = 1; color = w->color = COLATTR(fg, bg); w->curx = 0; w->cury = 0; w->o_curx = curx; w->o_cury = cury; w->o_attr = curattr; w->o_color = curcolor; w->o_cursor = _curstype; w->direct = direct; if (border != BNONE) { x1--; x2++; y1--; y2++; } /* Store whatever we are overlapping */ bytes = (y2 - y1 + 1) * (x2 - x1 + 1) * sizeof(ELM) + 100; if ((e = malloc(bytes)) == NULL) { free(w); return NULL; } w->map = e; /* How many bytes is one line */ bytes = (x2 - x1 + 1) * sizeof(ELM); /* Loop */ for (y = y1; y <= y2; y++) { memcpy(e, gmap + COLS * y + x1, bytes); e += (x2 - x1 + 1); } /* Do we want history? */ w->histline = w->histlines = 0; w->histbuf = NULL; if (histlines) { /* Reserve some memory. */ bytes = w->xs * histlines * sizeof(ELM); if ((w->histbuf = malloc(bytes)) == NULL) { free(w->map); free(w); return NULL; } w->histlines = histlines; /* Clear the history buf. */ e = w->histbuf; for (y = 0; y < w->xs * histlines; y++) { e->value = ' '; e->attr = attr; e->color = color; e++; } } /* And draw the window */ if (border) { _write(border == BSINGLE ? S_UL : D_UL, w->direct, x1, y1, xattr, color); for (x = x1 + 1; x < x2; x++) _write(border == BSINGLE ? S_HOR : D_HOR, w->direct, x, y1, xattr, color); _write(border == BSINGLE ? S_UR : D_UR, w->direct, x2, y1, xattr, color); for (y = y1 + 1; y < y2; y++) { _write(border == BSINGLE ? S_VER : D_VER, w->direct, x1, y, xattr, color); for (x = x1 + 1; x < x2; x++) _write(' ', w->direct, x, y, attr, color); _write(border == BSINGLE ? S_VER : D_VER, w->direct, x2, y, xattr, color); } _write(border == BSINGLE ? S_LL : D_LL, w->direct, x1, y2, xattr, color); for (x = x1 + 1; x < x2; x++) _write(border == BSINGLE ? S_HOR : D_HOR, w->direct, x, y2, xattr, color); _write(border == BSINGLE ? S_LR : D_LR, w->direct, x2, y2, xattr, color); if (w->direct) _gotoxy(x1 + 1, y1 + 1); } else if (doclr) winclr(w); wcursor(w, CNORMAL); if (w->direct) wflush(); return w;}/* * Close a window. */void wclose(WIN *win, int replace){ ELM *e; int x, y;#ifdef SMOOTH curwin = NULL;#endif if (!win) return; if (win == stdwin) { win_end(); return; } e = win->map; if (win->border) { win->x1--; win->x2++; win->y1--; win->y2++; } wcursor(win, win->o_cursor); if (replace) { for (y = win->y1; y <= win->y2; y++) { /* temporal way to avoid 'half-character' problem */ /* in multibyte characters such as Japanese -- from here */ ELM *g; g = gmap + (y * stdwin->xs); for (x = 0 ; x < win->x1; x++) { _write(g->value, 1, x, y, g->attr, g->color); g++; } /* to here */ for (x = win->x1; x <= win->x2; x++) { _write(e->value, 1, x, y, e->attr, e->color); e++; } } _gotoxy(win->o_curx, win->o_cury); _setattr(win->o_attr, win->o_color); } free(win->map); if (win->histbuf) free(win->histbuf); free(win); /* 1.1.98 dickey@clark.net */ wflush();}static int oldx, oldy;static int ocursor;/* * Clear screen & restore keyboard modes */void wleave(void){ oldx = curx; oldy = cury; ocursor = _curstype; setcbreak(0); /* Normal */ _gotoxy(0, LINES - 1); _setattr(XA_NORMAL, COLATTR(WHITE, BLACK)); _cursor(CNORMAL); if (CL != NULL) outstr(CL); else outstr("\n");#ifdef ST_LINE if (DS) outstr(DS);#endif if (KE != NULL) outstr(KE); if (RS != NULL) outstr(RS); wflush();}void wreturn(void){ int x, y; ELM *e;#ifdef SMOOTH curwin = NULL;#endif curattr = -1; curcolor = -1; setcbreak(1); /* Cbreak, no echo */ if (IS != NULL) outstr(IS); /* Initialization string */ if (EA != NULL) outstr(EA); /* Graphics init. */ if (KS != NULL) outstr(KS); /* Keypad mode */ _gotoxy(0, 0); _cursor(ocursor); e = gmap; for (y = 0; y <LINES; y++) { for(x = 0; x < COLS; x++) { _write(e->value, -1, x, y, e->attr, e->color); e++; } } _gotoxy(oldx, oldy);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -