1 /* x11.c: X11 window interface for Metafont, using Xt.  Original by
2    rusty@garnet.berkeley.edu.  */
3 
4 #define	EXTERN extern
5 #include "../mfd.h"
6 
7 #ifdef X11WIN			/* almost whole file */
8 
9 /* For wchar_t et al., that the X files might want. */
10 #include <kpathsea/systypes.h>
11 
12 #undef input /* the XWMHints structure has a field named `input' */
13 #undef output
14 #include <X11/Xlib.h>
15 #include <X11/Intrinsic.h>
16 #include <X11/StringDefs.h>
17 #undef wchar_t
18 
19 #define PLANE 0
20 
21 static unsigned int mf_defwidth = 0;
22 static unsigned int mf_defheight = 0;
23 
24 static Display *mf_display;
25 static Window mf_window;
26 
27 static Pixmap mf_pixmap;
28 
29 static XtAppContext mf_app;
30 
31 static GC mf_dgc;		/* draw gc */
32 static GC mf_egc;		/* erase gc */
33 static GC mf_cgc;		/* copy plane gc */
34 
35 typedef struct
36 {
37   unsigned int mf_width, mf_height;
38   Pixel mf_fg, mf_bg;
39 } mf_resources_struct;
40 
41 static mf_resources_struct mf_x11_resources;
42 
43 
44 /* Don't paint anything until we're mapped.  */
45 static Boolean mf_mapped;
46 
47 #ifdef MF_XT_DEBUG
48 static int mf_max_x, mf_max_y;
49 static int mf_min_x, mf_min_y;
50 
51 static void mf_checkextent ();
52 #endif
53 
54 static XtResource mf_resources[]
55   = { { "width", "Width", XtRInt, sizeof (int),
56         XtOffset (mf_resources_struct *, mf_width), XtRInt,
57         (XtPointer) & mf_defwidth },
58 
59       { "height", "Height", XtRInt, sizeof (int),
60         XtOffset (mf_resources_struct *, mf_height), XtRInt,
61         (XtPointer) &mf_defheight },
62 
63       { "foreground", "Foreground", XtRPixel, sizeof (Pixel),
64         XtOffset (mf_resources_struct *, mf_fg),
65         XtRString, (XtPointer) "Black" },
66 
67       { "background", "Background", XtRPixel, sizeof (Pixel),
68         XtOffset (mf_resources_struct *, mf_bg), XtRString,
69         (XtPointer) "White" },
70 };
71 
72 /* Maybe someday we'll read options, until then, this is just here for
73    the resources.  */
74 static XrmOptionDescRec mf_optiondesclist[]
75 = { { "-width",   "width", XrmoptionSepArg, (XPointer) NULL },
76     { "-height", "height", XrmoptionSepArg, (XPointer) NULL },
77     { "-fg", "foreground", XrmoptionSepArg, (XPointer) NULL },
78     { "-bg", "background", XrmoptionSepArg, (XPointer) NULL },
79 };
80 
81 static void mf_events(void);
82 static void mf_mapstatus(Widget w, XtPointer data, XEvent *ev);
83 static void mf_newpixmap(unsigned int width, unsigned int height);
84 static void mf_redraw(void);
85 static void mf_repaint(Widget w, XtPointer data, XEvent *ev);
86 
87 #include <mfdisplay.h>
88 
89 /* Return 1 if display opened successfully, else 0.  */
90 
91 int
mf_x11_initscreen(void)92 mf_x11_initscreen (void)
93 {
94   XSetWindowAttributes xwa;
95   Widget mf_toplevel;
96   Widget mf_canvas;
97   XGCValues gcv;
98   Arg args[1];
99   int mf_argc;
100   char *mf_argv[2];
101 
102   mf_argv[0] = "mf";
103   mf_argv[1] = NULL;
104   mf_argc = 1;
105 
106   mf_toplevel = XtInitialize ("mf", "Metafont",
107 			      mf_optiondesclist,
108 			      XtNumber (mf_optiondesclist),
109 			      &mf_argc, mf_argv);
110 
111   XtGetApplicationResources (mf_toplevel, (XtPointer) & mf_x11_resources,
112 			     mf_resources, XtNumber (mf_resources),
113 			     NULL, 0);
114 
115   if (mf_argc != 1)
116     {
117       fprintf (stderr, "Usage: %s\n", mf_argv[0]);
118       return 0;
119     }
120 
121   /* If nothing specified in their resources (e.g., .Xdefaults)
122      then use the values of Metafont's "screen".  */
123   if (mf_x11_resources.mf_width == 0)
124     mf_x11_resources.mf_width = screenwidth;
125   if (mf_x11_resources.mf_height == 0)
126     mf_x11_resources.mf_height = screendepth;
127 
128   mf_canvas = XtCreateManagedWidget ("canvas", widgetClass, mf_toplevel,
129 				     NULL, 0);
130 
131   XtSetArg (args[0], XtNwidth, mf_x11_resources.mf_width);
132   XtSetValues (mf_canvas, args, 1);
133   XtSetArg (args[0], XtNheight, mf_x11_resources.mf_height);
134   XtSetValues (mf_canvas, args, 1);
135 
136   /* for mf_x11_updatescreen() */
137   mf_app = XtWidgetToApplicationContext (mf_canvas);
138 
139   XtAddEventHandler (mf_canvas, (Cardinal) ExposureMask, True,
140 		     (XtEventHandler) mf_repaint, NULL);
141   XtAddEventHandler (mf_canvas, (Cardinal) StructureNotifyMask, True,
142 		     (XtEventHandler) mf_mapstatus, NULL);
143 
144   XtRealizeWidget (mf_toplevel);
145 
146   mf_display = XtDisplay (mf_canvas);
147   mf_window = XtWindow (mf_canvas);
148 
149   /* Since Metafont isn't your typical x window program that
150      sits in XTMainLoop, if the server supports backing store
151      and save unders this will help keep the output looking
152      nice.  */
153   xwa.backing_store = Always;
154   xwa.save_under = True;
155   XChangeWindowAttributes (mf_display, mf_window,
156 			   CWBackingStore | CWSaveUnder, &xwa);
157 
158   gcv.background = mf_x11_resources.mf_bg;
159   gcv.foreground = mf_x11_resources.mf_fg;
160   gcv.function = GXcopy;
161 
162   /* copy plane gc */
163   mf_cgc = XCreateGC (mf_display, mf_window,
164 		      GCForeground | GCBackground | GCFunction, &gcv);
165 
166   mf_newpixmap (screenwidth > mf_x11_resources.mf_width
167                 ? screenwidth : mf_x11_resources.mf_width,
168 		screendepth > mf_x11_resources.mf_height
169 	        ? screendepth : mf_x11_resources.mf_height);
170 
171   return 1;
172 }
173 
174 void
mf_x11_updatescreen(void)175 mf_x11_updatescreen (void)
176 {
177   mf_events ();
178   mf_redraw ();
179 
180 #ifdef MF_XT_DEBUG
181   printf ("max_x=%d, min_x=%d, max_y=%d, min_y=%d\n",
182 	  mf_max_x, mf_min_x,
183 	  mf_max_y, mf_min_y);
184 #endif
185 }
186 
187 
188 void
mf_x11_blankrectangle(screencol left,screencol right,screenrow top,screenrow bottom)189 mf_x11_blankrectangle(screencol left,
190                       screencol right,
191                       screenrow top,
192                       screenrow bottom)
193 {
194   XFillRectangle (mf_display, mf_pixmap, mf_egc, (int) left, (int) top,
195 		  (int) (right - left + 1), (int) (bottom - top + 1));
196   mf_events ();
197 }
198 
199 void
mf_x11_paintrow(screenrow row,pixelcolor init_color,transspec tvect,screencol vector_size)200 mf_x11_paintrow(screenrow row,
201                 pixelcolor init_color,
202                 transspec tvect,
203                 screencol vector_size)
204 {
205   GC gc;
206   int col;
207 
208   gc = (init_color == 0) ? mf_egc : mf_dgc;
209 
210   do
211     {
212       col = *tvect++;
213 
214 #ifdef MF_XT_DEBUG
215       mf_checkextent (col, *tvect, row);
216 #endif /* MF_XT_DEBUG */
217 
218       XDrawLine (mf_display, mf_pixmap, gc, col, (int) row,
219 		 (int) *tvect, (int) row);
220 
221       gc = (gc == mf_egc) ? mf_dgc : mf_egc;
222     }
223   while (--vector_size > 0);
224 
225   mf_events ();
226 }
227 
228 #ifdef MF_XT_DEBUG
229 static void
mf_checkextent(int x1,int x2,int y)230 mf_checkextent(int x1, int x2, int y)
231 {
232   if (x1 < mf_min_x)
233     mf_min_x = x1;
234   if (x1 > mf_max_x)
235     mf_max_x = x1;
236 
237   if (x2 < mf_min_x)
238     mf_min_x = x2;
239   if (x2 > mf_max_x)
240     mf_max_x = x2;
241 
242   if (y > mf_max_y)
243     mf_max_y = y;
244   if (y < mf_min_y)
245     mf_min_y = y;
246 }
247 #endif /* MF_XT_DEBUG */
248 
249 static void
mf_events(void)250 mf_events (void)
251 {
252   XEvent event;
253 
254   if (XtAppPending (mf_app) != 0)
255     {
256       while (XtAppPending (mf_app) != 0)
257 	{
258 	  XtAppNextEvent (mf_app, &event);
259 	  XtDispatchEvent (&event);
260 	}
261     }
262 }
263 
264 static void
mf_newpixmap(unsigned int width,unsigned int height)265 mf_newpixmap(unsigned int width, unsigned int height)
266 {
267   XGCValues gcv;
268   Pixmap newpixmap;
269 
270   /* width == mf_width and height == mf_height
271      the first time mf_newpixmap() is called.
272    */
273   if (width < mf_x11_resources.mf_width && height < mf_x11_resources.mf_height)
274     return;
275 
276   newpixmap = XCreatePixmap (mf_display, mf_window, width, height, 1);
277 
278   gcv.background = 0;
279   gcv.foreground = 1;
280 
281   if (mf_dgc != 0)
282     XFreeGC (mf_display, mf_dgc);
283 
284   /* draw gc */
285   gcv.line_width = 1;
286   mf_dgc = XCreateGC (mf_display, newpixmap,
287 		      GCForeground | GCBackground | GCLineWidth, &gcv);
288 
289   if (mf_egc != 0)
290     XFreeGC (mf_display, mf_egc);
291 
292   /* erase gc */
293   gcv.foreground = 0;
294   mf_egc = XCreateGC (mf_display, newpixmap,
295 		      GCForeground | GCBackground | GCLineWidth, &gcv);
296 
297   XFillRectangle (mf_display, newpixmap, mf_egc, 0, 0, width, height);
298 
299   if (mf_pixmap != 0)
300     {
301       XCopyArea (mf_display, mf_pixmap, newpixmap, mf_dgc, 0, 0,
302 		 mf_x11_resources.mf_width,
303 		 mf_x11_resources.mf_height, 0, 0);
304 
305       XFreePixmap (mf_display, mf_pixmap);
306     }
307 
308   mf_pixmap = newpixmap;
309 
310   mf_x11_resources.mf_width = width;
311   mf_x11_resources.mf_height = height;
312 }
313 
314 static void
mf_repaint(Widget w,XtPointer data,XEvent * ev)315 mf_repaint(Widget w, XtPointer data, XEvent *ev)
316 {
317   if (!mf_mapped || !ev || ev->type != Expose)
318     return;
319 
320   /* We are a ``simple application''. */
321   if (ev->xexpose.count == 0)
322     {
323       XEvent event;
324 
325       /* skip all excess redraws */
326       while (XCheckTypedEvent (mf_display, Expose, &event) != False)
327 	continue;
328 
329       mf_redraw ();
330     }
331 }
332 
333 
334 static void
mf_mapstatus(Widget w,XtPointer data,XEvent * ev)335 mf_mapstatus(Widget w, XtPointer data, XEvent *ev)
336 {
337   switch (ev->type)
338     {
339     case MapNotify:
340       mf_mapped = True;
341       break;
342 
343     case UnmapNotify:
344       mf_mapped = False;
345       break;
346 
347     case ConfigureNotify:
348       mf_newpixmap (ev->xconfigure.width, ev->xconfigure.height);
349       mf_redraw ();
350       break;
351     }
352 }
353 
354 
355 static void
mf_redraw(void)356 mf_redraw (void)
357 {
358   XCopyPlane (mf_display, mf_pixmap, mf_window, mf_cgc, 0, 0,
359 	      mf_x11_resources.mf_width, mf_x11_resources.mf_height,
360 	      0, 0, (unsigned long) 1);
361 
362   XFlush (mf_display);
363 }
364 
365 #else
366 int x11_dummy;
367 #endif /* X11WIN */
368