/********** Copyright 1990 Regents of the University of California. All rights reserved. Author: 1988 Jeffrey M. Hsu $Id$ **********/ /* X11 drivers. */ #include #ifndef X_DISPLAY_MISSING # include # include /* PN */ # include /* PN */ # include # include # include # include # include # include # include # include "../com_hardcopy.h" /* Added X11/ prefix to the next includes - ER */ # include # include # include # include # include # include # include # include # include # include # ifdef DEBUG # include /* for _Xdebug */ # endif #include "x11.h" #include "graphdb.h" #include "display.h" #include "graf.h" #include "../error.h" #define RAD_TO_DEG (180.0 / M_PI) /* X dependent default parameters */ #define DEF_FONT "10x14" #define NUMLINESTYLES 8 #define MW_LINEWIDTH 2 /* MW. I want larger lines */ #define NXPLANES 5 /* note: What is this used for? */ #define BOXSIZE 30 /* initial size of bounding box for zoomin */ #define NUMCOLORS 20 typedef struct x11info { Window window; int isopen; Widget shell, form, view, buttonbox, buttons[2]; XFontStruct *font; GC gc; int lastx, lasty; /* used in X_DrawLine */ int lastlinestyle; /* used in X_DrawLine */ Pixel colors[NUMCOLORS]; } X11devdep; #define DEVDEP(g) (*((X11devdep *) (g)->devdep)) static Display *display; static GC xorgc; static char *xlinestyles[NUMLINESTYLES] = { /* test patterns XXX */ "\001\001\001\001", /* solid */ "\001\002\001\002", /* dots */ "\007\007\007\007", /* longdash */ "\003\003\003\003", /* shortdash */ "\007\002\002\002", /* dots longdash */ "\003\002\001\002", /* dots shortdash */ "\003\003\007\003", /* short/longdash */ }; /* atoms for catching window delet by WM x-button */ static Atom atom_wm_delete_window; static Atom atom_wm_protocols; static Widget toplevel; static Bool noclear = False; static GRAPH *lasthardcopy; /* graph user selected */ static int X11_Open = 0; static int numdispplanes; /* static functions */ static void initlinestyles (void); static void initcolors (GRAPH *graph); static void X_ScreentoData (GRAPH *graph, int x, int y, double *fx, double *fy); static void linear_arc(int x0, int y0, int radius, double theta, double delta_theta); static void slopelocation(GRAPH *graph, int x0, int y0); static void zoomin(GRAPH *graph); //XtEventHandler static void handlekeypressed(Widget w, XtPointer clientdata, XEvent *ev, Boolean *continue_dispatch); static void handlebuttonev(Widget w, XtPointer graph, XEvent *ev, Boolean *continue_dispatch); static void redraw(Widget w, XtPointer client_data, XEvent *ev, Boolean *continue_dispatch); static void resize(Widget w, XtPointer client_data, XEvent *ev, Boolean *continue_dispatch); //XtCallbackProc static void hardcopy(Widget w, XtPointer client_data, XtPointer call_data); static void killwin(Widget w, XtPointer client_data, XtPointer call_data); static int errorhandler(Display *display, XErrorEvent *errorev) { XGetErrorText(display, errorev->error_code, ErrorMessage, 1024); externalerror(ErrorMessage); return 0; } int X11_Init(void) { char buf[512]; char *displayname; XGCValues gcvalues; /* grrr, Xtk forced contortions */ char *argv[2]; int argc = 2; if (cp_getvar("display", CP_STRING, buf)) { displayname = buf; } else if (!(displayname = getenv("DISPLAY"))) { internalerror("Can't open X display."); return (1); } # ifdef DEBUG _Xdebug = 1; # endif argv[0] = "ngspice"; argv[1] = displayname; /* argv[2] = "-geometry"; argv[3] = "=1x1+2+2"; */ /* initialize X toolkit */ toplevel = XtInitialize("ngspice", "Nutmeg", NULL, 0, &argc, argv); display = XtDisplay(toplevel); X11_Open = 1; /* "invert" works better than "xor" for B&W */ /* xor gc should be a function of the pixels that are written on */ /* gcvalues.function = GXxor; */ /* this patch makes lines visible on true color displays Guenther Roehrich 22-Jan-99 */ gcvalues.function = GXinvert; gcvalues.line_width = 1; gcvalues.foreground = 1; gcvalues.background = 0; xorgc = XCreateGC(display, DefaultRootWindow(display), GCLineWidth | GCFunction | GCForeground | GCBackground, &gcvalues); /* set correct information */ dispdev->numlinestyles = NUMLINESTYLES; dispdev->numcolors = NUMCOLORS; dispdev->width = DisplayWidth(display, DefaultScreen(display)); dispdev->height = DisplayHeight(display, DefaultScreen(display)); /* we don't want non-fatal X errors to call exit */ XSetErrorHandler(errorhandler); numdispplanes = DisplayPlanes(display, DefaultScreen(display)); return (0); } static void initlinestyles(void) { int i; if (numdispplanes > 1) { /* Dotted lines are a distraction when we have colors. */ for (i = 2; i < NUMLINESTYLES; i++) { xlinestyles[i] = xlinestyles[0]; } } } static void initcolors(GRAPH *graph) { int i; static char *colornames[] = { "black", /* white */ "white", "red", "blue", "orange", "green", "pink", "brown", "khaki", "plum", "orchid", "violet", "maroon", "turquoise", "sienna", "coral", "cyan", "magenta", "gold", "yellow", "" }; XColor visualcolor, exactcolor; char buf[BSIZE_SP], colorstring[BSIZE_SP]; int xmaxcolors = NUMCOLORS; /* note: can we get rid of this? */ if (numdispplanes == 1) { /* black and white */ xmaxcolors = 2; DEVDEP(graph).colors[0] = DEVDEP(graph).view->core.background_pixel; if (DEVDEP(graph).colors[0] == WhitePixel(display, DefaultScreen(display))) DEVDEP(graph).colors[1] = BlackPixel(display, DefaultScreen(display)); else DEVDEP(graph).colors[1] = WhitePixel(display, DefaultScreen(display)); } else { if (numdispplanes < NXPLANES) xmaxcolors = 1 << numdispplanes; for (i = 0; i < xmaxcolors; i++) { (void) sprintf(buf, "color%d", i); if (!cp_getvar(buf, CP_STRING, colorstring)) (void) strcpy(colorstring, colornames[i]); if (!XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)), colorstring, &visualcolor, &exactcolor)) { (void) sprintf(ErrorMessage, "can't get color %s\n", colorstring); externalerror(ErrorMessage); DEVDEP(graph).colors[i] = i ? BlackPixel(display, DefaultScreen(display)) : WhitePixel(display, DefaultScreen(display)); continue; } DEVDEP(graph).colors[i] = visualcolor.pixel; /* MW. I don't need this, everyone must know what he is doing if (i > 0 && DEVDEP(graph).colors[i] == DEVDEP(graph).view->core.background_pixel) { DEVDEP(graph).colors[i] = DEVDEP(graph).colors[0]; } */ } /* MW. Set Beackgroound here */ XSetWindowBackground(display, DEVDEP(graph).window, DEVDEP(graph).colors[0]); /* if (DEVDEP(graph).colors[0] != DEVDEP(graph).view->core.background_pixel) { DEVDEP(graph).colors[0] = DEVDEP(graph).view->core.background_pixel; } */ } for (i = xmaxcolors; i < NUMCOLORS; i++) { DEVDEP(graph).colors[i] = DEVDEP(graph).colors[i + 1 - xmaxcolors]; } } static void handlekeypressed(Widget w, XtPointer client_data, XEvent *ev, Boolean *continue_dispatch) { XKeyEvent *keyev = & ev->xkey; GRAPH *graph = (GRAPH *) client_data; char text[4]; int nbytes; NG_IGNORE(w); NG_IGNORE(continue_dispatch); nbytes = XLookupString(keyev, text, 4, NULL, NULL); if (!nbytes) return; /* write it */ PushGraphContext(graph); text[nbytes] = '\0'; SetColor(1); DevDrawText(text, keyev->x, graph->absolute.height - keyev->y); /* save it */ SaveText(graph, text, keyev->x, graph->absolute.height - keyev->y); /* warp mouse so user can type in sequence */ XWarpPointer(display, None, DEVDEP(graph).window, 0, 0, 0, 0, keyev->x + XTextWidth(DEVDEP(graph).font, text, nbytes), keyev->y); PopGraphContext(); } static void handlebuttonev(Widget w, XtPointer client_data, XEvent *ev, Boolean *continue_dispatch) { GRAPH *graph = (GRAPH *) client_data; NG_IGNORE(w); NG_IGNORE(continue_dispatch); switch (ev->xbutton.button) { case Button1: slopelocation(graph, ev->xbutton.x, ev->xbutton.y); break; case Button3: zoomin(graph); break; } } /* callback function for catching window deletion by WM x-button */ static void handle_wm_messages(Widget w, XtPointer client_data, XEvent *ev, Boolean *cont) { GRAPH *graph = (GRAPH *) client_data; NG_IGNORE(w); NG_IGNORE(cont); if (ev->type == ClientMessage && ev->xclient.message_type == atom_wm_protocols && (Atom) ev->xclient.data.l[0] == atom_wm_delete_window) { RemoveWindow(graph); } } /* Recover from bad NewViewPort call. */ #define RECOVERNEWVIEWPORT() tfree(graph);\ graph = NULL; /* need to do this or else DestroyGraph will free it again */ /* NewViewport is responsible for filling in graph->viewport */ int X11_NewViewport(GRAPH *graph) { char fontname[513]; /* who knows . . . */ char *p, *q; Cursor cursor; XSetWindowAttributes w_attrs; XGCValues gcvalues; static Arg formargs[ ] = { { XtNleft, (XtArgVal) XtChainLeft }, { XtNresizable, (XtArgVal) TRUE } }; static Arg bboxargs[ ] = { { XtNfromHoriz, (XtArgVal) NULL }, { XtNbottom, (XtArgVal) XtChainTop }, { XtNtop, (XtArgVal) XtChainTop }, { XtNleft, (XtArgVal) XtChainRight }, { XtNright, (XtArgVal) XtChainRight } }; static Arg buttonargs[ ] = { { XtNlabel, (XtArgVal) NULL }, { XtNfromVert, (XtArgVal) NULL }, { XtNbottom, (XtArgVal) XtChainTop }, { XtNtop, (XtArgVal) XtChainTop }, { XtNleft, (XtArgVal) XtRubber }, { XtNright, (XtArgVal) XtRubber }, { XtNresizable, (XtArgVal) TRUE } }; static Arg viewargs[] = { { XtNresizable, (XtArgVal) TRUE }, { XtNwidth, (XtArgVal) 300 }, { XtNheight, (XtArgVal) 300 }, { XtNright, (XtArgVal) XtChainRight } }; int trys; graph->devdep = TMALLOC(X11devdep, 1); /* set up new shell */ DEVDEP(graph).shell = XtCreateApplicationShell("shell", topLevelShellWidgetClass, NULL, 0); /* set up form widget */ DEVDEP(graph).form = XtCreateManagedWidget("form", formWidgetClass, DEVDEP(graph).shell, formargs, XtNumber(formargs)); /* set up viewport */ DEVDEP(graph).view = XtCreateManagedWidget("viewport", widgetClass, DEVDEP(graph).form, viewargs, XtNumber(viewargs)); XtAddEventHandler(DEVDEP(graph).view, ButtonPressMask, FALSE, handlebuttonev, graph); XtAddEventHandler(DEVDEP(graph).view, KeyPressMask, FALSE, handlekeypressed, graph); XtAddEventHandler(DEVDEP(graph).view, StructureNotifyMask, FALSE, resize, graph); XtAddEventHandler(DEVDEP(graph).view, ExposureMask, FALSE, redraw, graph); /* set up button box */ XtSetArg(bboxargs[1], XtNfromHoriz, DEVDEP(graph).view); DEVDEP(graph).buttonbox = XtCreateManagedWidget("buttonbox", boxWidgetClass, DEVDEP(graph).form, bboxargs, XtNumber(bboxargs)); /* set up buttons */ XtSetArg(buttonargs[0], XtNlabel, "quit"); XtSetArg(bboxargs[1], XtNfromVert, NULL); DEVDEP(graph).buttons[0] = XtCreateManagedWidget("quit", commandWidgetClass, DEVDEP(graph).buttonbox, buttonargs, 1); XtAddCallback(DEVDEP(graph).buttons[0], XtNcallback, killwin, graph); XtSetArg(buttonargs[0], XtNlabel, "hardcopy"); XtSetArg(bboxargs[1], XtNfromVert, DEVDEP(graph).buttons[0]); DEVDEP(graph).buttons[1] = XtCreateManagedWidget("hardcopy", commandWidgetClass, DEVDEP(graph).buttonbox, buttonargs, 1); XtAddCallback(DEVDEP(graph).buttons[1], XtNcallback, hardcopy, graph); /* set up fonts */ if (!cp_getvar("font", CP_STRING, fontname)) { (void) strcpy(fontname, DEF_FONT); } for (p = fontname; *p && *p <= ' '; p++) ; if (p != fontname) { for (q = fontname; *p; *q++ = *p++) ; *q = 0; } trys = 1; while (!(DEVDEP(graph).font = XLoadQueryFont(display, fontname))) { sprintf(ErrorMessage, "can't open font %s", fontname); strcpy(fontname, "fixed"); if (trys > 1) { internalerror(ErrorMessage); RECOVERNEWVIEWPORT(); return(1); } trys += 1; } graph->fontwidth = DEVDEP(graph).font->max_bounds.rbearing - DEVDEP(graph).font->min_bounds.lbearing + 1; graph->fontheight = DEVDEP(graph).font->max_bounds.ascent + DEVDEP(graph).font->max_bounds.descent + 1; XtRealizeWidget(DEVDEP(graph).shell); DEVDEP(graph).window = XtWindow(DEVDEP(graph).view); DEVDEP(graph).isopen = 0; w_attrs.bit_gravity = ForgetGravity; XChangeWindowAttributes(display, DEVDEP(graph).window, CWBitGravity, &w_attrs); /* have to note font and set mask GCFont in XCreateGC, p.w.h. */ gcvalues.font = DEVDEP(graph).font->fid; gcvalues.line_width = MW_LINEWIDTH; gcvalues.cap_style = CapNotLast; gcvalues.function = GXcopy; DEVDEP(graph).gc = XCreateGC(display, DEVDEP(graph).window, GCFont | GCLineWidth | GCCapStyle | GCFunction, &gcvalues); /* should absolute.positions really be shell.pos? */ graph->absolute.xpos = DEVDEP(graph).view->core.x; graph->absolute.ypos = DEVDEP(graph).view->core.y; graph->absolute.width = DEVDEP(graph).view->core.width; graph->absolute.height = DEVDEP(graph).view->core.height; initlinestyles(); initcolors(graph); /* set up cursor */ cursor = XCreateFontCursor(display, XC_left_ptr); XDefineCursor(display, DEVDEP(graph).window, cursor); /* WM_DELETE_WINDOW protocol */ atom_wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False); atom_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); XtAddEventHandler(DEVDEP(graph).shell, NoEventMask, True, handle_wm_messages,graph); XSetWMProtocols(display, XtWindow(DEVDEP(graph).shell), &atom_wm_delete_window, 1); return (0); } /* This routine closes the X connection. It is not to be called for finishing a graph. */ int X11_Close(void) { XCloseDisplay(display); return 0; } int X11_DrawLine(int x1, int y1, int x2, int y2) { if (DEVDEP(currentgraph).isopen) XDrawLine(display, DEVDEP(currentgraph).window, DEVDEP(currentgraph).gc, x1, currentgraph->absolute.height - y1, x2, currentgraph->absolute.height - y2); return 0; } int X11_Arc(int x0, int y0, int radius, double theta, double delta_theta) { int t1, t2; if (0 && !cp_getvar("x11lineararcs", CP_BOOL, NULL)) { linear_arc(x0, y0, radius, theta, delta_theta); } if (DEVDEP(currentgraph).isopen) { t1 = (int) (64 * (180.0 / M_PI) * theta); t2 = (int) (64 * (180.0 / M_PI) * delta_theta); if (t2 == 0) return 0; XDrawArc(display, DEVDEP(currentgraph).window, DEVDEP(currentgraph).gc, x0 - radius, currentgraph->absolute.height - radius - y0, (Dimension) (2 * radius), (Dimension) (2 * radius), t1, t2); } return 0; } /* note: x and y are the LOWER left corner of text */ int X11_Text(char *text, int x, int y) { /* We specify text position by lower left corner, so have to adjust for X11's font nonsense. */ if (DEVDEP(currentgraph).isopen) XDrawString(display, DEVDEP(currentgraph).window, DEVDEP(currentgraph).gc, x, currentgraph->absolute.height - (y + DEVDEP(currentgraph).font->max_bounds.descent), text, (int) strlen(text)); /* note: unlike before, we do not save any text here */ return 0; } int X11_DefineColor(int colorid, double red, double green, double blue) { NG_IGNORE(blue); NG_IGNORE(green); NG_IGNORE(red); NG_IGNORE(colorid); internalerror("X11_DefineColor not implemented."); return 0; } int X11_DefineLinestyle(int linestyleid, int mask) { NG_IGNORE(mask); NG_IGNORE(linestyleid); internalerror("X11_DefineLinestyle not implemented."); return 0; } int X11_SetLinestyle(int linestyleid) { XGCValues values; if (currentgraph->linestyle != linestyleid) { if ((linestyleid == 0 || numdispplanes > 1) && linestyleid != 1) { /* solid if linestyle 0 or if has color, allow only one * dashed linestyle */ values.line_style = LineSolid; } else { values.line_style = LineOnOffDash; } XChangeGC(display, DEVDEP(currentgraph).gc, GCLineStyle, &values); currentgraph->linestyle = linestyleid; XSetDashes(display, DEVDEP(currentgraph).gc, 0, xlinestyles[linestyleid], 4); } return 0; } int X11_SetColor(int colorid) { currentgraph->currentcolor = colorid; XSetForeground(display, DEVDEP(currentgraph).gc, DEVDEP(currentgraph).colors[colorid]); return 0; } int X11_Update(void) { if (X11_Open) XSync(display, 0); return 0; } int X11_Clear(void) { if (!noclear) /* hack so exposures look like they're handled nicely */ XClearWindow(display, DEVDEP(currentgraph).window); return 0; } static void X_ScreentoData(GRAPH *graph, int x, int y, double *fx, double *fy) { double lmin, lmax; if (graph->grid.gridtype == GRID_XLOG || graph->grid.gridtype == GRID_LOGLOG) { lmin = log10(graph->datawindow.xmin); lmax = log10(graph->datawindow.xmax); *fx = exp(((x - graph->viewportxoff) * (lmax - lmin) / graph->viewport.width + lmin) * M_LN10); } else { *fx = (x - graph->viewportxoff) * graph->aspectratiox + graph->datawindow.xmin; } if (graph->grid.gridtype == GRID_YLOG || graph->grid.gridtype == GRID_LOGLOG) { lmin = log10(graph->datawindow.ymin); lmax = log10(graph->datawindow.ymax); *fy = exp(((graph->absolute.height - y - graph->viewportxoff) * (lmax - lmin) / graph->viewport.height + lmin) * M_LN10); } else { *fy = ((graph->absolute.height - y) - graph->viewportyoff) * graph->aspectratioy + graph->datawindow.ymin; } } static void slopelocation(GRAPH *graph, int x0, int y0) /* initial position of mouse */ { int x1, y1; int x, y; Window rootwindow, childwindow; int rootx, rooty; unsigned int state; double fx0, fx1, fy0, fy1; double angle; x1 = x0; y1 = y0; XQueryPointer(display, DEVDEP(graph).window, &rootwindow, &childwindow, &rootx, &rooty, &x, &y, &state); XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); while (state & Button1Mask) { if (x != x1 || y != y1) { XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); x1 = x; y1 = y; XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); } XQueryPointer(display, DEVDEP(graph).window, &rootwindow, &childwindow, &rootx, &rooty, &x, &y, &state); } XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); X_ScreentoData(graph, x0, y0, &fx0, &fy0); X_ScreentoData(graph, x1, y1, &fx1, &fy1); /* print it out */ if (x1 == x0 && y1 == y0) { /* only one location */ fprintf(stdout, "\nx0 = %g, y0 = %g\n", fx0, fy0); if (graph->grid.gridtype == GRID_POLAR || graph->grid.gridtype == GRID_SMITH || graph->grid.gridtype == GRID_SMITHGRID) { angle = RAD_TO_DEG * atan2( fy0, fx0 ); fprintf(stdout, "r0 = %g, a0 = %g\n", sqrt( fx0*fx0 + fy0*fy0 ), (angle>0)?angle:360.0+angle); } } else { /* need to print info about two points */ fprintf(stdout, "\nx0 = %g, y0 = %g x1 = %g, y1 = %g\n", fx0, fy0, fx1, fy1); fprintf(stdout, "dx = %g, dy = %g\n", fx1-fx0, fy1 - fy0); if (x1 != x0 && y1 != y0) { /* add slope info if both dx and dy are zero, because otherwise either dy/dx or dx/dy is zero, which is uninteresting */ fprintf(stdout, "dy/dx = %g dx/dy = %g\n", (fy1-fy0)/(fx1-fx0), (fx1-fx0)/(fy1-fy0)); } } return; } /* should be able to do this by sleight of hand on graph parameters */ static void zoomin(GRAPH *graph) { /* note: need to add circular boxes XXX */ int x0, y0, x1, y1; double fx0, fx1, fy0, fy1, ftemp; char buf[BSIZE_SP]; char buf2[128]; char *t; Window rootwindow, childwindow; int rootx, rooty; unsigned int state; int x, y, upperx, uppery; unsigned width, height; /* open box and get area to zoom in on */ XQueryPointer(display, DEVDEP(graph).window, &rootwindow, &childwindow, &rootx, &rooty, &x0, &y0, &state); x = x1 = x0 + BOXSIZE; y = y1 = y0 + BOXSIZE; upperx = x0; uppery = y0; width = BOXSIZE; height = BOXSIZE; XDrawRectangle(display, DEVDEP(graph).window, xorgc, upperx, uppery, width, height); XWarpPointer(display, None, DEVDEP(graph).window, 0, 0, 0, 0, x1, y1); while (state & Button3Mask) { if (x != x1 || y != y1) { x1 = x; y1 = y; XDrawRectangle(display, DEVDEP(graph).window, xorgc, upperx, uppery, width, height); upperx = MIN(x1, x0); uppery = MIN(y1, y0); width = (unsigned) ABS(x1 - x0); height = (unsigned) ABS(y1 - y0); XDrawRectangle(display, DEVDEP(graph).window, xorgc, upperx, uppery, width, height); } XQueryPointer(display, DEVDEP(graph).window, &rootwindow, &childwindow, &rootx, &rooty, &x, &y, &state); } XDrawRectangle(display, DEVDEP(graph).window, xorgc, upperx, uppery, width, height); X_ScreentoData(graph, x0, y0, &fx0, &fy0); X_ScreentoData(graph, x1, y1, &fx1, &fy1); if (fx0 > fx1) { ftemp = fx0; fx0 = fx1; fx1 = ftemp; } if (fy0 > fy1) { ftemp = fy0; fy0 = fy1; fy1 = ftemp; } strncpy(buf2, graph->plotname, sizeof(buf2)); if ((t = strchr(buf2, ':')) != NULL) *t = 0; if (!eq(plot_cur->pl_typename, buf2)) { (void) sprintf(buf, "setplot %s; %s xlimit %.20e %.20e ylimit %.20e %.20e; setplot $curplot\n", buf2, graph->commandline, fx0, fx1, fy0, fy1); } else { (void) sprintf(buf, "%s xlimit %e %e ylimit %e %e\n", graph->commandline, fx0, fx1, fy0, fy1); } /* don't use the following if using GNU Readline or BSD EditLine */ #if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) { wordlist *wl; /* hack for Gordon Jacobs */ /* add to history list if plothistory is set */ if (cp_getvar("plothistory", CP_BOOL, NULL)) { wl = cp_parse(buf); (void) cp_addhistent(cp_event++, wl); } } #endif /* !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) */ (void) cp_evloop(buf); } static void hardcopy(Widget w, XtPointer client_data, XtPointer call_data) { NG_IGNORE(call_data); NG_IGNORE(w); /* com_hardcopy() -> gr_resize() -> setcolor() dirung postscript printing will act on currentgraph with a DEVDEP inherited from PSdevdep. But currentgraph had not changed its devdep, which was derived from incompatible X11devdep, thus overwriting some variables. Here you find a temporary remedy, until there will be a cleanup of graph handling. E.g. CopyGraph() does not make a copy of its devdep, but just copies the pointer, so keeping the old devdep. */ lasthardcopy = (GRAPH *) client_data; /* FIXME #1: this should print currentgraph with * currentgraph dynamically bound to client_data * FIXME #2: the !currentgraphs case, * don't bother do call com_hardcopy */ if (currentgraph) { void *devdep = currentgraph->devdep; com_hardcopy(NULL); currentgraph->devdep = devdep; } else { com_hardcopy(NULL); } } static void killwin(Widget w, XtPointer client_data, XtPointer call_data) { GRAPH *graph = (GRAPH *) client_data; NG_IGNORE(call_data); NG_IGNORE(w); RemoveWindow(graph); } /* called from postcoms.c In the command 'destroy ac2' Will remove window associated with the plot (e.g. ac2) just before data of the plot are deleted.*/ void RemoveWindow(GRAPH *graph) { if(graph->devdep) { /* Iplots are done asynchronously */ DEVDEP(graph).isopen = 0; /* MW. Not sure but DestroyGraph might free() to much - try Xt...() first */ XtDestroyWidget(DEVDEP(graph).shell); } if (graph == currentgraph) currentgraph = NULL; DestroyGraph(graph->graphid); } /* call higher gr_redraw routine */ static void redraw(Widget w, XtPointer client_data, XEvent *event, Boolean *continue_dispatch) { GRAPH *graph = (GRAPH *) client_data; XExposeEvent *pev = & event->xexpose; XEvent ev; XRectangle rects[30]; int n = 1; NG_IGNORE(w); NG_IGNORE(continue_dispatch); DEVDEP(graph).isopen = 1; rects[0].x = (Position) pev->x; rects[0].y = (Position) pev->y; rects[0].width = (Dimension) pev->width; rects[0].height = (Dimension) pev->height; /* XXX */ /* pull out all other expose regions that need to be redrawn */ while (n < 30 && XCheckWindowEvent(display, DEVDEP(graph).window, ExposureMask, &ev)) { pev = (XExposeEvent *) &ev; rects[n].x = (Position) pev->x; rects[n].y = (Position) pev->y; rects[n].width = (Dimension) pev->width; rects[n].height = (Dimension) pev->height; n++; } XSetClipRectangles(display, DEVDEP(graph).gc, 0, 0, rects, n, Unsorted); noclear = True; { GRAPH *tmp = currentgraph; currentgraph = graph; gr_redraw(graph); currentgraph = tmp; } noclear = False; XSetClipMask(display, DEVDEP(graph).gc, None); } static void resize(Widget w, XtPointer client_data, XEvent *call_data, Boolean *continue_dispatch) { GRAPH *graph = (GRAPH *) client_data; XEvent ev; NG_IGNORE(call_data); NG_IGNORE(continue_dispatch); /* pull out all other exposure events Also, get rid of other StructureNotify events on this window. */ while (XCheckWindowEvent(display, DEVDEP(graph).window, /* ExposureMask | */ StructureNotifyMask, &ev)) ; XClearWindow(display, DEVDEP(graph).window); graph->absolute.width = w->core.width; graph->absolute.height = w->core.height; { GRAPH *tmp = currentgraph; currentgraph = graph; gr_resize(graph); currentgraph = tmp; } } int X11_Input(REQUEST *request, RESPONSE *response) { XEvent ev; int nfds; fd_set rfds; switch (request->option) { case char_option: nfds = ConnectionNumber(display) > fileno(request->fp) ? ConnectionNumber(display) : fileno(request->fp); for (;;) { /* first read off the queue before doing the select */ while (XtPending()) { XtNextEvent(&ev); XtDispatchEvent(&ev); } /* block on ConnectionNumber and request->fp */ /* PN: added fd_set * casting */ FD_ZERO(&rfds); FD_SET(fileno(request->fp), &rfds); FD_SET(ConnectionNumber(display), &rfds); select (nfds + 1, &rfds, NULL, NULL, NULL); /* handle X events first */ if (FD_ISSET (ConnectionNumber(display), &rfds)) { /* handle ALL X events */ while (XtPending()) { XtNextEvent(&ev); XtDispatchEvent(&ev); } } if (FD_ISSET (fileno(request->fp), &rfds)) { goto out; } } break; case click_option: /* let's fake this */ response->reply.graph = lasthardcopy; break; case button_option: /* sit and handle events until get a button selection */ internalerror("button_option not implemented"); response->option = error_option; return 1; break; case checkup_option: /* first read off the queue before doing the select */ while (XtPending()) { XtNextEvent(&ev); XtDispatchEvent(&ev); } break; default: internalerror("unrecognized input type"); response->option = error_option; return 1; break; } out: if (response) response->option = request->option; return 0; } static void linear_arc(int x0, int y0, int radius, double theta, double delta_theta) /* x coordinate of center */ /* y coordinate of center */ /* radius of arc */ /* initial angle ( +x axis = 0 rad ) */ /* delta angle */ /* * Notes: * Draws an arc of radius and center at (x0,y0) beginning at * angle theta (in rad) and ending at theta + delta_theta */ { int x1, y1, x2, y2; int i, s = 60; double dphi; x2 = x0 + (int) (radius * cos(theta)); y2 = y0 + (int) (radius * sin(theta)); dphi = delta_theta / s; for(i=1; i<=s; i++) { x1 = x2; y1 = y2; x2 = x0 + (int)(radius * cos(theta + i*dphi)); y2 = y0 + (int)(radius * sin(theta + i*dphi)); X11_DrawLine(x1,y1,x2,y2); } } #else int x11_dummy_symbol; /* otherwise, some linkers get upset */ #endif /* X_DISPLAY_MISSING */