diff --git a/console/Makefile.in b/console/Makefile.in index e959a3e9f6..3da9931a5e 100644 --- a/console/Makefile.in +++ b/console/Makefile.in @@ -9,7 +9,8 @@ C_SRCS = \ generic.c \ interface.c \ ncurses.c \ - tty.c + tty.c \ + xterm.c all: $(MODULE).o diff --git a/console/generic.c b/console/generic.c index ff2ea5e792..3a08834203 100644 --- a/console/generic.c +++ b/console/generic.c @@ -10,6 +10,7 @@ driver, it should make sure to perserve the old values. */ #include + #include "console.h" #include "config.h" #include "debug.h" diff --git a/console/interface.c b/console/interface.c index 8829e9526c..0e20550c7d 100644 --- a/console/interface.c +++ b/console/interface.c @@ -6,10 +6,16 @@ This could be done using a macro, but additional functionality may be provided here in the future. */ +#include + #include "windows.h" #include "console.h" #include "config.h" +/* I did this without realizing that CONSOLE_* was actually used by + the Win32 console driver. I will definately have to rename these + functions to avoid the name clash... */ + void CONSOLE_Write(char out, int fg_color, int bg_color, int attribute) { if (driver.write) @@ -22,6 +28,9 @@ void CONSOLE_Write(char out, int fg_color, int bg_color, int attribute) void CONSOLE_Init() { + /* Suitable defaults... */ + driver.console_out = stdout; + driver.console_in = stdin; /* Eventually, this will be a command-line choice */ #ifndef WINE_NCURSES TTY_Start(); @@ -30,6 +39,8 @@ void CONSOLE_Init() #endif GENERIC_Start(); + /*XTERM_Start();*/ + if (driver.init) driver.init(); } diff --git a/console/ncurses.c b/console/ncurses.c index d34299fe6c..6429221019 100644 --- a/console/ncurses.c +++ b/console/ncurses.c @@ -23,6 +23,8 @@ #undef ERR /* Use ncurses's err() */ #include +SCREEN *ncurses_screen; + void NCURSES_Start() { /* This should be the root driver so we can ignore anything @@ -46,7 +48,9 @@ void NCURSES_Start() void NCURSES_Init() { - initscr(); + ncurses_screen = newterm("xterm", driver.console_out, + driver.console_in); + set_term(ncurses_screen); cbreak(); noecho(); nonl(); @@ -58,7 +62,7 @@ void NCURSES_Init() void NCURSES_Write(char output, int fg, int bg, int attribute) { /* We can discard all extended information. */ - addch(output); + waddch(stdscr, output); } void NCURSES_Close() @@ -74,7 +78,7 @@ void NCURSES_GetKeystroke(char *scan, char *ascii) /* When it is detected, we will already have the right value in scan and ascii, but we need to take this keystroke out of the buffer. */ - getch(); + wgetch(stdscr); } int NCURSES_CheckForKeystroke(char *scan, char *ascii) @@ -82,7 +86,7 @@ int NCURSES_CheckForKeystroke(char *scan, char *ascii) /* We don't currently support scan codes here */ /* FIXME */ int temp; - temp = getch(); + temp = wgetch(stdscr); if (temp == ERR) { return FALSE; @@ -97,7 +101,7 @@ int NCURSES_CheckForKeystroke(char *scan, char *ascii) void NCURSES_MoveCursor(char row, char col) { - move(row, col); + wmove(stdscr, row, col); } void NCURSES_GetCursorPosition(char *row, char *col) @@ -114,7 +118,7 @@ void NCURSES_GetCharacterAtCursor(char *ch, int *fg_color, int *bg_color, int *attribute) { /* We will eventually have to convert the color data */ - *ch = (char) inch(); + *ch = (char) winch(stdscr); *fg_color = 0; *bg_color = 0; *attribute = 0; @@ -122,12 +126,12 @@ void NCURSES_GetCharacterAtCursor(char *ch, int *fg_color, int void NCURSES_Refresh() { - refresh(); + wrefresh(stdscr); } void NCURSES_ClearScreen() { - erase(); + werase(stdscr); } #endif /* WINE_NCURSES */ diff --git a/console/tty.c b/console/tty.c index 0a220a5e45..7225cf1dba 100644 --- a/console/tty.c +++ b/console/tty.c @@ -28,14 +28,14 @@ void TTY_Start() void TTY_Write(char output, int fg, int bg, int attribute) { /* We can discard all extended information. */ - printf("%c", output); + fprintf(driver.console_out, "%c", output); } void TTY_GetKeystroke(char *ch, char *scan) { /* All we have are character input things, nothing for extended */ /* This is just the TTY driver, after all. We'll cope. */ - _lread16(0, ch, 0); + *ch = fgetc(driver.console_in); } diff --git a/console/xterm.c b/console/xterm.c new file mode 100644 index 0000000000..cb675f793b --- /dev/null +++ b/console/xterm.c @@ -0,0 +1,174 @@ +/* xterm.c */ + +/* This "driver" is designed to go on top of an existing driver + to provide support for features only present if using an + xterm or compatible program for your console output. It should + inlcude such features as resizing, separation of output from the + standard wine console, and a configurable title bar for + Win32 console. */ +/* Right now, it doesn't have any "special" features */ + +#include +#include +#include +#include +#include +#include + +#include "windows.h" +#include "console.h" +#include "debug.h" + +static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid); +static FILE *wine_openpty(FILE **master, FILE **slave, char *name, + struct termios *term, struct winsize *winsize); + +/* The console -- I chose to keep the master and slave + * (UNIX) file descriptors around in case they are needed for + * ioctls later. The pid is needed to destroy the xterm on close + */ +typedef struct _XTERM_CONSOLE { + FILE *master; /* xterm side of pty */ + FILE *slave; /* wine side of pty */ + int pid; /* xterm's pid, -1 if no xterm */ +} XTERM_CONSOLE; + +static XTERM_CONSOLE xterm_console; + +CONSOLE_device chain; +FILE *old_in, *old_out; + +void XTERM_Start() +{ + /* Here, this is a supplementary driver so we should remember to call + the chain. */ + chain.init = driver.init; + driver.init = XTERM_Init; + + chain.close = driver.close; + driver.close = XTERM_Close; +} + +void XTERM_Init() +{ + wine_create_console(&xterm_console.master, &xterm_console.slave, + &xterm_console.pid); + + old_in = driver.console_in; + driver.console_in = xterm_console.slave; + + old_out = driver.console_out; + driver.console_out = xterm_console.slave; + + /* Then call the chain... */ + if (chain.init) + chain.init(); +} + +void XTERM_Close() +{ + /* Call the chain first... */ + if (chain.close) + chain.close(); + + driver.console_in = old_in; + driver.console_out = old_out; + + /* make sure a xterm exists to kill */ + if (xterm_console.pid != -1) { + kill(xterm_console.pid, SIGTERM); + } +} + +/** + * It looks like the openpty that comes with glibc in RedHat 5.0 + * is buggy (second call returns what looks like a dup of 0 and 1 + * instead of a new pty), this is a generic replacement. + */ +/** Can't we determine this using autoconf? + */ + +static FILE *wine_openpty(FILE **master, FILE **slave, char *name, + struct termios *term, struct winsize *winsize) +{ + FILE *fdm, *fds; + char *ptr1, *ptr2; + char pts_name[512]; + + strcpy (pts_name, "/dev/ptyXY"); + for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) { + pts_name[8] = *ptr1; + for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) { + pts_name[9] = *ptr2; + + if ((fdm = fopen(pts_name, "r+")) == NULL) { + if (errno == ENOENT) + return (FILE *) -1; + else + continue; + } + pts_name[5] = 't'; + if ((fds = fopen(pts_name, "r+")) == NULL) { + pts_name[5] = 'p'; + continue; + } + *master = fdm; + *slave = fds; + + if (term != NULL) + tcsetattr((*slave)->_fileno, TCSANOW, term); + if (winsize != NULL) + ioctl((*slave)->_fileno, TIOCSWINSZ, winsize); + + if (name != NULL) + strcpy(name, pts_name); + return fds; + } + } + return (FILE *) -1; +} + +static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid) +{ + struct termios term; + char buf[1024]; + char c = '\0'; + int status = 0; + int i; + + if (tcgetattr(0, &term) < 0) return FALSE; + term.c_lflag |= ICANON; + term.c_lflag &= ~ECHO; + if (wine_openpty(master, slave, NULL, &term, NULL) < 0) + return FALSE; + + if ((*pid=fork()) == 0) { + tcsetattr((*slave)->_fileno, TCSADRAIN, &term); + sprintf(buf, "-Sxx%d", (*master)->_fileno); + execlp("xterm", "xterm", buf, NULL); + ERR(console, "error creating AllocConsole xterm\n"); + exit(1); + } + + /* most xterms like to print their window ID when used with -S; + * read it and continue before the user has a chance... + * NOTE: this is the reason we started xterm with ECHO off, + * we'll turn it back on below + */ + + for (i=0; c!='\n'; (status=fread(&c, 1, 1, *slave)), i++) { + if (status == -1 && c == '\0') { + /* wait for xterm to be created */ + usleep(100); + } + if (i > 10000) { + WARN(console, "can't read xterm WID\n"); + kill(*pid, SIGKILL); + return FALSE; + } + } + term.c_lflag |= ECHO; + tcsetattr((*master)->_fileno, TCSADRAIN, &term); + + return TRUE; +} diff --git a/include/console.h b/include/console.h index 6e34bfee3f..0f1fbebaca 100644 --- a/include/console.h +++ b/include/console.h @@ -7,6 +7,8 @@ #ifndef CONSOLE_H #define CONSOLE_H +#include + #include "config.h" typedef struct CONSOLE_DRIVER @@ -36,6 +38,9 @@ typedef struct CONSOLE_DRIVER /* Other data */ int norefresh; + FILE *console_out; + FILE *console_in; + } CONSOLE_device; CONSOLE_device driver; /* Global driver struct */ @@ -87,4 +92,9 @@ void NCURSES_ClearScreen(); #endif /* WINE_NCURSES */ +/* Xterm specific defines */ +void XTERM_Start(); +void XTERM_Close(); +void XTERM_Init(); + #endif /* CONSOLE_H */