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