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