autoconf: added checks for libio.h, elf.h, curses.h,ncurses.h and
[wine] / console / xterm.c
1 /* xterm.c */
2
3 /* This "driver" is designed to go on top of an existing driver
4    to provide support for features only present if using an
5    xterm or compatible program for your console output. 
6    Currently, it supports resizing and separating debug messages from
7    program output.
8    It does not currently support changing the title bar.
9 */
10
11 #include <signal.h>
12 #include <sys/ioctl.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <termios.h>
16 #include <errno.h>
17
18 #include "windows.h"
19 #include "console.h"
20 #include "debug.h"
21
22 #define ESC '\x1b'
23
24 static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid);
25 static FILE *wine_openpty(FILE **master, FILE **slave, char *name,
26                         struct termios *term, struct winsize *winsize);
27
28 /* The console -- I chose to keep the master and slave
29  * (UNIX) file descriptors around in case they are needed for
30  * ioctls later.  The pid is needed to destroy the xterm on close
31  */
32 typedef struct _XTERM_CONSOLE {
33         FILE    *master;                 /* xterm side of pty */
34         FILE    *slave;                  /* wine side of pty */
35         int     pid;                     /* xterm's pid, -1 if no xterm */
36 } XTERM_CONSOLE;
37
38 static XTERM_CONSOLE xterm_console;
39
40 CONSOLE_device chain;
41 FILE *old_in, *old_out;
42
43 void XTERM_Start()
44 {
45    /* Here, this is a supplementary driver so we should remember to call
46       the chain. */
47    chain.init = driver.init;
48    driver.init = XTERM_Init;
49
50    chain.close = driver.close;
51    driver.close = XTERM_Close;
52
53    chain.resizeScreen = driver.resizeScreen;
54    driver.resizeScreen = XTERM_ResizeScreen;
55 }
56
57 void XTERM_Init()
58 {
59    wine_create_console(&xterm_console.master, &xterm_console.slave,
60       &xterm_console.pid);
61
62    old_in = driver.console_in;
63    driver.console_in = xterm_console.slave;
64
65    old_out = driver.console_out;
66    driver.console_out = xterm_console.slave;
67
68    /* Then call the chain... */
69    if (chain.init)
70       chain.init();
71 }
72
73 void XTERM_Close()
74 {
75    /* Call the chain first... */
76    if (chain.close)
77       chain.close();
78
79    driver.console_in = old_in;
80    driver.console_out = old_out;
81
82    /* make sure a xterm exists to kill */
83    if (xterm_console.pid != -1) {
84       kill(xterm_console.pid, SIGTERM);
85    }
86 }
87
88 void XTERM_ResizeScreen(int x, int y)
89 {
90    char temp[100];
91
92    /* Call the chain first, there shoudln't be any... */
93    if (chain.resizeScreen)
94       chain.resizeScreen(x, y);
95
96    sprintf(temp, "\x1b[8;%d;%dt", y, x);
97    CONSOLE_WriteRawString(temp);
98
99    CONSOLE_NotifyResizeScreen(x, y);
100 }
101
102
103 static BOOL32 wine_create_console(FILE **master, FILE **slave, int *pid)
104 {
105         /* There is definately a bug in this routine that causes a lot
106            of garbage to be written to the screen, but I can't find it...
107         */
108         struct termios term;
109         char buf[1024];
110         char c = '\0';
111         int status = 0;
112         int i;
113         int tmaster, tslave;
114
115         if (tcgetattr(0, &term) < 0) return FALSE;
116         term.c_lflag |= ICANON;
117         term.c_lflag &= ~ECHO;
118         if (wine_openpty(&tmaster, &tslave, NULL, &term, NULL) < 0)
119            return FALSE;
120         *master = fdopen(tmaster, "r+");
121         *slave = fdopen(tslave, "r+");
122
123         if ((*pid=fork()) == 0) {
124                 tcsetattr(fileno(*slave), TCSADRAIN, &term);
125                 sprintf(buf, "-Sxx%d", fileno(*master));
126                 execlp(CONSOLE_XTERM_PROG, CONSOLE_XTERM_PROG, buf, "-fg",
127                    "white", "-bg", "black", NULL);
128                 ERR(console, "error creating xterm\n");
129                 exit(1);
130         }
131
132         /* most xterms like to print their window ID when used with -S;
133          * read it and continue before the user has a chance...
134          * NOTE: this is the reason we started xterm with ECHO off,
135          * we'll turn it back on below
136          */
137
138         for (i=0; c!='\n'; (status=fread(&c, 1, 1, *slave)), i++) {
139                 if (status == -1 && c == '\0') {
140                                 /* wait for xterm to be created */
141                         usleep(100);
142                 }
143                 if (i > 10000) {
144                         WARN(console, "can't read xterm WID\n");
145                         kill(*pid, SIGKILL);
146                         return FALSE;
147                 }
148         }
149         term.c_lflag |= ECHO;
150         tcsetattr(fileno(*master), TCSADRAIN, &term);
151
152         return TRUE;
153 }