1cc2 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BW 2 Display *d; Window w; GC tgc, fgc; Pixmap wsave, csave; Atom wm_protocols, wm_delete_window; int cols = 80; int lines = 25; int pheight = 66; int wx = 0, wy = 0, ww, wh; char *fg = "#acaaac"; char *bg = "black"; char *font = "-misc-fixed-medium-r-normal--20-*-iso8859-1"; int cw, ch, asc, desc; int x, y; char *shell; int ptyfd, xfd; int glass = 0; static void wrestore() { XCopyArea(d, wsave, w, tgc, 0, 0, ww + (BW*2), wh + (BW*2), 0, 0); } static void cur(int state) { static int first = 1; if (state) { XCopyArea(d, w, csave, tgc, x, y - asc, cw, ch, 0, 0); XFillRectangle(d, w, tgc, x, y - asc, cw, ch); XCopyArea(d, wsave, csave, tgc, x, y - asc, cw, ch, 0, 0); XFillRectangle(d, wsave, tgc, x, y - asc, cw, ch); first = 0; } else { if (! first) { XCopyArea(d, csave, w, tgc, 0, 0, cw, ch, x, y - asc); XCopyArea(d, csave, wsave, tgc, 0, 0, cw, ch, x, y - asc); } } } static void feed(void) { XCopyArea(d, w, w, tgc, BW, BW + ch, ww, wh - ch, BW, BW); XFillRectangle(d, w, fgc, BW, BW + wh - ch, ww, ch); XCopyArea(d, wsave, wsave, tgc, BW, BW + ch, ww, wh - ch, BW, BW); XFillRectangle(d, wsave, fgc, BW, BW + wh - ch, ww, ch); } static int read_pty(void) { static char lbuf[128]; static int llen = 0; static int line = 0; char buf[4096]; int i, j, n; unsigned char c; #define print() if (glass) { \ XDrawImageString(d, w, tgc, x, y, lbuf, llen); \ XDrawImageString(d, wsave, tgc, x, y, lbuf, llen); \ } else { \ XDrawString(d, w, tgc, x, y, lbuf, llen); \ XDrawString(d, wsave, tgc, x, y, lbuf, llen); \ } if (! (n = read(ptyfd, buf, 4096))) return n; if (glass) cur(0); for (i = 0; i < n; i++) { c = buf[i]; switch (c) { case 8: if (llen) { print(); } x += (llen * cw) - cw; llen = 0; break; case 10: feed(); if (++line == pheight) line = 0; break; case 12: if (llen) { print(); x += llen * cw; llen = 0; } for (j = 0; j < (pheight - line); j++) feed(); line = 0; break; case 13: if (llen) { print(); } x = BW; llen = 0; break; default: if ((c < 32) || ((c > 126) && (c < 160))) continue; if ((x + (llen * cw)) == BW + ww) { print(); feed(); x = BW; llen = 0; } *(lbuf + llen++) = c; } } if (llen) { print(); x += (llen * cw); llen = 0; } if (glass) cur(1); return n; } static void write_pty(XEvent *e) { KeySym ks; unsigned char c; XLookupString((XKeyEvent *)e, &c, 1, &ks, NULL); if (c != 0) write(ptyfd, &c, 1); } static void usage(char *name) { fprintf(stderr, "usage: %s [-x xpos] [-y ypos] [-c columns] [-l lines] [-f font]\n", name); exit(1); } static void init(int argc, char **argv) { XFontStruct *fi; XColor fgcol, bgcol; XClassHint *chint; XSizeHints *shints; char *name; int pid; int c; if ((name = strrchr(argv[0], '/'))) name++; else name = argv[0]; if (! strcmp(name, "ttyemu")) { fprintf(stderr, "Error: wrong invocation name\n"); exit(1); } glass = ! strcmp(name, "glasstty"); while ((c = getopt(argc, argv, ":x:y:c:l:f:")) != -1) { switch (c) { case 'x': wx = atoi(optarg); break; case 'y': wy = atoi(optarg); break; case 'c': cols = atoi(optarg); break; case 'l': lines = atoi(optarg); break; case 'f': font = (char *)malloc(strlen(optarg) + 1); strcpy(font, optarg); break; case ':': case '?': default: usage(name); } } if (! (pid = forkpty(&ptyfd, NULL, NULL, NULL))) { char *shell, *tail, shminus[80]; setenv(glass ? "GLASSTTY" : "HCTTY", "1", 1); if (! (shell = getenv("SHELL"))) shell = "/bin/sh"; tail = strrchr(shell, '/') + 1; sprintf(shminus, "-%s", tail); execl(shell, shminus, (char *)NULL); perror("execl"); _exit(1); } else if (pid < 0) { perror("fork"); exit(1); } setlocale(LC_ALL, ""); if (! (d = XOpenDisplay(NULL))) { fprintf(stderr, "Error opening display!\n"); exit(1); } xfd = ConnectionNumber(d); if (! (fi = XLoadQueryFont(d, font))) { fprintf(stderr, "Error loading font!\n"); exit(1); } cw = fi->per_char[32].width; ch = fi->ascent + fi->descent; XAllocNamedColor(d, DefaultColormap(d, 0), fg, &fgcol, &fgcol); XAllocNamedColor(d, DefaultColormap(d, 0), bg, &bgcol, &bgcol); ww = cw * cols; wh = ch * lines; if (! (w = XCreateSimpleWindow(d, DefaultRootWindow(d), wx, wy, ww + (BW*2), wh + (BW*2), 0, bgcol.pixel, bgcol.pixel)) ) { printf("Error creating window!\n"); exit(1); } XSelectInput(d, w, KeyPressMask|ExposureMask); chint = XAllocClassHint(); chint->res_name = (glass ? "glasstty" : "hctty"); chint->res_class = (glass ? "Glasstty" : "Hctty"); XSetClassHint(d, w, chint); XStoreName(d, w, glass ? "Glass TTY" : "Hardcopy TTY"); shints = XAllocSizeHints(); shints->x = wx; shints->y = wy; shints->flags = USPosition; XSetWMNormalHints(d, w, shints); wm_protocols = XInternAtom(d, "WM_PROTOCOLS", False); wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False); XSetWMProtocols(d, w, &wm_delete_window, 1); tgc = XCreateGC(d, w, 0, NULL); XSetForeground(d, tgc, fgcol.pixel); XSetBackground(d, tgc, bgcol.pixel); XSetFont(d, tgc, fi->fid); fgc = XCreateGC(d, w, 0, NULL); XSetForeground(d, fgc, bgcol.pixel); wsave = XCreatePixmap(d, w, ww + (BW*2), wh + (BW*2), DefaultDepth(d, 0)); XFillRectangle(d, wsave, fgc, 0, 0, ww + (BW*2), wh + (BW*2)); if (glass) csave = XCreatePixmap(d, w, cw, ch, DefaultDepth(d, 0)); x = BW; y = BW + wh - fi->descent; asc = fi->ascent; desc = fi->descent; XMapWindow(d, w); } static void quit() { XDestroyWindow(d, w); XCloseDisplay(d); exit(0); } int main(int argc, char **argv) { init(argc, argv); for (;;) { XEvent e; fd_set io_set; struct timeval timeout; while(XPending(d)) { XNextEvent(d, &e); switch (e.type) { case Expose: if (! e.xexpose.count) wrestore(); break; case KeyPress: write_pty(&e); break; case ClientMessage: if (e.xclient.message_type == wm_protocols && e.xclient.data.l[0] == wm_delete_window) quit(); break; } } FD_ZERO(&io_set); FD_SET(ptyfd, &io_set); FD_SET(xfd, &io_set); timeout.tv_sec = 0; timeout.tv_usec = 5000; if (select(xfd + 1, &io_set, NULL, NULL, &timeout) <= 0) continue; if (FD_ISSET(ptyfd, &io_set)) { if (! read_pty()) quit(); } } } . 0