Added test for GetFullPathNamesA, GetLongPathNamesA,
[wine] / console / xterm.c
1 /*
2  * Copyright 1999 - Joseph Pranevich
3  *
4  * This "driver" is designed to go on top of an existing driver
5  * to provide support for features only present if using an
6  * xterm or compatible program for your console output. 
7  * Currently, it supports resizing and separating debug messages from
8  * program output.
9  * It does not currently support changing the title bar.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <signal.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <termios.h>
36 #ifdef HAVE_LIBUTIL_H
37 # include <libutil.h>
38 #endif
39 #ifdef HAVE_PTY_H
40 # include <pty.h>
41 #endif
42
43 #include "console.h"
44 #include "options.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(console);
48
49 char console_xterm_prog[80];
50
51 static BOOL wine_create_console(FILE **master, FILE **slave, pid_t *pid);
52
53 /* The console -- I chose to keep the master and slave
54  * (UNIX) file descriptors around in case they are needed for
55  * ioctls later.  The pid is needed to destroy the xterm on close
56  */
57 typedef struct _XTERM_CONSOLE {
58         FILE    *master;                 /* xterm side of pty */
59         FILE    *slave;                  /* wine side of pty */
60         pid_t    pid;                    /* xterm's pid, -1 if no xterm */
61 } XTERM_CONSOLE;
62
63 static XTERM_CONSOLE xterm_console;
64
65 CONSOLE_device chain;
66 FILE *old_in, *old_out;
67
68 void XTERM_Start(void)
69 {
70    /* Here, this is a supplementary driver so we should remember to call
71       the chain. */
72    chain.init = driver.init;
73    driver.init = XTERM_Init;
74
75    chain.close = driver.close;
76    driver.close = XTERM_Close;
77
78    chain.resizeScreen = driver.resizeScreen;
79    driver.resizeScreen = XTERM_ResizeScreen;
80
81    /* Read in driver configuration */
82    PROFILE_GetWineIniString("console", "XtermProg",
83       "xterm", console_xterm_prog, 79); 
84
85 }
86
87 void XTERM_Init()
88 {
89    wine_create_console(&xterm_console.master, &xterm_console.slave,
90       &xterm_console.pid);
91
92    old_in = driver.console_in;
93    driver.console_in = xterm_console.slave;
94
95    old_out = driver.console_out;
96    driver.console_out = xterm_console.slave;
97
98    /* Then call the chain... */
99    if (chain.init)
100       chain.init();
101 }
102
103 void XTERM_Close()
104 {
105    /* Call the chain first... */
106    if (chain.close)
107       chain.close();
108
109    driver.console_in = old_in;
110    driver.console_out = old_out;
111
112    /* make sure a xterm exists to kill */
113    if (xterm_console.pid != -1) {
114       kill(xterm_console.pid, SIGTERM);
115    }
116 }
117
118 void XTERM_ResizeScreen(int x, int y)
119 {
120    char temp[100];
121
122    /* Call the chain first, there shoudln't be any... */
123    if (chain.resizeScreen)
124       chain.resizeScreen(x, y);
125
126    sprintf(temp, "\x1b[8;%d;%dt", y, x);
127    CONSOLE_WriteRawString(temp);
128
129    CONSOLE_NotifyResizeScreen(x, y);
130 }
131
132
133 static BOOL wine_create_console(FILE **master, FILE **slave, pid_t *pid)
134 {
135         /* There is definately a bug in this routine that causes a lot
136            of garbage to be written to the screen, but I can't find it...
137         */
138         struct termios term;
139         char buf[1024];
140         char c = '\0';
141         int status = 0;
142         int i;
143         int tmaster, tslave;
144         char xterm_resolution[10];
145
146         sprintf(xterm_resolution, "%dx%d", driver.x_res,
147            driver.y_res);
148
149         if (tcgetattr(0, &term) < 0) return FALSE;
150         term.c_lflag |= ICANON;
151         term.c_lflag &= ~ECHO;
152         if (openpty(&tmaster, &tslave, NULL, &term, NULL) < 0)
153            return FALSE;
154         *master = fdopen(tmaster, "r+");
155         *slave = fdopen(tslave, "r+");
156
157         if ((*pid=fork()) == 0) {
158                 tcsetattr(fileno(*slave), TCSADRAIN, &term);
159                 sprintf(buf, "-Sxx%d", fileno(*master));
160                 execlp(console_xterm_prog, console_xterm_prog, buf, "-fg",
161                    "white", "-bg", "black", "-g",
162                    xterm_resolution, NULL);
163                 ERR("error creating xterm (file not found?)\n");
164                 exit(1);
165         }
166
167         /* most xterms like to print their window ID when used with -S;
168          * read it and continue before the user has a chance...
169          * NOTE: this is the reason we started xterm with ECHO off,
170          * we'll turn it back on below
171          */
172
173         for (i=0; c!='\n'; (status=fread(&c, 1, 1, *slave)), i++) {
174                 if (status == -1 && c == '\0') {
175                                 /* wait for xterm to be created */
176                         usleep(100);
177                 }
178                 if (i > 10000) {
179                         WARN("can't read xterm WID\n");
180                         kill(*pid, SIGKILL);
181                         return FALSE;
182                 }
183         }
184         term.c_lflag |= ECHO;
185         tcsetattr(fileno(*master), TCSADRAIN, &term);
186
187         return TRUE;
188 }