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