/* This file is term.c. It's written in C and uses Tk. */ #include #include #include #include Tcl_Interp *interp; Tk_Window mainWindow; const int height = 24; const int width = 80; void term_construct(void) { static int n = 0; /* how many terminals have been constructed */ const char background = ' '; char buffer[12]; interp = Tcl_CreateInterp(); mainWindow = Tk_CreateMainWindow(interp, getenv("DISPLAY"), "game", "Game"); if (mainWindow == NULL) { fprintf(stderr, "%s\n", interp->result); exit(1); } sprintf(buffer, "%d", n++); if (Tcl_SetVar(interp, "n", buffer, TCL_LEAVE_ERR_MSG) == NULL) { fprintf(stderr, "%s\n", interp->result); exit(2); } sprintf(buffer, "%d", height); if (Tcl_SetVar(interp, "height", buffer, TCL_LEAVE_ERR_MSG) == NULL) { fprintf(stderr, "%s\n", interp->result); exit(3); } sprintf(buffer, "%d", width); if (Tcl_SetVar(interp, "width", buffer, TCL_LEAVE_ERR_MSG) == NULL) { fprintf(stderr, "%s\n", interp->result); exit(4); } sprintf(buffer, "%c", background); if (Tcl_SetVar(interp, "background", buffer, TCL_LEAVE_ERR_MSG) == NULL) { fprintf(stderr, "%s\n", interp->result); exit(5); } if (Tcl_Eval(interp, "toplevel .toplevel$n\n" "text .toplevel$n.text" " -height $height" " -width $width" " -background White" " -foreground Black" " -font -adobe-courier-medium-r-normal--12-*-*-m-*-*-*\n" "#Must fill the text widget with lines of characters." "set line \"\"\n" "for {set i 0} {$i < $width} {incr i} {" "append line $background" "}\n" "append line \"\n\"\n" "for {set i 1} {$i <= $height} {incr i} {" ".toplevel$n.text insert $i.0 $line" "}\n" "#queue of keystrokes, used by term_key\n" "set queue \"\"\n" "bind .toplevel$n.text {append queue \"\%K\"}\n" "focus .toplevel$n.text\n" "wm title .toplevel$n \"game\"\n" "wm withdraw .\n" "pack .toplevel$n.text\n" "update\n" ) != TCL_OK) { fprintf(stderr, "%s\n", interp->result); exit(6); } } void term_destruct(void) { /* If the user has not already destroyed the main window by clicking on its go-away box, */ if (tk_NumMainWindows == 1) { if (Tcl_Eval(interp, "destroy .toplevel$n.text .toplevel$n\n") != TCL_OK) { fprintf(stderr, "%s\n", interp->result); exit(7); } Tk_DestroyWindow(mainWindow); } Tcl_DeleteInterp(interp); } unsigned term_xmax(void) {return width;} unsigned term_ymax(void) {return height;} int term_get(unsigned x, unsigned y) { char buffer[256]; /* The line numbers in a text widget are 1-based. The character on each line are 0-based. */ sprintf(buffer, ".toplevel$n.text get %d.%d\n", y + 1, x); if (Tcl_Eval(interp, buffer) != TCL_OK) { fprintf(stderr, "%s\n", interp->result); exit(8); } return interp->result[0]; } void term_put(unsigned x, unsigned y, char c) { char buffer[256]; if (x < 0 || x > term_xmax() || y < 0 || y > term_ymax()) { fprintf(stderr, "out of bounds (%d, %d)\n", x, y); exit(9); } /* The line numbers in a text widget are 1-based. The character on each line are 0-based. */ sprintf(buffer, ".toplevel$n.text delete %d.%d\n" ".toplevel$n.text insert %d.%d \"%s%c\"\n" "update\n", y + 1, x, y + 1, x, c == '"' ? "\\" : "", c); if (Tcl_Eval(interp, buffer) != TCL_OK) { fprintf(stderr, "%s\n", interp->result); exit(10); } } /* Wrap around, if necessary. */ void term_puts(unsigned x, unsigned y, const char *s) { const int number_of_rows = term_xmax(); const int number_of_columns = term_ymax(); const int len = strlen(s); int i; for (i = 0; i < len; ++i) { const int zero_based_x = x + i; const int j = zero_based_x / number_of_columns; const int zero_based_y = y + j; term_put( zero_based_x % number_of_columns, zero_based_y % number_of_rows, s[i]); } } int term_key(void) { char *p; char c; /* Process all outstanding events, including keystrokes. */ while (Tk_DoOneEvent(TK_ALL_EVENTS | TK_DONT_WAIT) != 0) { if (tk_NumMainWindows != 1) { return EOF; } } /* Remove and return the first character in the value of queue. */ if ((p = Tcl_GetVar(interp, "queue", 0)) == NULL) { fprintf(stderr, "the variable queue doesn't exist"); exit(12); } if ((c = p[0]) != '\0' && Tcl_SetVar(interp, "queue", p + 1, TCL_LEAVE_ERR_MSG) == NULL) { fprintf(stderr, "%s\n", interp->result); exit(13); } return c; } void term_wait(int milliseconds) { Tk_Sleep(milliseconds); } void term_beep(void) { if (Tcl_Eval(interp, "puts stderr \\a\n") != TCL_OK) { fprintf(stderr, "%s\n", interp->result); exit(14); } }