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