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