1 /* mftalk.c -- generic Metafont window server.
2 Copyright (C) 1994 Ralph Schleicher
3 Slightly modified for Web2c 7.0 by Karl Berry.
4 Further modifications for Web2C 7.2 by Mathias.Herberts@irisa.fr */
5
6 /* This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 /* Please remember the following for porting to UNIX:
21
22 pid = fork ();
23 if (pid == 0)
24 execve (...); pid = spawnve (mode, ...);
25 else if (pid == -1) if (pid == -1)
26 error (); error ();
27 else else
28 success (); success ();
29
30 Spawnve(2) has many different modes and a `session' is indicated by
31 running on an extra terminal. */
32
33
34 #define EXTERN extern
35 #include "../mfd.h"
36
37 #ifdef MFTALKWIN
38
39 #undef input
40 #undef output
41 #undef read
42 #undef write
43 #ifdef OS2
44 #include <sys/param.h>
45 #include <process.h>
46 extern int close (int);
47 extern int pipe (int *);
48 extern int read (int, void *, size_t);
49 extern int setmode (int, int);
50 extern int write (int, const void *, size_t);
51 #endif
52 #include <fcntl.h>
53 #include <signal.h>
54 #include <kpathsea/variable.h>
55 #include "mftalk.h"
56
57 /* We use SIGCHLD, but fall back on SIGCLD if that's all we have. */
58 #if !defined (SIGCHLD) && defined (SIGCLD)
59 #define SIGCHLD SIGCLD
60 #endif
61
62 #define fatal(func, cond) do { if (cond) FATAL_PERROR ("perror"); } while (0)
63
64 static RETSIGTYPE child_died (int sig);
65 static string app_type (char *prog, int *app);
66
67 static int pid = -1; /* Process ID of our child. */
68 static int win = -1; /* Write handle to the `window'. */
69 static int buf[8]; /* Temporary buffer. */
70 static RETSIGTYPE (*old) (); /* Old signal handler. */
71
72
73 #include <mfdisplay.h>
74
75 int
mf_mftalk_initscreen(void)76 mf_mftalk_initscreen (void)
77 {
78 int app; /* Client application type. */
79 char *prog, *name; /* Client program name. */
80 /* Size of METAFONT window. */
81 char height[MAX_INT_LENGTH], width[MAX_INT_LENGTH];
82 /* Inherited pipe handles. */
83 char input[MAX_INT_LENGTH], output[MAX_INT_LENGTH];
84 char parent[MAX_INT_LENGTH]; /* My own process ID. */
85 int sc_pipe[2]; /* Server->Client pipe. */
86 int cs_pipe[2]; /* Client->Server pipe. */
87 int res, ack; /* Wait until child is ready. */
88
89 prog = kpse_var_value ("MFTALK");
90 if (prog == NULL)
91 prog = "mftalk.exe";
92
93 name = app_type (prog, &app);
94 if (!name)
95 return 0;
96
97 if (pipe (sc_pipe) == -1)
98 return 0;
99 if (pipe (cs_pipe) == -1)
100 {
101 close (sc_pipe[0]);
102 close (sc_pipe[1]);
103 return 0;
104 }
105 #ifdef OS2
106 fatal (setmode, setmode (sc_pipe[0], O_BINARY) == -1);
107 fatal (setmode, setmode (sc_pipe[1], O_BINARY) == -1);
108 fatal (setmode, setmode (cs_pipe[0], O_BINARY) == -1);
109 fatal (setmode, setmode (cs_pipe[1], O_BINARY) == -1);
110 #endif
111
112 old = signal (SIGCHLD, child_died);
113 fatal (old, old == SIG_ERR);
114
115 sprintf (height, "-h%d", screendepth);
116 sprintf (width, "-w%d", screenwidth);
117 sprintf (input, "-i%d", sc_pipe[0]);
118 sprintf (output, "-o%d", cs_pipe[1]);
119 sprintf (parent, "-p%d", getpid ());
120
121 #ifdef OS2
122 pid = spawnl (app, name, prog, height, width, input, output, parent, NULL);
123 #else
124 pid = fork ();
125 if (pid == 0)
126 {
127 fatal (close, close (0) == -1);
128 fatal (dup, dup (sc_pipe[0]) != 0);
129 fatal (close, close (sc_pipe[0]) == -1);
130 fatal (close, close (sc_pipe[1]) == -1);
131 fatal (close, close (1) == -1);
132 fatal (dup, dup (cs_pipe[1]) != 1);
133 fatal (close, close (cs_pipe[0]) == -1);
134 fatal (close, close (cs_pipe[1]) == -1);
135
136 /* We still pass the file handles as parameters for
137 * backward compatibility. instead of sc_pipe[0] and
138 * cs_pipe[1] we just pass 0 (stdin) and 1 (stdout).
139 */
140
141 sprintf (input, "-i0");
142 sprintf (output, "-o1");
143
144 execl (name, prog, height, width, input, output, parent, NULL);
145 }
146 #endif /* not OS2 */
147 switch (pid)
148 {
149 case -1:
150 failure:
151 fatal (close, close (sc_pipe[0]) == -1);
152 fatal (close, close (sc_pipe[1]) == -1);
153 fatal (close, close (cs_pipe[0]) == -1);
154 fatal (close, close (cs_pipe[1]) == -1);
155 fatal (signal, signal (SIGCHLD, old) == SIG_ERR);
156 break;
157 default:
158 res = read (cs_pipe[0], &ack, sizeof (int));
159 if (res != sizeof (int) || ack != MF_ACK)
160 goto failure;
161 fatal (close, close (cs_pipe[0]) == -1);
162 win = sc_pipe[1];
163 break;
164 }
165
166 return (win == -1) ? 0 : 1;
167 }
168
169
170 void
mf_mftalk_updatescreen(void)171 mf_mftalk_updatescreen (void)
172 {
173 buf[0] = MF_FLUSH;
174 write (win, buf, sizeof (int));
175 }
176
177
178 void
mf_mftalk_blankrectangle(screencol left,screencol right,screenrow top,screenrow bottom)179 mf_mftalk_blankrectangle (screencol left,
180 screencol right,
181 screenrow top,
182 screenrow bottom)
183 {
184 buf[0] = MF_RECT;
185 buf[1] = MF_WHITE;
186 buf[2] = left;
187 buf[3] = bottom;
188 buf[4] = right;
189 buf[5] = top;
190
191 write (win, buf, 6 * sizeof (int));
192 }
193
194
195 void
mf_mftalk_paintrow(screenrow row,pixelcolor init_color,transspec transition_vector,screencol vector_size)196 mf_mftalk_paintrow (screenrow row,
197 pixelcolor init_color,
198 transspec transition_vector,
199 screencol vector_size)
200 {
201 buf[0] = MF_LINE;
202 buf[1] = init_color == 0 ? MF_WHITE : MF_BLACK;
203 buf[2] = *transition_vector++;
204 buf[3] = row;
205 buf[4] = --vector_size;
206
207 write (win, buf, 5 * sizeof (int));
208 write (win, transition_vector, vector_size * sizeof (int));
209 }
210
211
212 static string
app_type(string prog,int * app)213 app_type (string prog, int *app)
214 {
215 #ifdef OS2
216 int res, app;
217
218 res = DosSearchPath (0x02 | 0x01, "PATH", prog, buf, len);
219 if (res != 0)
220 return -1;
221
222 res = DosQueryAppType (buf, &app);
223 if (res != 0)
224 return -1;
225
226 switch (app & 0x07) /* Quick guess. */
227 {
228 case 0x00: return (P_SESSION | P_DEFAULT);
229 case 0x01: return (P_SESSION | P_FULLSCREEN);
230 case 0x02: return (P_SESSION | P_WINDOWED);
231 case 0x03: return (P_PM);
232 }
233 #endif /* OS2 */
234
235 *app = 0; /* Irrelevant. */
236 return prog;
237 }
238
239
240 static RETSIGTYPE
child_died(int sig)241 child_died (int sig)
242 {
243 #ifdef OS2
244 fatal (signal, signal (sig, SIG_ACK) == SIG_ERR);
245 #endif
246 fatal (signal, signal (sig, SIG_IGN) == SIG_ERR);
247
248 if (pid == -1 || kill (-pid, 0) == 0) /* This was not our child. */
249 {
250 if (old != SIG_IGN)
251 {
252 fatal (signal, signal (sig, old) == SIG_ERR);
253 fatal (raise, raise (sig) == -1);
254 }
255 fatal (signal, signal (sig, child_died) == SIG_ERR);
256 }
257 else
258 {
259 close (win); /* This may fail. */
260 win = -1;
261
262 pid = -1;
263
264 screenstarted = false; /* METAFONT variables. */
265 screenOK = false;
266
267 fatal (signal, signal (sig, old) == SIG_ERR);
268 }
269 }
270
271 #else /* !MFTALKWIN */
272
273 int mftalk_dummy;
274
275 #endif /* !MFTALKWIN */
276