/*=========== The X V11R2 Window System driver for gplot ====================*/ #include #ifdef VMS #include #include #include #include #include #else /* UNIX */ #include #include #include #include #include #endif #include "defs.h" #include "xws_defs.h" extern int cla_init(); /* gplot's cell array manipulation package initializer */ /*======== Global X Variables intended for the X Driver only ========*/ Widget Toplevel; /* X Toolkit - the top level widget */ Display *Dpy; /* display */ int Scr; /* screen number */ Window Win; /* window id */ Window Topwin; /* top-level window id */ XWindowAttributes window_attributes; /* attributes of Win */ GC LineGC; /* Graphic Context for polylines and points */ GC MarkerGC; /* Graphic Context for markers */ GC PolygonGC; /* Graphic Context for polygon fill */ GC EdgeGC; /* Graphic Context for polygon edges */ GC CellArrayGC; /* Graphic Context for cell array */ GC TextGC; /* Graphic Context for text */ XFontStruct *Xfs; /* X font attributes for text */ XPoint Points[MAX_POINTS]; /* point array for vector graphics */ XSegment Segments[MAX_SEGMENTS]; /* segment array for vector graphics */ Cursor WaitCursor; /* used between begin and end page */ Cursor ReadyCursor; /* used when translation is complete */ XImage *sample_image; /* generated to learn about the display */ /*======== Other Global Variables for the X Driver only ========*/ /* * Metafile_Defaults is a boolean flag which controls loading of the * metafile defaults replacement elements which define color defaults * for indexed color metacode. */ char *ProgramName; /* copy of argv[0] for messages */ struct mf_d_struct *CGMClass1; /* CGM Metafile Descriptor Elements */ struct pic_d_struct *CGMClass2; /* CGM Picture Descriptor Elements */ struct control_struct *CGMClass3; /* CGM Control Elements */ struct attrib_struct *CGMClass5; /* CGM Attribute Elements */ struct info_struct *pDev_xws; /* copy of dev info struct pointer */ short MaxY; /* maximum y coordinate in X window */ short MaxX; /* maximum x coordinate in X window */ short Metafile_Defaults=TRUE; /* for default colors */ int my_byte_order; /* This machine's byte ordering */ int my_bit_order; /* This machine's bit ordering */ int manage_own_window; /* open and manage own window */ static void xws_xws_init(pargc, argv) int *pargc; char *argv[]; { static Arg args[] = { {XtNwidth, (XtArgVal) DEFAULT_WIDTH}, {XtNheight,(XtArgVal) DEFAULT_HEIGHT}, }; /* The default size of the window. The user can override this with the * -geometry command line argument, or through the window manager, or * through the ".Xdefaults" file. */ Widget graph_widget; /* X Toolkit */ XSizeHints hints; /* window manager size hints */ /* Check to see if the drawing window has already been opened * (presumably by a user interface). If not, open it. */ if (!Dpy) { manage_own_window= TRUE; /* Open the X server connection, parse standard parts of the command * line, and create the initial widget. * * In order to recognize X toolkit options, the driver must process * the argc and argv passed to the main routine of gplot. * argc (via pargc) and argv are modified by XtInitialize(). * No application-specific options are parsed by this driver; only * X Toolkit options are parsed and removed from the command line. * * User can specify preferences for this application if user knows * application name and widget class name (argv[0] and GPlot). * Application resources are loaded from, in order, * /usr/lib/X11/app-defaults/GPlot * server resource file * ~/.Xdefaults or ~/.Xdefaults-hostname * command line arguments * See section 4.2 of "X Toolkit Intrinsics - C Language Interface," * by McCormack, Asente, & Swick; and the article "Using and * Specifying X Resources" by Jim Fulton, and comments in the * routine xws_window_size(), and see gplot X documentation. */ Toplevel = XtInitialize(argv[0], APP_CLASS, (XrmOptionDescRec *) NULL, 0, pargc, argv); /* Allocate the widget instance and set instance-specific attributes. * Inform widget's parent of the new child. */ graph_widget = XtCreateManagedWidget("graph", widgetClass, Toplevel, args, XtNumber(args)); /* Create windows, making the top window visible to the user */ XtRealizeWidget(Toplevel); /* At this point we enter the level of the Xlib interface. */ Dpy = XtDisplay(graph_widget); Win = XtWindow(graph_widget); Topwin = XtWindow(Toplevel); /* for xws_window_size() */ XSelectInput(Dpy, Win, ExposureMask); /* Set window manager size hints */ hints.width = DEFAULT_WIDTH; hints.height = DEFAULT_HEIGHT; hints.flags = PSize; XSetNormalHints(Dpy, Win, &hints); } else manage_own_window= FALSE; /* user interface will manage it */ Scr = DefaultScreen(Dpy); /* Make our cursors */ WaitCursor = XCreateFontCursor(Dpy, XC_watch); ReadyCursor = XCreateFontCursor(Dpy, XC_X_cursor); } static void xws_gc_init() { unsigned long valuemask; XGCValues xgcv; /* GCs control attributes of Graphical Primitive Elements */ valuemask = (GCForeground | GCBackground); xgcv.background = WhitePixel(Dpy, Scr); xgcv.foreground = BlackPixel(Dpy, Scr); if (((LineGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0) || ((MarkerGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0) || ((PolygonGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0) || ((EdgeGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0) || ((CellArrayGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0) || ((TextGC = XCreateGC(Dpy, Win, valuemask, &xgcv)) == 0)) (void) fprintf(stderr, "%s: display %s cannot create GC\n", ProgramName, DisplayString(Dpy)); } static void xws_font_init(pDev_info) struct info_struct *pDev_info; { /* Load the font into the X server and get information on it. */ if ((Xfs = XLoadQueryFont(Dpy, DEFAULT_FONT)) == NULL) { (void) fprintf(stderr, "%s: display %s doesn't know font %s\n", ProgramName, DisplayString(Dpy), DEFAULT_FONT); return; } /* I am using proportionally spaced fonts, where not all characters * have the same width. Therefore I'll tell gplot that the character * width is the the maximum width over all characters in the font. */ pDev_info->c_width= Xfs->max_bounds.rbearing - Xfs->min_bounds.lbearing; pDev_info->c_height = Xfs->max_bounds.ascent + Xfs->max_bounds.descent; XSetFont(Dpy, TextGC, Xfs->fid); } #define MILLIMETERS_PER_INCH 25.40000 static void xws_gplot_init(pDev_info, pdelim, pgprim, pattr) struct info_struct *pDev_info; int (*pdelim[]) (); int (*pgprim[]) (); int (*pattr[]) (); { /* Save a pointer to the device info struct */ pDev_xws= pDev_info; /* X origin is at (0,0); see xws_window_size for size setting */ pDev_info->x_offset = 0.0; pDev_info->y_offset = 0.0; /* How many pixels per inch in the x and y directions? */ pDev_info->pxl_in = (float) DisplayWidth(Dpy, Scr) / (float) DisplayWidthMM(Dpy, Scr) * (MILLIMETERS_PER_INCH); pDev_info->ypxl_in = (float) DisplayHeight(Dpy, Scr) / (float) DisplayHeightMM(Dpy, Scr) * (MILLIMETERS_PER_INCH); /* X line width by default is 0, which is a line of 1 pixel width */ /* X edge width is functionally the same as line width */ pDev_info->d_l_width = pDev_info->d_e_width = 1; /* gplot will adjust the default marker size to suit itself. */ pDev_info->d_m_size = DEFAULT_MARKER_SIZE; /* Device capability bit vector: interface document lacks definitions. * Provided by this driver are: * horizontal text centering * vertical text centering * string text precision would be on if we were not * emulating text. */ pDev_info->capability = v_center | h_center; /* Allow gplot to call the following functions ... */ /* Class 0 - Delimiter Elements */ pdelim[(int) B_Mf] = xws_begin; /* begin metafile */ pdelim[(int) E_Mf] = xws_end; /* end metafile */ pdelim[(int) B_Pic] = xws_bpic; /* begin picture */ pdelim[(int) B_Pic_Body] = xws_bpage; /* begin picture body*/ pdelim[(int) E_Pic] = xws_epage; /* end picture */ /* Class 4 - Graphical Primitive Elements */ pgprim[(int) PolyLine] = xws_pline; /* polyline */ pgprim[(int) Dis_Poly] = xws_dpline; /* disjoint polyline */ pgprim[(int) PolyMarker] = xws_pmarker; /* polymarker */ pgprim[(int) Polygon] = xws_pgon; /* polygon */ pgprim[(int) Cell_Array] = xws_carray; /* cell array */ /* No text routine is needed, since text is being emulated. */ /*pgprim[(int) Text] = xws_text; *//* text */ /* Class 5 - Attribute Elements */ pattr[(int) LType] = xws_l_type; /* line type */ pattr[(int) LWidth] = xws_l_width; /* line width */ pattr[(int) LColour] = xws_l_colour; /* line colour */ pattr[(int) MType] = xws_mk_type; /* marker type */ pattr[(int) MSize] = xws_mk_size; /* marker size */ pattr[(int) MColour] = xws_mk_colour; /* marker colour */ pattr[(int) IntStyle] = xws_fl_style; /* interior style */ pattr[(int) FillColour] = xws_fl_colour; /* fill colour */ pattr[(int) EType] = xws_e_type; /* edge type */ pattr[(int) EdWidth] = xws_e_width; /* edge width */ pattr[(int) EdColour] = xws_e_colour; /* edge color */ pattr[(int) ColTab] = xws_ctab; /* modify color table */ /* Text is now handled by emulation, so these are not needed */ /*pattr[(int) TColour] = xws_t_colour;*//* text colour */ /*pattr[(int) TAlign] = xws_t_align;*//* text alignment */ } static void xws_window_size(pDev_info) struct info_struct *pDev_info; { XEvent event; /* for event notification */ XExposeEvent *expose_event; /* for reporting actual window size */ /* There are two cases of this routine- the case where the driver is * to manage its own window, and the case where a user interface is * doing it and the driver need do very little. */ if (manage_own_window) { /* * In order to guarantee reliable applications, applications must wait until * the first expose event before proceeding to draw. Some window managers * will intercept the map request to control placement or add window * decoration. In these cases, your map request never takes place, but the * window manager gets around to issuing one on your behalf sometime later. * Graphics requests sent in this interval of time may be lost. * * Expose events were selected in xws_xws_init(). */ expose_event = (XExposeEvent *) &event; while (TRUE) { XtNextEvent(&event); if (event.type == Expose && expose_event->count == 0) break; } /* Because the user may employ the window manager to create a window of a * size other than the default, wait until the first window expose event is * completed before determing the window size, then inform gplot of the size. * * However, if the user creates the window so that it is larger than the * default size, things don't work as expected. The window is opened in the * requested size, but the width and height returned in the XExposeEvent * structure are the default sizes, and therefore the graphics output will * occur in a subarea of the window, in the upper left corner, in an area * defined by the default size of the window. This may be because the * underlying toolkit windows have not been resized larger as well, but * that is an unconfirmed guess. * * To use a window larger (or smaller) than the default size, use * the -geometry command line argument, as in: * gplot -geometry 800x800+0+0 -dx metafile * You can effectively define your own default window size by specifying * geometry in your .Xdefaults file; see documentation accompanying code. * GPlot*geometry: 800x800 */ pDev_info->x_size = ((float) expose_event->width) / pDev_info->pxl_in; pDev_info->y_size = ((float) expose_event->height) / pDev_info->ypxl_in; /* Determine the maximum y coordinate for coordinate translation. Gplot * assumes an origin of (0,0) in the lower left corner. X has an origin of * (0,0) in the upper left corner. The maximum x coordinate is used only for * marker clipping. */ MaxX = expose_event->height - 1; MaxY = expose_event->width - 1; } else /* clause for when a user interface is managing the window */ { /* All of these values will be reset before the first CGM elements * are drawn. Since we cannot trap an exposure event for fear of * messing up the user interface, and since the window may not * yet be open, all we can really do is insert place-holder values. */ pDev_info->x_size= 1.0; pDev_info->y_size= 1.0; MaxX= 100; MaxY= 100; } } /* Create a trivial sample image, to learn the image characteristics of * this device. */ static void xws_sample_image() { long junk= 0; /* fake data for the image */ sample_image= XCreateImage(Dpy, DefaultVisual(Dpy,Scr), (unsigned int)DefaultDepth(Dpy,Scr), ZPixmap, 0, (char *) &junk, 1, 1, BitmapPad(Dpy), 0 ); } /* This routine figures out the bit and byte ordering (most significant * or least significant bit or byte first) of the machine it's running * on. */ static void xws_order_check() { unsigned long bytechk= 1; unsigned char bitchk= 1; /* The following checks byte ordering by grabbing the first byte of an unsigned long containing the value 1. If any bit is on, the LSB is stored first. */ if ( *(char *)&bytechk ) my_byte_order= LSBFirst; else my_byte_order= MSBFirst; /* The following checks to see if a single left shift pushes a value '1' out of an unsigned char. If it does, the bits of the char are stored LSB first. */ if ( (char) ( bitchk << 1 ) ) my_bit_order= MSBFirst; else my_bit_order= LSBFirst; } void /*ARGSUSED*/ xws_setup(pOp, pDev_info, pc1, pc2, pc3, pc5, pdelim, pmfdesc, pdesc, pmfctrl, pgprim, pattr, pescfun, pextfun, pctrl, pargc, argv) struct one_opt *pOp; /* not used - I use pargc and argv */ struct info_struct *pDev_info; struct mf_d_struct *pc1; struct pic_d_struct *pc2; struct control_struct *pc3; struct attrib_struct *pc5; int (*pdelim[]) (); int (*pmfdesc[]) (); int (*pdesc[]) (); int (*pmfctrl[]) (); int (*pgprim[]) (); int (*pattr[]) (); int (*pescfun[]) (); int (*pextfun[]) (); int (*pctrl[])(); /* controller functions */ int *pargc; char *argv[]; { ProgramName = argv ? argv[0] : "gplot"; /* Initialize gplot's cell array utilities */ cla_init( pc1, pc2, pc5, pgprim, pattr ); /* initialize X by opening the display, creating and mapping windows */ xws_xws_init(pargc,argv); /* initialize color */ xws_color_init(); /* initialize Graphic Contexts */ xws_gc_init(); /* At this point we would initialize font, but since fonts are now completely emulated there is no need to do so. xws_font_init(pDev_info); */ /* make copies of gplot's global variable pointers (silly) */ CGMClass1 = pc1; CGMClass2 = pc2; CGMClass3 = pc3; CGMClass5 = pc5; /* initialize gplot data structures */ xws_gplot_init(pDev_info, pdelim, pgprim, pattr); /* block until the window is exposed, then determine window size */ xws_window_size(pDev_info); /* Select the events for which we want future notification. These * apply to the remainder of this client's lifetime, and are checked * at the end of each metacode frame by xws_epage(). */ if (manage_own_window) XSelectInput(Dpy, Win, (ButtonPressMask | EnterWindowMask | KeyPressMask | LeaveWindowMask)); /* Get a sample image, to learn about the display. */ xws_sample_image(); /* Check bit and byte order (MSBFirst, LSBFirst) of this machine */ xws_order_check(); }