| /* 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. |
| Currently, it supports resizing and separating debug messages from |
| program output. |
| It does not currently support changing the title bar. |
| */ |
| |
| #include <stdio.h> |
| #include <signal.h> |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <termios.h> |
| #include <errno.h> |
| |
| #include "console.h" |
| #include "options.h" |
| #include "debug.h" |
| |
| #define ESC '\x1b' |
| |
| char console_xterm_prog[80]; |
| char console_xterm_resolution[10]; |
| |
| static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid); |
| FILE *wine_openpty(int *master, int *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; |
| |
| chain.resizeScreen = driver.resizeScreen; |
| driver.resizeScreen = XTERM_ResizeScreen; |
| |
| /* Read in driver configuration */ |
| PROFILE_GetWineIniString("console", "XtermProg", |
| "xterm", console_xterm_prog, 79); |
| PROFILE_GetWineIniString("console", "XtermResolution", |
| "80x24", console_xterm_resolution, 9); |
| |
| } |
| |
| 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); |
| } |
| } |
| |
| void XTERM_ResizeScreen(int x, int y) |
| { |
| char temp[100]; |
| |
| /* Call the chain first, there shoudln't be any... */ |
| if (chain.resizeScreen) |
| chain.resizeScreen(x, y); |
| |
| sprintf(temp, "\x1b[8;%d;%dt", y, x); |
| CONSOLE_WriteRawString(temp); |
| |
| CONSOLE_NotifyResizeScreen(x, y); |
| } |
| |
| |
| static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid) |
| { |
| /* There is definately a bug in this routine that causes a lot |
| of garbage to be written to the screen, but I can't find it... |
| */ |
| struct termios term; |
| char buf[1024]; |
| char c = '\0'; |
| int status = 0; |
| int i; |
| int tmaster, tslave; |
| |
| if (tcgetattr(0, &term) < 0) return FALSE; |
| term.c_lflag |= ICANON; |
| term.c_lflag &= ~ECHO; |
| if (wine_openpty(&tmaster, &tslave, NULL, &term, NULL) < 0) |
| return FALSE; |
| *master = fdopen(tmaster, "r+"); |
| *slave = fdopen(tslave, "r+"); |
| |
| if ((*pid=fork()) == 0) { |
| tcsetattr(fileno(*slave), TCSADRAIN, &term); |
| sprintf(buf, "-Sxx%d", fileno(*master)); |
| execlp(console_xterm_prog, console_xterm_prog, buf, "-fg", |
| "white", "-bg", "black", "-g", |
| console_xterm_resolution, NULL); |
| ERR(console, "error creating xterm (file not found?)\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(fileno(*master), TCSADRAIN, &term); |
| |
| return TRUE; |
| } |