Back to index

tetex-bin  3.0
x11-Xlib.c
Go to the documentation of this file.
00001 /*
00002 X Window System version 11 (release 3 et al.) interface for Metafont.
00003  
00004 Modified from Tim Morgan's X Version 11 routines by Richard Johnson.
00005 Modified from that by Karl Berry <karl@umb.edu>.  8/3/89
00006 
00007 MF can now understand geometry (sort of, at least on a Sun running 3.4
00008 and using uwm) in the resource database, as in the following in
00009 .Xdefaults to put a window of width 500 and height 600 at (200,50):
00010 
00011 Metafont*geometry: 500x600+200+200
00012 
00013 You cannot give the geometry on the command line (who would want to)?
00014 
00015 The width and height specified in the resource must not be larger than
00016 the screenwidth and screendepth defined in ../mf/cmf.ch.
00017 If they are, then I reset them to the maximum.
00018 
00019 We don't handle Expose events in general. This means that the window
00020 cannot be moved, resized, or obscured. The problem is that I don't know
00021 when we can look for such events. Adding a check to the main loop of
00022 Metafont was more than I wanted to do. Another problem is that Metafont
00023 does not keep track of the contents of the screen, and so I don't see
00024 how to know what to redraw. The right way to do this is probably to fork
00025 a process, and keep a Pixmap around of the contents of the window.
00026 
00027 I could never have done this without David Rosenthal's Hello World
00028 program for X. See $X/mit/doc/HelloWorld.
00029 
00030 All section numbers refer to Xlib -- C Language X Interface.  */
00031 
00032 
00033 #define       EXTERN extern
00034 #include "../mfd.h"
00035 
00036 
00037 #ifdef X11WIN
00038 
00039 #undef input /* the XWMHints structure has a field named `input' */
00040 #undef output
00041 
00042 #include <X11/Xatom.h>
00043 #include <X11/Xlib.h>
00044 #include <X11/Xutil.h>
00045 
00046 
00047 /* Variables for communicating between the routines we'll write.  */
00048 
00049 static Display *my_display;
00050 static int my_screen;
00051 static Window my_window;
00052 static GC my_gc;
00053 static int white, black;
00054 
00055 
00056 /* Window manager hints.  */
00057 
00058 static XWMHints wm_hints = {
00059    (InputHint|StateHint), /* flags telling which values are set */
00060    False, /* We don't expect input. */
00061    NormalState, /* Initial state. */
00062    0, /* icon pixmap */
00063    0, /* icon window */
00064    0, 0, /* icon location (should get from resource?) */
00065    0, /* icon mask */
00066    0 /* window group */
00067 };
00068 
00069 
00070 /* Some constants for the resource database, etc.  */
00071 #define PROGRAM_NAME "Metafont"
00072 #define ARG_GEOMETRY "geometry"
00073 #define BORDER_WIDTH 1 /* Should get this from resource. */
00074 #define DEFAULT_X_POSITION 0
00075 #define DEFAULT_Y_POSITION 0
00076 
00077 
00078 /* Return 1 (i.e., true) if display opened successfully, else 0.  */
00079 
00080 int
00081 mf_x11_initscreen()
00082 {
00083     char *geometry;
00084     int geometry_found = 0;
00085     char default_geometry[100];
00086     XSizeHints sizehints;
00087     XGCValues gcvalues;
00088 
00089     /* We want the default display. (section 2.1 Opening the display)  */
00090     my_display = XOpenDisplay(NULL);
00091     if (my_display == NULL) return 0;
00092     
00093     /* Given a display, we can get the screen and the ``black'' and
00094        ``white'' pixels.  (section 2.2.1 Display macros)  */
00095     my_screen = DefaultScreen(my_display);     
00096     white = WhitePixel(my_display, my_screen);
00097     black = BlackPixel(my_display, my_screen);
00098     
00099     
00100     sizehints.x = DEFAULT_X_POSITION;
00101     sizehints.y = DEFAULT_Y_POSITION;
00102     sizehints.width = screenwidth;
00103     sizehints.height = screendepth;
00104     sizehints.flags = PPosition|PSize;
00105 
00106     sprintf (default_geometry, "%ux%u+%u+%u", screenwidth, screendepth,
00107                                DEFAULT_X_POSITION, DEFAULT_Y_POSITION);
00108 
00109     /* Look up the geometry for this window. (Section 10.2 Obtaining X
00110        environment defaults)  */
00111     geometry = XGetDefault(my_display, PROGRAM_NAME, ARG_GEOMETRY);
00112     
00113     if (geometry != NULL) {
00114        /* (section 10.3 Parsing window geometry) */
00115        int bitmask = XGeometry(my_display, my_screen,
00116                             geometry, default_geometry,
00117                                BORDER_WIDTH,
00118                                1, 1, /* ``Font'' width and height. */
00119                                0, 0, /* Interior padding. */
00120                                &(sizehints.x), &(sizehints.y),
00121                                &(sizehints.width), &(sizehints.height));
00122        
00123        /* (section 9.1.6 Setting and getting window sizing hints)  */
00124        if (bitmask & (XValue|YValue)) {
00125           sizehints.flags |= USPosition;
00126           geometry_found = 1;
00127        }
00128        
00129        if (bitmask & (WidthValue|HeightValue)) {
00130           sizehints.flags |= USSize;
00131           if (sizehints.width > screenwidth) sizehints.width = screenwidth;
00132           if (sizehints.height > screendepth) sizehints.height = screendepth;
00133           geometry_found = 1;
00134        }
00135     }
00136     
00137     
00138     /* Our window is pretty simple. (section 3.3 Creating windows)  */
00139     my_window = XCreateSimpleWindow(my_display,
00140                           DefaultRootWindow(my_display), /* parent */
00141                           sizehints.x, sizehints.y, /* upper left */
00142                           sizehints.width, sizehints.height,
00143                           BORDER_WIDTH,
00144                        black, /* border color */
00145                           white); /* background color */
00146     
00147     /* (section 9.1.1 Setting standard properties)  */
00148     XSetStandardProperties(my_display, my_window, 
00149                            PROGRAM_NAME,  /* window name */
00150                            PROGRAM_NAME,  /* icon name */
00151                         None,  /* pixmap for icon */
00152                            0, 0,  /* argv and argc for restarting */
00153                            &sizehints);
00154     XSetWMHints(my_display, my_window, &wm_hints);
00155     
00156     
00157     /* We need a graphics context if we're going to draw anything.
00158        (section 5.3 Manipulating graphics context/state)  */
00159     gcvalues.foreground = black;
00160     gcvalues.background = white;
00161     /* A ``thin'' line.  This is much faster than a line of length 1,
00162        although the manual cautions that the results might be less
00163        consistent across screens.  */
00164     gcvalues.line_width = 0;
00165     
00166     my_gc = XCreateGC(my_display, my_window,
00167                     GCForeground|GCBackground|GCLineWidth,
00168                     &gcvalues);
00169     
00170     /* (section 3.5 Mapping windows)  This is the confusing part of the
00171     program, at least to me. If no geometry spec was found, then the
00172     window manager puts up the blinking rectangle, and the user clicks,
00173     all before the following call returns. But if a geometry spec was
00174     found, then we want to do a whole mess of other things, because the
00175     window manager is going to send us an expose event so that we can
00176     bring our window up -- and this is one expose event we have to
00177     handle.  */
00178     XMapWindow(my_display, my_window);
00179 
00180     if (geometry_found) {
00181        /* The window manager sends us an Expose event. Yuck.
00182        */
00183        XEvent my_event;
00184        /* We certainly don't want to handle anything else.
00185           (section 8.5 Selecting events)
00186        */
00187        XSelectInput(my_display, my_window, ExposureMask);
00188 
00189        /* We also want to do this right now. This is the confusion. From
00190           stepping through the program under the debugger, it appears
00191           that it is this call to XSync (given the previous call to
00192           XSelectInput) that actually brings the window up -- and yet
00193           without the remaining code, the thing doesn't work right. Very
00194           strange. (section 8.6 Handling the output buffer)  
00195        */
00196        XSync(my_display, 0);
00197 
00198        /* Now get the event. (section 8.8.1 Returning the next event)
00199        */
00200        XNextEvent(my_display, &my_event);
00201        
00202        /* Ignore all but the last of the Expose events.
00203           (section 8.4.5.1 Expose event processing)
00204        */
00205        if (my_event.type == Expose && my_event.xexpose.count == 0) {
00206           /* Apparently the network might STILL have my_events coming in.
00207              Let's throw away Expose my_events again. (section 8.8.3
00208              Selecting my_events using a window or my_event mask)
00209           */
00210           while (XCheckTypedEvent(my_display, Expose, &my_event)) ;
00211 
00212           /* Finally, let's draw the blank screen.
00213           */
00214           XClearWindow(my_display, my_window);
00215        }
00216    }
00217     
00218     /* That's it.  */
00219     return 1;
00220 }
00221 
00222 
00223 /* Make sure the screen is up to date. (section 8.6 Handling the output
00224 buffer)  */
00225 
00226 void
00227 mf_x11_updatescreen()
00228 {
00229     XFlush(my_display);
00230 }
00231 
00232 
00233 /* Blank the rectangular inside the given coordinates. We don't need to
00234 reset the foreground to black because we always set it at the beginning
00235 of paintrow (below).  */
00236 
00237 void
00238 mf_x11_blankrectangle P4C(screencol, left,
00239                           screencol, right,
00240                           screenrow, top,
00241                           screenrow, bottom)
00242 {
00243     XSetForeground(my_display, my_gc, white);
00244     XFillRectangle(my_display, my_window, my_gc,
00245                    (int) left,
00246                    (int) top,
00247                   (unsigned) (right - left + 1),
00248                    (unsigned) (bottom - top + 1));
00249 }
00250 
00251 
00252 /* Paint a row with the given ``transition specifications''. We might be
00253 able to do something here with drawing many lines.  */
00254 
00255 void
00256 mf_x11_paintrow P4C(screenrow, row,
00257                     pixelcolor, init_color,
00258                     transspec, tvect,
00259                     register screencol, vector_size)
00260 {
00261     register int color, col;
00262 
00263     color = (init_color == 0) ? white : black;
00264 
00265     do {
00266        col = *tvect++;
00267        XSetForeground(my_display, my_gc, color);
00268         
00269         /* (section 6.3.2 Drawing single and multiple lines)
00270         */
00271        XDrawLine(my_display, my_window, my_gc, col, (int) row,
00272                 (int) *tvect, (int) row);
00273                   
00274         color = (color == white) ? black : white;
00275     } while (--vector_size > 0);
00276 }
00277 
00278 #else
00279 int x11_dummy;
00280 #endif /* X11WIN */