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