/* x11.c: X11 window interface for Metafont, using Xt. Original by rusty@garnet.berkeley.edu. */ #define EXTERN extern #include "../mfd.h" #ifdef X11WIN /* almost whole file */ /* For wchar_t et al., that the X files might want. */ #include #undef input /* the XWMHints structure has a field named `input' */ #undef output #include #include #include #undef wchar_t #define PLANE 0 static unsigned int mf_defwidth = 0; static unsigned int mf_defheight = 0; static Display *mf_display; static Window mf_window; static Pixmap mf_pixmap; static XtAppContext mf_app; static GC mf_dgc; /* draw gc */ static GC mf_egc; /* erase gc */ static GC mf_cgc; /* copy plane gc */ typedef struct { unsigned int mf_width, mf_height; Pixel mf_fg, mf_bg; } mf_resources_struct; static mf_resources_struct mf_x11_resources; /* Don't paint anything until we're mapped. */ static Boolean mf_mapped = False; static Boolean mf_awaiting_expose = True; #ifdef MF_XT_DEBUG static int mf_max_x, mf_max_y; static int mf_min_x, mf_min_y; static void mf_checkextent (); #endif static XtResource mf_resources[] = { { "width", "Width", XtRInt, sizeof (int), XtOffset (mf_resources_struct *, mf_width), XtRInt, (XtPointer) & mf_defwidth }, { "height", "Height", XtRInt, sizeof (int), XtOffset (mf_resources_struct *, mf_height), XtRInt, (XtPointer) &mf_defheight }, { "foreground", "Foreground", XtRPixel, sizeof (Pixel), XtOffset (mf_resources_struct *, mf_fg), XtRString, (XtPointer) "Black" }, { "background", "Background", XtRPixel, sizeof (Pixel), XtOffset (mf_resources_struct *, mf_bg), XtRString, (XtPointer) "White" }, }; /* Maybe someday we'll read options, until then, this is just here for the resources. */ static XrmOptionDescRec mf_optiondesclist[] = { { "-width", "width", XrmoptionSepArg, (XPointer) NULL }, { "-height", "height", XrmoptionSepArg, (XPointer) NULL }, { "-fg", "foreground", XrmoptionSepArg, (XPointer) NULL }, { "-bg", "background", XrmoptionSepArg, (XPointer) NULL }, }; static void mf_events(void); static void mf_mapstatus(Widget w, XtPointer data, XEvent *ev); static void mf_newpixmap(unsigned int width, unsigned int height); static void mf_redraw(void); static void mf_repaint(Widget w, XtPointer data, XEvent *ev); #include /* Return 1 if display opened successfully, else 0. */ int mf_x11_initscreen (void) { XSetWindowAttributes xwa; Widget mf_toplevel; Widget mf_canvas; XGCValues gcv; Arg args[1]; int mf_argc; char *mf_argv[2]; mf_argv[0] = "mf"; mf_argv[1] = NULL; mf_argc = 1; mf_toplevel = XtInitialize ("mf", "Metafont", mf_optiondesclist, XtNumber (mf_optiondesclist), &mf_argc, mf_argv); XtGetApplicationResources (mf_toplevel, (XtPointer) & mf_x11_resources, mf_resources, XtNumber (mf_resources), NULL, 0); if (mf_argc != 1) { fprintf (stderr, "Usage: %s\n", mf_argv[0]); return 0; } /* If nothing specified in their resources (e.g., .Xdefaults) then use the values of Metafont's "screen". */ if (mf_x11_resources.mf_width == 0) mf_x11_resources.mf_width = screenwidth; if (mf_x11_resources.mf_height == 0) mf_x11_resources.mf_height = screendepth; mf_canvas = XtCreateManagedWidget ("canvas", widgetClass, mf_toplevel, NULL, 0); XtSetArg (args[0], XtNwidth, mf_x11_resources.mf_width); XtSetValues (mf_canvas, args, 1); XtSetArg (args[0], XtNheight, mf_x11_resources.mf_height); XtSetValues (mf_canvas, args, 1); /* for mf_x11_updatescreen() */ mf_app = XtWidgetToApplicationContext (mf_canvas); XtAddEventHandler (mf_canvas, (Cardinal) ExposureMask, True, (XtEventHandler) mf_repaint, NULL); XtAddEventHandler (mf_canvas, (Cardinal) StructureNotifyMask, True, (XtEventHandler) mf_mapstatus, NULL); XtRealizeWidget (mf_toplevel); mf_display = XtDisplay (mf_canvas); mf_window = XtWindow (mf_canvas); /* Since Metafont isn't your typical x window program that sits in XTMainLoop, if the server supports backing store and save unders this will help keep the output looking nice. */ xwa.backing_store = WhenMapped; XChangeWindowAttributes (mf_display, mf_window, CWBackingStore, &xwa); gcv.background = mf_x11_resources.mf_bg; gcv.foreground = mf_x11_resources.mf_fg; gcv.function = GXcopy; /* copy plane gc */ mf_cgc = XCreateGC (mf_display, mf_window, GCForeground | GCBackground | GCFunction, &gcv); mf_newpixmap (screenwidth > mf_x11_resources.mf_width ? screenwidth : mf_x11_resources.mf_width, screendepth > mf_x11_resources.mf_height ? screendepth : mf_x11_resources.mf_height); return 1; } void mf_x11_updatescreen (void) { XEvent event; mf_events (); while (mf_awaiting_expose) { XtAppNextEvent (mf_app, &event); XtDispatchEvent (&event); } mf_redraw (); #ifdef MF_XT_DEBUG printf ("max_x=%d, min_x=%d, max_y=%d, min_y=%d\n", mf_max_x, mf_min_x, mf_max_y, mf_min_y); #endif } void mf_x11_blankrectangle(screencol left, screencol right, screenrow top, screenrow bottom) { XFillRectangle (mf_display, mf_pixmap, mf_egc, (int) left, (int) top, (int) (right - left + 1), (int) (bottom - top + 1)); mf_events (); } void mf_x11_paintrow(screenrow row, pixelcolor init_color, transspec tvect, screencol vector_size) { GC gc; int col; gc = (init_color == 0) ? mf_egc : mf_dgc; do { col = *tvect++; #ifdef MF_XT_DEBUG mf_checkextent (col, *tvect, row); #endif /* MF_XT_DEBUG */ XDrawLine (mf_display, mf_pixmap, gc, col, (int) row, (int) *tvect, (int) row); gc = (gc == mf_egc) ? mf_dgc : mf_egc; } while (--vector_size > 0); mf_events (); } #ifdef MF_XT_DEBUG static void mf_checkextent(int x1, int x2, int y) { if (x1 < mf_min_x) mf_min_x = x1; if (x1 > mf_max_x) mf_max_x = x1; if (x2 < mf_min_x) mf_min_x = x2; if (x2 > mf_max_x) mf_max_x = x2; if (y > mf_max_y) mf_max_y = y; if (y < mf_min_y) mf_min_y = y; } #endif /* MF_XT_DEBUG */ static void mf_events (void) { XEvent event; if (XtAppPending (mf_app) != 0) { while (XtAppPending (mf_app) != 0) { XtAppNextEvent (mf_app, &event); XtDispatchEvent (&event); } } } static void mf_newpixmap(unsigned int width, unsigned int height) { XGCValues gcv; Pixmap newpixmap; /* width == mf_width and height == mf_height the first time mf_newpixmap() is called. */ if (width < mf_x11_resources.mf_width && height < mf_x11_resources.mf_height) return; newpixmap = XCreatePixmap (mf_display, mf_window, width, height, 1); gcv.background = 0; gcv.foreground = 1; if (mf_dgc != 0) XFreeGC (mf_display, mf_dgc); /* draw gc */ gcv.line_width = 1; mf_dgc = XCreateGC (mf_display, newpixmap, GCForeground | GCBackground | GCLineWidth, &gcv); if (mf_egc != 0) XFreeGC (mf_display, mf_egc); /* erase gc */ gcv.foreground = 0; mf_egc = XCreateGC (mf_display, newpixmap, GCForeground | GCBackground | GCLineWidth, &gcv); XFillRectangle (mf_display, newpixmap, mf_egc, 0, 0, width, height); if (mf_pixmap != 0) { XCopyArea (mf_display, mf_pixmap, newpixmap, mf_dgc, 0, 0, mf_x11_resources.mf_width, mf_x11_resources.mf_height, 0, 0); XFreePixmap (mf_display, mf_pixmap); } mf_pixmap = newpixmap; mf_x11_resources.mf_width = width; mf_x11_resources.mf_height = height; } static void mf_repaint(Widget w, XtPointer data, XEvent *ev) { if (!mf_mapped || !ev || ev->type != Expose) return; /* We are a ``simple application''. */ if (ev->xexpose.count == 0) { XEvent event; /* skip all excess redraws */ while (XCheckTypedEvent (mf_display, Expose, &event) != False) continue; mf_redraw (); mf_awaiting_expose = False; } } static void mf_mapstatus(Widget w, XtPointer data, XEvent *ev) { switch (ev->type) { case MapNotify: mf_mapped = True; break; case UnmapNotify: mf_mapped = False; break; case ConfigureNotify: mf_newpixmap (ev->xconfigure.width, ev->xconfigure.height); mf_redraw (); break; } } static void mf_redraw (void) { XCopyPlane (mf_display, mf_pixmap, mf_window, mf_cgc, 0, 0, mf_x11_resources.mf_width, mf_x11_resources.mf_height, 0, 0, (unsigned long) 1); XFlush (mf_display); } #else int x11_dummy; #endif /* X11WIN */