1 /*
2 X Window System version 11 (release 3 et al.) interface for Metafont.
3 
4 Modified from Tim Morgan's X Version 11 routines by Richard Johnson.
5 Modified from that by Karl Berry <karl@umb.edu>.  8/3/89
6 
7 MF can now understand geometry (sort of, at least on a Sun running 3.4
8 and using uwm) in the resource database, as in the following in
9 .Xdefaults to put a window of width 500 and height 600 at (200,50):
10 
11 Metafont*geometry: 500x600+200+200
12 
13 You cannot give the geometry on the command line (who would want to)?
14 
15 The width and height specified in the resource must not be larger than
16 the screenwidth and screendepth defined in ../mf/cmf.ch.
17 If they are, then I reset them to the maximum.
18 
19 We don't handle Expose events in general. This means that the window
20 cannot be moved, resized, or obscured. The problem is that I don't know
21 when we can look for such events. Adding a check to the main loop of
22 Metafont was more than I wanted to do. Another problem is that Metafont
23 does not keep track of the contents of the screen, and so I don't see
24 how to know what to redraw. The right way to do this is probably to fork
25 a process, and keep a Pixmap around of the contents of the window.
26 
27 I could never have done this without David Rosenthal's Hello World
28 program for X. See $X/mit/doc/HelloWorld.
29 
30 All section numbers refer to Xlib -- C Language X Interface.  */
31 
32 
33 #define	EXTERN	extern
34 #include "../mfd.h"
35 
36 
37 #ifdef	X11WIN
38 
39 #undef input /* the XWMHints structure has a field named `input' */
40 #undef output
41 
42 #include <X11/Xatom.h>
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 
46 
47 /* Variables for communicating between the routines we'll write.  */
48 
49 static Display *my_display;
50 static int my_screen;
51 static Window my_window;
52 static GC my_gc;
53 static int white, black;
54 
55 
56 /* Window manager hints.  */
57 
58 static XWMHints wm_hints = {
59    (InputHint|StateHint), /* flags telling which values are set */
60    False, /* We don't expect input. */
61    NormalState, /* Initial state. */
62    0, /* icon pixmap */
63    0, /* icon window */
64    0, 0, /* icon location (should get from resource?) */
65    0, /* icon mask */
66    0 /* window group */
67 };
68 
69 
70 /* Some constants for the resource database, etc.  */
71 #define PROGRAM_NAME "Metafont"
72 #define ARG_GEOMETRY "geometry"
73 #define BORDER_WIDTH 1 /* Should get this from resource. */
74 #define DEFAULT_X_POSITION 0
75 #define DEFAULT_Y_POSITION 0
76 
77 
78 #include <mfdisplay.h>
79 
80 /* Return 1 (i.e., true) if display opened successfully, else 0.  */
81 
82 int
mf_x11_initscreen(void)83 mf_x11_initscreen(void)
84 {
85     char *geometry;
86     int geometry_found = 0;
87     char default_geometry[100];
88     XSizeHints sizehints;
89     XGCValues gcvalues;
90 
91     /* We want the default display. (section 2.1 Opening the display)  */
92     my_display = XOpenDisplay(NULL);
93     if (my_display == NULL) return 0;
94 
95     /* Given a display, we can get the screen and the ``black'' and
96        ``white'' pixels.  (section 2.2.1 Display macros)  */
97     my_screen = DefaultScreen(my_display);
98     white = WhitePixel(my_display, my_screen);
99     black = BlackPixel(my_display, my_screen);
100 
101 
102     sizehints.x = DEFAULT_X_POSITION;
103     sizehints.y = DEFAULT_Y_POSITION;
104     sizehints.width = screenwidth;
105     sizehints.height = screendepth;
106     sizehints.flags = PPosition|PSize;
107 
108     sprintf (default_geometry, "%ux%u+%u+%u",
109                                (unsigned int) screenwidth, (unsigned int) screendepth,
110                                DEFAULT_X_POSITION, DEFAULT_Y_POSITION);
111 
112     /* Look up the geometry for this window. (Section 10.2 Obtaining X
113        environment defaults)  */
114     geometry = XGetDefault(my_display, PROGRAM_NAME, ARG_GEOMETRY);
115 
116     if (geometry != NULL) {
117        /* (section 10.3 Parsing window geometry) */
118        int bitmask = XGeometry(my_display, my_screen,
119 			       geometry, default_geometry,
120                                BORDER_WIDTH,
121                                1, 1, /* ``Font'' width and height. */
122                                0, 0, /* Interior padding. */
123                                &(sizehints.x), &(sizehints.y),
124                                &(sizehints.width), &(sizehints.height));
125 
126        /* (section 9.1.6 Setting and getting window sizing hints)  */
127        if (bitmask & (XValue|YValue)) {
128           sizehints.flags |= USPosition;
129           geometry_found = 1;
130        }
131 
132        if (bitmask & (WidthValue|HeightValue)) {
133           sizehints.flags |= USSize;
134           if (sizehints.width > screenwidth) sizehints.width = screenwidth;
135           if (sizehints.height > screendepth) sizehints.height = screendepth;
136           geometry_found = 1;
137        }
138     }
139 
140 
141     /* Our window is pretty simple. (section 3.3 Creating windows)  */
142     my_window = XCreateSimpleWindow(my_display,
143                           DefaultRootWindow(my_display), /* parent */
144                           sizehints.x, sizehints.y, /* upper left */
145                           sizehints.width, sizehints.height,
146                           BORDER_WIDTH,
147 			  black, /* border color */
148                           white); /* background color */
149 
150     /* (section 9.1.1 Setting standard properties)  */
151     XSetStandardProperties(my_display, my_window,
152                            PROGRAM_NAME,  /* window name */
153                            PROGRAM_NAME,  /* icon name */
154 			   None,  /* pixmap for icon */
155                            0, 0,  /* argv and argc for restarting */
156                            &sizehints);
157     XSetWMHints(my_display, my_window, &wm_hints);
158 
159 
160     /* We need a graphics context if we're going to draw anything.
161        (section 5.3 Manipulating graphics context/state)  */
162     gcvalues.foreground = black;
163     gcvalues.background = white;
164     /* A ``thin'' line.  This is much faster than a line of length 1,
165        although the manual cautions that the results might be less
166        consistent across screens.  */
167     gcvalues.line_width = 0;
168 
169     my_gc = XCreateGC(my_display, my_window,
170 		      GCForeground|GCBackground|GCLineWidth,
171 		      &gcvalues);
172 
173     /* (section 3.5 Mapping windows)  This is the confusing part of the
174     program, at least to me. If no geometry spec was found, then the
175     window manager puts up the blinking rectangle, and the user clicks,
176     all before the following call returns. But if a geometry spec was
177     found, then we want to do a whole mess of other things, because the
178     window manager is going to send us an expose event so that we can
179     bring our window up -- and this is one expose event we have to
180     handle.  */
181     XMapWindow(my_display, my_window);
182 
183     if (geometry_found) {
184        /* The window manager sends us an Expose event. Yuck.
185        */
186        XEvent my_event;
187        /* We certainly don't want to handle anything else.
188           (section 8.5 Selecting events)
189        */
190        XSelectInput(my_display, my_window, ExposureMask);
191 
192        /* We also want to do this right now. This is the confusion. From
193           stepping through the program under the debugger, it appears
194           that it is this call to XSync (given the previous call to
195           XSelectInput) that actually brings the window up -- and yet
196           without the remaining code, the thing doesn't work right. Very
197           strange. (section 8.6 Handling the output buffer)
198        */
199        XSync(my_display, 0);
200 
201        /* Now get the event. (section 8.8.1 Returning the next event)
202        */
203        XNextEvent(my_display, &my_event);
204 
205        /* Ignore all but the last of the Expose events.
206           (section 8.4.5.1 Expose event processing)
207        */
208        if (my_event.type == Expose && my_event.xexpose.count == 0) {
209           /* Apparently the network might STILL have my_events coming in.
210              Let's throw away Expose my_events again. (section 8.8.3
211              Selecting my_events using a window or my_event mask)
212           */
213           while (XCheckTypedEvent(my_display, Expose, &my_event)) ;
214 
215           /* Finally, let's draw the blank screen.
216           */
217           XClearWindow(my_display, my_window);
218        }
219    }
220 
221     /* That's it.  */
222     return 1;
223 }
224 
225 
226 /* Make sure the screen is up to date. (section 8.6 Handling the output
227 buffer)  */
228 
229 void
mf_x11_updatescreen(void)230 mf_x11_updatescreen(void)
231 {
232     XFlush(my_display);
233 }
234 
235 
236 /* Blank the rectangular inside the given coordinates. We don't need to
237 reset the foreground to black because we always set it at the beginning
238 of paintrow (below).  */
239 
240 void
mf_x11_blankrectangle(screencol left,screencol right,screenrow top,screenrow bottom)241 mf_x11_blankrectangle(screencol left,
242                       screencol right,
243                       screenrow top,
244                       screenrow bottom)
245 {
246     XSetForeground(my_display, my_gc, white);
247     XFillRectangle(my_display, my_window, my_gc,
248                    (int) left,
249                    (int) top,
250    	           (unsigned) (right - left + 1),
251                    (unsigned) (bottom - top + 1));
252 }
253 
254 
255 /* Paint a row with the given ``transition specifications''. We might be
256 able to do something here with drawing many lines.  */
257 
258 void
mf_x11_paintrow(screenrow row,pixelcolor init_color,transspec tvect,screencol vector_size)259 mf_x11_paintrow(screenrow row,
260                 pixelcolor init_color,
261                 transspec tvect,
262                 screencol vector_size)
263 {
264     register int color, col;
265 
266     color = (init_color == 0) ? white : black;
267 
268     do {
269 	col = *tvect++;
270 	XSetForeground(my_display, my_gc, color);
271 
272         /* (section 6.3.2 Drawing single and multiple lines)
273         */
274 	XDrawLine(my_display, my_window, my_gc, col, (int) row,
275 		  (int) *tvect, (int) row);
276 
277         color = (color == white) ? black : white;
278     } while (--vector_size > 0);
279 }
280 
281 #else
282 int x11_dummy;
283 #endif /* X11WIN */
284