Annotation of OpenXM_contrib/gnuplot/gplt_x11.c, Revision 1.1.1.1
1.1 maekawa 1: #ifndef lint
2: static char *RCSid = "$Id: gplt_x11.c,v 1.71 1998/04/14 00:15:22 drd Exp $";
3: #endif
4:
5: /* GNUPLOT - gplt_x11.c */
6:
7: /*[
8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
9: *
10: * Permission to use, copy, and distribute this software and its
11: * documentation for any purpose with or without fee is hereby granted,
12: * provided that the above copyright notice appear in all copies and
13: * that both that copyright notice and this permission notice appear
14: * in supporting documentation.
15: *
16: * Permission to modify the software is granted, but not the right to
17: * distribute the complete modified source code. Modifications are to
18: * be distributed as patches to the released version. Permission to
19: * distribute binaries produced by compiling modified sources is granted,
20: * provided you
21: * 1. distribute the corresponding source modifications from the
22: * released version in the form of a patch file along with the binaries,
23: * 2. add special version identification to distinguish your version
24: * in addition to the base release version number,
25: * 3. provide your name and address as the primary contact for the
26: * support of your modified version, and
27: * 4. retain our contact information in regard to use of the base
28: * software.
29: * Permission to distribute the released version of the source code along
30: * with corresponding source modifications in the form of a patch file is
31: * granted with same provisions 2 through 4 for binary distributions.
32: *
33: * This software is provided "as is" without express or implied warranty
34: * to the extent permitted by applicable law.
35: ]*/
36:
37:
38: /* lph changes:
39: * (a) make EXPORT_SELECTION the default and specify NOEXPORT to undefine
40: * (b) append X11 terminal number to resource name
41: * (c) change cursor for active terminal
42: */
43:
44: /*-----------------------------------------------------------------------------
45: * gnuplot_x11 - X11 outboard terminal driver for gnuplot 3.3
46: *
47: * Requires installation of companion inboard x11 driver in gnuplot/term.c
48: *
49: * Acknowledgements:
50: * Chris Peterson (MIT)
51: * Dana Chee (Bellcore)
52: * Arthur Smith (Cornell)
53: * Hendri Hondorp (University of Twente, The Netherlands)
54: * Bill Kucharski (Solbourne)
55: * Charlie Kline (University of Illinois)
56: * Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
57: * Russell Lang (Monash University, Australia)
58: * O'Reilly & Associates: X Window System - Volumes 1 & 2
59: *
60: * This code is provided as is and with no warranties of any kind.
61: *
62: * drd: change to allow multiple windows to be maintained independently
63: *
64: * There is a mailing list for gnuplot users. Note, however, that the
65: * newsgroup
66: * comp.graphics.apps.gnuplot
67: * is identical to the mailing list (they
68: * both carry the same set of messages). We prefer that you read the
69: * messages through that newsgroup, to subscribing to the mailing list.
70: * (If you can read that newsgroup, and are already on the mailing list,
71: * please send a message to majordomo@dartmouth.edu, asking to be
72: * removed from the mailing list.)
73: *
74: * The address for mailing to list members is
75: * info-gnuplot@dartmouth.edu
76: * and for mailing administrative requests is
77: * majordomo@dartmouth.edu
78: * The mailing list for bug reports is
79: * bug-gnuplot@dartmouth.edu
80: * The list of those interested in beta-test versions is
81: * info-gnuplot-beta@dartmouth.edu
82: *---------------------------------------------------------------------------*/
83:
84: /* drd : export the graph via ICCCM primary selection. well... not quite
85: * ICCCM since we dont support full list of targets, but this
86: * is a start. define EXPORT_SELECTION if you want this feature
87: */
88:
89: /*lph: add a "feature" to undefine EXPORT_SELECTION
90: The following makes EXPORT_SELECTION the default and
91: defining NOEXPORT over-rides the default
92: */
93:
94: #ifdef HAVE_CONFIG_H
95: # include "config.h"
96: #endif
97:
98: #ifdef EXPORT_SELECTION
99: # undef EXPORT_SELECTION
100: #endif /* EXPORT SELECTION */
101: #ifndef NOEXPORT
102: # define EXPORT_SELECTION XA_PRIMARY
103: #endif /* NOEXPORT */
104:
105:
106: #if !(defined(VMS) || defined(CRIPPLED_SELECT))
107: # define DEFAULT_X11
108: #endif
109:
110: #if defined(VMS) && defined(CRIPPLED_SELECT)
111: Error. Incompatible options.
112: #endif
113:
114:
115: #include <X11/Xos.h>
116: #include <X11/Xlib.h>
117: #include <X11/Xresource.h>
118: #include <X11/Xutil.h>
119: #include <X11/Xatom.h>
120: #include <X11/keysym.h>
121:
122: #include <signal.h>
123:
124: #ifdef HAVE_SYS_BSDTYPES_H
125: # include <sys/bsdtypes.h>
126: #endif /* HAVE_SYS_BSDTYPES_H */
127:
128: #ifdef __EMX__
129: /* for gethostname ... */
130: # include <netdb.h>
131: #endif
132:
133: #if defined(HAVE_SYS_SELECT_H) && !defined(VMS)
134: # include <sys/select.h>
135: #endif /* HAVE_SYS_SELECT_H && !VMS */
136:
137: #ifndef FD_SET
138: # define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << ((n) % 32)))
139: # define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << ((n) % 32)))
140: # define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << ((n) % 32)))
141: # define FD_ZERO(p) memset((char *)(p),'\0',sizeof(*(p)))
142: #endif /* not FD_SET */
143:
144: #include "plot.h"
145:
146: #if defined(HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_SYSINFO)
147: # include <sys/systeminfo.h>
148: # define SYSINFO_METHOD "sysinfo"
149: # define GP_SYSTEMINFO(host) sysinfo (SI_HOSTNAME, (host), MAXHOSTNAMELEN)
150: #else
151: # define SYSINFO_METHOD "gethostname"
152: # define GP_SYSTEMINFO(host) gethostname ((host), MAXHOSTNAMELEN)
153: #endif /* HAVE_SYS_SYSTEMINFO_H && HAVE_SYSINFO */
154:
155: #ifdef VMS
156: # ifdef __DECC
157: # include <starlet.h>
158: # endif /* __DECC */
159: # define EXIT(status) sys$delprc(0,0) /* VMS does not drop itself */
160: #else
161: # define EXIT(status) exit(status)
162: #endif
163:
164: #ifdef OSK
165: # define EINTR E_ILLFNC
166: #endif
167:
168: /* information about one window/plot */
169:
170: typedef struct plot_struct {
171: Window window;
172: Pixmap pixmap;
173: unsigned int posn_flags;
174: int x, y;
175: unsigned int width, height; /* window size */
176: unsigned int px, py; /* pointsize */
177: int ncommands, max_commands;
178: char **commands;
179: } plot_struct;
180:
181: void store_command __PROTO((char *line, plot_struct * plot));
182: void prepare_plot __PROTO((plot_struct * plot, int term_number));
183: void delete_plot __PROTO((plot_struct * plot));
184:
185: int record __PROTO((void));
186: void process_event __PROTO((XEvent * event)); /* from Xserver */
187:
188: void mainloop __PROTO((void));
189:
190: void display __PROTO((plot_struct * plot));
191:
192: void reset_cursor __PROTO((void));
193:
194: void preset __PROTO((int argc, char *argv[]));
195: char *pr_GetR __PROTO((XrmDatabase db, char *resource));
196: void pr_color __PROTO((void));
197: void pr_dashes __PROTO((void));
198: void pr_font __PROTO((void));
199: void pr_geometry __PROTO((void));
200: void pr_pointsize __PROTO((void));
201: void pr_width __PROTO((void));
202: Window pr_window __PROTO((unsigned int flags, int x, int y, unsigned int width, unsigned height));
203: void pr_raise __PROTO((void));
204: void pr_persist __PROTO((void));
205:
206: #ifdef EXPORT_SELECTION
207: void export_graph __PROTO((plot_struct * plot));
208: void handle_selection_event __PROTO((XEvent * event));
209: #endif
210:
211: #define FallbackFont "fixed"
212:
213: #define Ncolors 13
214: unsigned long colors[Ncolors];
215:
216: #define Nwidths 10
217: unsigned int widths[Nwidths] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
218:
219: #define Ndashes 10
220: char dashes[Ndashes][5];
221:
222: #define MAX_WINDOWS 16
223:
224: #define XC_crosshair 34
225:
226:
227: struct plot_struct plot_array[MAX_WINDOWS];
228:
229:
230: Display *dpy;
231: int scr;
232: Window root;
233: Visual *vis;
234: GC gc = (GC) 0;
235: XFontStruct *font;
236: int do_raise = 1, persist = 0;
237: KeyCode q_keycode;
238: Cursor cursor;
239:
240: int windows_open = 0;
241:
242: int gX = 100, gY = 100;
243: unsigned int gW = 640, gH = 450;
244: unsigned int gFlags = PSize;
245:
246: unsigned int BorderWidth = 2;
247: unsigned int D; /* depth */
248:
249: Bool Mono = 0, Gray = 0, Rv = 0, Clear = 0;
250: char Name[64] = "gnuplot";
251: char Class[64] = "Gnuplot";
252:
253: int cx = 0, cy = 0, vchar;
254: double xscale, yscale, pointsize;
255: #define X(x) (int) ((x) * xscale)
256: #define Y(y) (int) ((4095-(y)) * yscale)
257:
258: #define Nbuf 1024
259: char buf[Nbuf], **commands = (char **) 0;
260:
261: FILE *X11_ipc;
262: char X11_ipcpath[32];
263:
264: /* when using an ICCCM-compliant window manager, we can ask it
265: * to send us an event when user chooses 'close window'. We do this
266: * by setting WM_DELETE_WINDOW atom in property WM_PROTOCOLS
267: */
268:
269: Atom WM_PROTOCOLS, WM_DELETE_WINDOW;
270:
271: XPoint Diamond[5], Triangle[4];
272: XSegment Plus[2], Cross[2], Star[4];
273:
274: /*-----------------------------------------------------------------------------
275: * main program
276: *---------------------------------------------------------------------------*/
277:
278: int main(argc, argv)
279: int argc;
280: char *argv[];
281: {
282:
283:
284: #ifdef OSK
285: /* malloc large blocks, otherwise problems with fragmented mem */
286: _mallocmin(102400);
287: #endif
288: #ifdef __EMX__
289: /* close open file handles */
290: fcloseall();
291: #endif
292:
293: FPRINTF((stderr, "gnuplot_X11 starting up\n"));
294:
295: preset(argc, argv);
296:
297: /* set up the alternative cursor */
298: cursor = XCreateFontCursor(dpy, XC_crosshair);
299:
300: mainloop();
301:
302: if (persist) {
303: FPRINTF((stderr, "waiting for %d windows\n, windows_open"));
304: /* read x events until all windows have been quit */
305: while (windows_open > 0) {
306: XEvent event;
307: XNextEvent(dpy, &event);
308: process_event(&event);
309: }
310: }
311: XCloseDisplay(dpy);
312:
313: FPRINTF((stderr, "exiting\n"));
314:
315: EXIT(0);
316: }
317:
318: /*-----------------------------------------------------------------------------
319: * mainloop processing - process X events and input from gnuplot
320: *
321: * Three different versions of main loop processing are provided to support
322: * three different platforms.
323: *
324: * DEFAULT_X11: use select() for both X events and input on stdin
325: * from gnuplot inboard driver
326: *
327: * CRIPPLED_SELECT: use select() to service X events and check during
328: * select timeout for temporary plot file created
329: * by inboard driver
330: *
331: * VMS: use XNextEvent to service X events and AST to
332: * service input from gnuplot inboard driver on stdin
333: *---------------------------------------------------------------------------*/
334:
335:
336: #ifdef DEFAULT_X11
337: /*-----------------------------------------------------------------------------
338: * DEFAULT_X11 mainloop
339: *---------------------------------------------------------------------------*/
340:
341: void mainloop()
342: {
343: int nf, nfds, cn = ConnectionNumber(dpy), in;
344: struct timeval *timer = (struct timeval *) 0;
345: #ifdef ISC22
346: struct timeval timeout;
347: #endif
348: fd_set rset, tset;
349:
350: X11_ipc = stdin;
351: in = fileno(X11_ipc);
352:
353: FD_ZERO(&rset);
354: FD_SET(cn, &rset);
355:
356: FD_SET(in, &rset);
357: nfds = (cn > in) ? cn + 1 : in + 1;
358:
359: #ifdef ISC22
360: /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
361: timeout.tv_sec = 0; /* select() in ISC2.2 needs timeout */
362: timeout.tv_usec = 300000; /* otherwise input from gnuplot is */
363: timer = &timeout; /* suspended til next X event. */
364: #endif /* ISC22 (0.3s are short enough not to be noticed */
365:
366: while (1) {
367:
368: /* XNextEvent does an XFlush() before waiting. But here.
369: * we must ensure that the queue is flushed, since we
370: * dont call XNextEvent until an event arrives. (I have
371: * twice wasted quite some time over this issue, so now
372: * I am making sure of it !
373: */
374:
375: XFlush(dpy);
376:
377: tset = rset;
378: nf = select((gp_nfds_t)nfds, gp_fd_set_p &tset, gp_fd_set_p 0,
379: gp_fd_set_p 0, gp_timeval_p timer);
380: if (nf < 0) {
381: if (errno == EINTR)
382: continue;
383: fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
384: EXIT(1);
385: }
386: if (nf > 0)
387: XNoOp(dpy);
388:
389: if (FD_ISSET(cn, &tset)) {
390: /* used to use CheckMaskEvent() but that cannot receive
391: * maskable events such as ClientMessage. So now we do
392: * one event, then return to the select.
393: * And that almost works, except that under some Xservers
394: * running without a window manager (e.g. Hummingbird Exceed under Win95)
395: * a bogus ConfigureNotify is sent followed by a valid ConfigureNotify
396: * when the window is maximized. The two events are queued, apparently
397: * in a single I/O because select() above doesn't see the second, valid
398: * event. This little loop fixes the problem by flushing the
399: * event queue completely.
400: */
401: XEvent xe;
402: do {
403: XNextEvent(dpy, &xe);
404: process_event(&xe);
405: } while (XPending(dpy));
406: }
407: if (FD_ISSET(in, &tset)) {
408: if (!record()) /* end of input */
409: return;
410: }
411: }
412: }
413:
414: #endif
415:
416:
417: #ifdef CRIPPLED_SELECT
418: /*-----------------------------------------------------------------------------
419: * CRIPPLED_SELECT mainloop
420: *---------------------------------------------------------------------------*/
421:
422: void mainloop()
423: {
424: int nf, nfds, cn = ConnectionNumber(dpy);
425: struct timeval timeout, *timer;
426: fd_set rset, tset;
427: unsigned long all = (unsigned long) (-1L);
428: XEvent xe;
429:
430: FD_ZERO(&rset);
431: FD_SET(cn, &rset);
432:
433: timeout.tv_sec = 1;
434: timeout.tv_usec = 0;
435: timer = &timeout;
436: sprintf(X11_ipcpath, "/tmp/Gnuplot_%d", getppid());
437: nfds = cn + 1;
438:
439: while (1) {
440: XFlush(dpy); /* see above */
441: tset = rset;
442: nf = select((gp_nfds_t)nfds, gp_fd_set_p &tset, gp_fd_set_p 0,
443: gp_fd_set_p 0, gp_timeval_p timer);
444: if (nf < 0) {
445: if (errno == EINTR)
446: continue;
447: fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
448: EXIT(1);
449: }
450: nf > 0 && XNoOp(dpy);
451: if (FD_ISSET(cn, &tset)) {
452: while (XCheckMaskEvent(dpy, all, &xe)) {
453: process_event(&xe);
454: }
455: }
456: if ((X11_ipc = fopen(X11_ipcpath, "r"))) {
457: unlink(X11_ipcpath);
458: record();
459: fclose(X11_ipc);
460: }
461: }
462: }
463: #endif /* CRIPPLED_SELECT */
464:
465:
466: #ifdef VMS
467: /*-----------------------------------------------------------------------------
468: * VMS mainloop - Yehavi Bourvine - YEHAVI@VMS.HUJI.AC.IL
469: *---------------------------------------------------------------------------*/
470:
471: /* In VMS there is no decent Select(). hence, we have to loop inside
472: * XGetNextEvent for getting the next X window event. In order to get input
473: * from the master we assign a channel to SYS$INPUT and use AST's in order to
474: * receive data. In order to exit the mainloop, we need to somehow make XNextEvent
475: * return from within the ast. We do this with a XSendEvent() to ourselves !
476: * This needs a window to send the message to, so we create an unmapped window
477: * for this purpose. Event type XClientMessage is perfect for this, but it
478: * appears that such messages come from elsewhere (motif window manager, perhaps ?)
479: * So we need to check fairly carefully that it is the ast event that has been received.
480: */
481:
482: #include <iodef.h>
483: char STDIIN[] = "SYS$INPUT:";
484: short STDIINchannel, STDIINiosb[4];
485: struct { short size, type; char *address; } STDIINdesc;
486: char STDIINbuffer[64];
487: int status;
488:
489: ast()
490: {
491: int status = sys$qio(0, STDIINchannel, IO$_READVBLK, STDIINiosb, record,
492: 0, STDIINbuffer, sizeof(STDIINbuffer) - 1, 0, 0, 0, 0);
493: if ((status & 0x1) == 0)
494: EXIT(status);
495: }
496:
497: Window message_window;
498:
499: void mainloop()
500: {
501: /* dummy unmapped window for receiving internally-generated terminate
502: * messages
503: */
504: message_window = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 0, 0);
505:
506: STDIINdesc.size = strlen(STDIIN);
507: STDIINdesc.type = 0;
508: STDIINdesc.address = STDIIN;
509: status = sys$assign(&STDIINdesc, &STDIINchannel, 0, 0, 0);
510: if ((status & 0x1) == 0)
511: EXIT(status);
512: ast();
513:
514: for (;;) {
515: XEvent xe;
516: XNextEvent(dpy, &xe);
517: if (xe.type == ClientMessage && xe.xclient.window == message_window) {
518: if (xe.xclient.message_type == None &&
519: xe.xclient.format == 8 &&
520: strcmp(xe.xclient.data.b, "die gnuplot die") == 0) {
521: FPRINTF((stderr, "quit message from ast\n"));
522: return;
523: } else {
524: FPRINTF((stderr, "Bogus XClientMessage event from window manager ?\n"));
525: }
526: }
527: process_event(&xe);
528: }
529: }
530:
531: #endif /* VMS */
532:
533: /* delete a window / plot */
534:
535: void delete_plot(plot)
536: plot_struct *plot;
537: {
538: int i;
539:
540: FPRINTF((stderr, "Delete plot %d\n", plot - plot_array));
541:
542: for (i = 0; i < plot->ncommands; ++i)
543: free(plot->commands[i]);
544: plot->ncommands = 0;
545:
546: if (plot->window) {
547: FPRINTF((stderr, "Destroy window 0x%x\n", plot->window));
548: XDestroyWindow(dpy, plot->window);
549: plot->window = None;
550: --windows_open;
551: }
552: if (plot->pixmap) {
553: XFreePixmap(dpy, plot->pixmap);
554: plot->pixmap = None;
555: }
556: /* but preserve geometry */
557: }
558:
559:
560: /* prepare the plot structure */
561:
562: void prepare_plot(plot, term_number)
563: plot_struct *plot;
564: int term_number;
565: {
566: int i;
567: char *term_name;
568:
569: for (i = 0; i < plot->ncommands; ++i)
570: free(plot->commands[i]);
571: plot->ncommands = 0;
572:
573: if (!plot->posn_flags) {
574: /* first time this window has been used - use default or -geometry
575: * settings
576: */
577: plot->posn_flags = gFlags;
578: plot->x = gX;
579: plot->y = gY;
580: plot->width = gW;
581: plot->height = gH;
582: }
583:
584: if (!plot->window) {
585: plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
586: ++windows_open;
587:
588: /* append the X11 terminal number (if greater than zero) */
589:
590: if (term_number) {
591: char new_name[60];
592: XFetchName(dpy, plot->window, &term_name);
593: FPRINTF((stderr, "Window title is %s\n", term_name));
594:
595: sprintf(new_name, "%.55s%3d", term_name, term_number);
596: FPRINTF((stderr, "term_number is %d\n", term_number));
597:
598: XStoreName(dpy, plot->window, new_name);
599:
600: sprintf(new_name, "gplt%3d", term_number);
601: XSetIconName(dpy, plot->window, new_name);
602: }
603: }
604: /* We don't know that it is the same window as before, so we reset the
605: * cursors for all windows and then define the cursor for the active
606: * window
607: */
608: reset_cursor();
609: XDefineCursor(dpy, plot->window, cursor);
610:
611: }
612:
613: /* store a command in a plot structure */
614:
615: void store_command(buffer, plot)
616: char *buffer;
617: plot_struct *plot;
618: {
619: char *p;
620:
621: FPRINTF((stderr, "Store in %d : %s", plot - plot_array, buffer));
622:
623: if (plot->ncommands >= plot->max_commands) {
624: plot->max_commands = plot->max_commands * 2 + 1;
625: plot->commands = (plot->commands)
626: ? (char **) realloc(plot->commands, plot->max_commands * sizeof(char *))
627: : (char **) malloc(sizeof(char *));
628: }
629: p = (char *) malloc((unsigned) strlen(buffer) + 1);
630: if (!plot->commands || !p) {
631: fputs("gnuplot: can't get memory. X11 aborted.\n", stderr);
632: EXIT(1);
633: }
634: plot->commands[plot->ncommands++] = strcpy(p, buffer);
635: }
636:
637: #ifndef VMS
638: /*-----------------------------------------------------------------------------
639: * record - record new plot from gnuplot inboard X11 driver (Unix)
640: *---------------------------------------------------------------------------*/
641:
642: int record()
643: {
644: static plot_struct *plot = plot_array;
645:
646: while (fgets(buf, Nbuf, X11_ipc)) {
647: switch (*buf) {
648: case 'G': /* enter graphics mode */
649: {
650: int plot_number = atoi(buf + 1); /* 0 if none specified */
651:
652: if (plot_number < 0 || plot_number >= MAX_WINDOWS)
653: plot_number = 0;
654:
655: FPRINTF((stderr, "plot for window number %d\n", plot_number));
656: plot = plot_array + plot_number;
657: prepare_plot(plot, plot_number);
658: continue;
659: }
660: case 'E': /* leave graphics mode / suspend */
661: display(plot);
662: return 1;
663: case 'R': /* leave x11 mode */
664: reset_cursor();
665: return 0;
666: default:
667: store_command(buf, plot);
668: continue;
669: }
670: }
671:
672: /* get here if fgets fails */
673:
674: #ifdef OSK
675: if (feof(X11_ipc)) /* On OS-9 sometimes while resizing the window, */
676: _cleareof(X11_ipc); /* and plotting data, the eof or error flag of */
677: if (ferror(X11_ipc)) /* X11_ipc stream gets set, while there is */
678: clearerr(X11_ipc); /* nothing wrong! Probably a bug in my select()? */
679: #else
680: if (feof(X11_ipc) || ferror(X11_ipc))
681: return 0;
682: #endif /* not OSK */
683:
684: return 1;
685: }
686:
687: #else /* VMS */
688: /*-----------------------------------------------------------------------------
689: * record - record new plot from gnuplot inboard X11 driver (VMS)
690: *---------------------------------------------------------------------------*/
691:
692: record()
693: {
694: static plot_struct *plot = plot_array;
695:
696: int status;
697:
698: if ((STDIINiosb[0] & 0x1) == 0)
699: EXIT(STDIINiosb[0]);
700: STDIINbuffer[STDIINiosb[1]] = '\0';
701: strcpy(buf, STDIINbuffer);
702:
703: switch (*buf) {
704: case 'G': /* enter graphics mode */
705: {
706: int plot_number = atoi(buf + 1); /* 0 if none specified */
707: if (plot_number < 0 || plot_number >= MAX_WINDOWS)
708: plot_number = 0;
709: FPRINTF((stderr, "plot for window number %d\n", plot_number));
710: plot = plot_array + plot_number;
711: prepare_plot(plot, plot_number);
712: break;
713: }
714: case 'E': /* leave graphics mode */
715: display(plot);
716: break;
717: case 'R': /* exit x11 mode */
718: FPRINTF((stderr, "received R - sending ClientMessage\n"));
719: reset_cursor();
720: sys$cancel(STDIINchannel);
721: /* this is ridiculous - cook up an event to ourselves,
722: * in order to get the mainloop() out of the XNextEvent() call
723: * it seems that window manager can also send clientmessages,
724: * so put a checksum into the message
725: */
726: {
727: XClientMessageEvent event;
728: event.type = ClientMessage;
729: event.send_event = True;
730: event.display = dpy;
731: event.window = message_window;
732: event.message_type = None;
733: event.format = 8;
734: strcpy(event.data.b, "die gnuplot die");
735: XSendEvent(dpy, message_window, False, 0, (XEvent *) & event);
736: XFlush(dpy);
737: }
738: return; /* no ast */
739: default:
740: store_command(buf, plot);
741: break;
742: }
743: ast();
744: }
745: #endif /* VMS */
746:
747:
748: /*-----------------------------------------------------------------------------
749: * display - display a stored plot
750: *---------------------------------------------------------------------------*/
751:
752: void display(plot)
753: plot_struct *plot;
754: {
755: int n, x, y, sw, sl, lt = 0, width, type, point, px, py;
756: int user_width = 1; /* as specified by plot...linewidth */
757: char *buffer, *str;
758: enum JUSTIFY jmode;
759:
760: FPRINTF((stderr, "Display %d ; %d commands\n", plot - plot_array, plot->ncommands));
761:
762: if (plot->ncommands == 0)
763: return;
764:
765: /* set scaling factor between internal driver & window geometry */
766: xscale = plot->width / 4096.0;
767: yscale = plot->height / 4096.0;
768:
769: /* initial point sizes, until overridden with P7xxxxyyyy */
770: px = (int) (xscale * pointsize);
771: py = (int) (yscale * pointsize);
772:
773: /* create new pixmap & GC */
774: if (gc)
775: XFreeGC(dpy, gc);
776:
777: if (!plot->pixmap) {
778: FPRINTF((stderr, "Create pixmap %d : %dx%dx%d\n", plot - plot_array, plot->width, plot->height, D));
779: plot->pixmap = XCreatePixmap(dpy, root, plot->width, plot->height, D);
780: }
781:
782: gc = XCreateGC(dpy, plot->pixmap, 0, (XGCValues *) 0);
783:
784: XSetFont(dpy, gc, font->fid);
785:
786: /* set pixmap background */
787: XSetForeground(dpy, gc, colors[0]);
788: XFillRectangle(dpy, plot->pixmap, gc, 0, 0, plot->width, plot->height);
789: XSetBackground(dpy, gc, colors[0]);
790:
791: if (!plot->window) {
792: plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
793: ++windows_open;
794: }
795: /* top the window but don't put keyboard or mouse focus into it. */
796: if (do_raise)
797: XMapRaised(dpy, plot->window);
798:
799: /* momentarily clear the window first if requested */
800: if (Clear) {
801: XClearWindow(dpy, plot->window);
802: XFlush(dpy);
803: }
804: /* loop over accumulated commands from inboard driver */
805: for (n = 0; n < plot->ncommands; n++) {
806: buffer = plot->commands[n];
807:
808: /* X11_vector(x,y) - draw vector */
809: if (*buffer == 'V') {
810: sscanf(buffer, "V%4d%4d", &x, &y);
811: XDrawLine(dpy, plot->pixmap, gc, X(cx), Y(cy), X(x), Y(y));
812: cx = x;
813: cy = y;
814: }
815: /* X11_move(x,y) - move */
816: else if (*buffer == 'M')
817: sscanf(buffer, "M%4d%4d", &cx, &cy);
818:
819: /* X11_put_text(x,y,str) - draw text */
820: else if (*buffer == 'T') {
821: sscanf(buffer, "T%4d%4d", &x, &y);
822: str = buffer + 9;
823: sl = strlen(str) - 1;
824: sw = XTextWidth(font, str, sl);
825:
826: switch (jmode) {
827: case LEFT:
828: sw = 0;
829: break;
830: case CENTRE:
831: sw = -sw / 2;
832: break;
833: case RIGHT:
834: sw = -sw;
835: break;
836: }
837:
838: XSetForeground(dpy, gc, colors[2]);
839: XDrawString(dpy, plot->pixmap, gc, X(x) + sw, Y(y) + vchar / 3, str, sl);
840: XSetForeground(dpy, gc, colors[lt + 3]);
841: } else if (*buffer == 'F') { /* fill box */
842: int style, xtmp, ytmp, w, h;
843:
844: if (sscanf(buffer + 1, "%4d%4d%4d%4d%4d", &style, &xtmp, &ytmp, &w, &h) == 5) {
845: /* gnuplot has origin at bottom left, but X uses top left
846: * There may be an off-by-one (or more) error here.
847: * style ignored here for the moment
848: */
849: ytmp += h; /* top left corner of rectangle to be filled */
850: w *= xscale;
851: h *= yscale;
852: XSetForeground(dpy, gc, colors[0]);
853: XFillRectangle(dpy, plot->pixmap, gc, X(xtmp), Y(ytmp), w, h);
854: XSetForeground(dpy, gc, colors[lt + 3]);
855: }
856: }
857: /* X11_justify_text(mode) - set text justification mode */
858: else if (*buffer == 'J')
859: sscanf(buffer, "J%4d", (int *) &jmode);
860:
861: /* X11_linewidth(width) - set line width */
862: else if (*buffer == 'W')
863: sscanf(buffer + 1, "%4d", &user_width);
864:
865: /* X11_linetype(type) - set line type */
866: else if (*buffer == 'L') {
867: sscanf(buffer, "L%4d", <);
868: lt = (lt % 8) + 2;
869: /* default width is 0 {which X treats as 1} */
870: width = widths[lt] ? user_width * widths[lt] : user_width;
871: if (dashes[lt][0]) {
872: type = LineOnOffDash;
873: XSetDashes(dpy, gc, 0, dashes[lt], strlen(dashes[lt]));
874: } else {
875: type = LineSolid;
876: }
877: XSetForeground(dpy, gc, colors[lt + 3]);
878: XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
879: }
880: /* X11_point(number) - draw a point */
881: else if (*buffer == 'P') {
882: /* linux sscanf does not like %1d%4d%4d" with Oxxxxyyyy */
883: /* sscanf(buffer, "P%1d%4d%4d", &point, &x, &y); */
884: point = buffer[1] - '0';
885: sscanf(buffer + 2, "%4d%4d", &x, &y);
886: if (point == 7) {
887: /* set point size */
888: px = (int) (x * xscale * pointsize);
889: py = (int) (y * yscale * pointsize);
890: } else {
891: if (type != LineSolid || width != 0) { /* select solid line */
892: XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinBevel);
893: }
894: switch (point) {
895: case 0: /* dot */
896: XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
897: break;
898: case 1: /* do diamond */
899: Diamond[0].x = (short) X(x) - px;
900: Diamond[0].y = (short) Y(y);
901: Diamond[1].x = (short) px;
902: Diamond[1].y = (short) -py;
903: Diamond[2].x = (short) px;
904: Diamond[2].y = (short) py;
905: Diamond[3].x = (short) -px;
906: Diamond[3].y = (short) py;
907: Diamond[4].x = (short) -px;
908: Diamond[4].y = (short) -py;
909:
910: /*
911: * Should really do a check with XMaxRequestSize()
912: */
913: XDrawLines(dpy, plot->pixmap, gc, Diamond, 5, CoordModePrevious);
914: XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
915: break;
916: case 2: /* do plus */
917: Plus[0].x1 = (short) X(x) - px;
918: Plus[0].y1 = (short) Y(y);
919: Plus[0].x2 = (short) X(x) + px;
920: Plus[0].y2 = (short) Y(y);
921: Plus[1].x1 = (short) X(x);
922: Plus[1].y1 = (short) Y(y) - py;
923: Plus[1].x2 = (short) X(x);
924: Plus[1].y2 = (short) Y(y) + py;
925:
926: XDrawSegments(dpy, plot->pixmap, gc, Plus, 2);
927: break;
928: case 3: /* do box */
929: XDrawRectangle(dpy, plot->pixmap, gc, X(x) - px, Y(y) - py, (px + px), (py + py));
930: XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
931: break;
932: case 4: /* do X */
933: Cross[0].x1 = (short) X(x) - px;
934: Cross[0].y1 = (short) Y(y) - py;
935: Cross[0].x2 = (short) X(x) + px;
936: Cross[0].y2 = (short) Y(y) + py;
937: Cross[1].x1 = (short) X(x) - px;
938: Cross[1].y1 = (short) Y(y) + py;
939: Cross[1].x2 = (short) X(x) + px;
940: Cross[1].y2 = (short) Y(y) - py;
941:
942: XDrawSegments(dpy, plot->pixmap, gc, Cross, 2);
943: break;
944: case 5: /* do triangle */
945: {
946: short temp_x, temp_y;
947:
948: temp_x = (short) (1.33 * (double) px + 0.5);
949: temp_y = (short) (1.33 * (double) py + 0.5);
950:
951: Triangle[0].x = (short) X(x);
952: Triangle[0].y = (short) Y(y) - temp_y;
953: Triangle[1].x = (short) temp_x;
954: Triangle[1].y = (short) 2 *py;
955: Triangle[2].x = (short) -(2 * temp_x);
956: Triangle[2].y = (short) 0;
957: Triangle[3].x = (short) temp_x;
958: Triangle[3].y = (short) -(2 * py);
959:
960: XDrawLines(dpy, plot->pixmap, gc, Triangle, 4, CoordModePrevious);
961: XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
962: }
963: break;
964: case 6: /* do star */
965: Star[0].x1 = (short) X(x) - px;
966: Star[0].y1 = (short) Y(y);
967: Star[0].x2 = (short) X(x) + px;
968: Star[0].y2 = (short) Y(y);
969: Star[1].x1 = (short) X(x);
970: Star[1].y1 = (short) Y(y) - py;
971: Star[1].x2 = (short) X(x);
972: Star[1].y2 = (short) Y(y) + py;
973: Star[2].x1 = (short) X(x) - px;
974: Star[2].y1 = (short) Y(y) - py;
975: Star[2].x2 = (short) X(x) + px;
976: Star[2].y2 = (short) Y(y) + py;
977: Star[3].x1 = (short) X(x) - px;
978: Star[3].y1 = (short) Y(y) + py;
979: Star[3].x2 = (short) X(x) + px;
980: Star[3].y2 = (short) Y(y) - py;
981:
982: XDrawSegments(dpy, plot->pixmap, gc, Star, 4);
983: break;
984: }
985: if (type != LineSolid || width != 0) { /* select solid line */
986: XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
987: }
988: }
989: }
990: }
991:
992: /* set new pixmap as window background */
993: XSetWindowBackgroundPixmap(dpy, plot->window, plot->pixmap);
994:
995: /* trigger exposure of background pixmap */
996: XClearWindow(dpy, plot->window);
997:
998: #ifdef EXPORT_SELECTION
999: export_graph(plot);
1000: #endif
1001:
1002: XFlush(dpy);
1003: }
1004:
1005: /*---------------------------------------------------------------------------
1006: * reset all cursors (since we dont have a record of the previous terminal #)
1007: *---------------------------------------------------------------------------*/
1008:
1009: void reset_cursor()
1010: {
1011: int plot_number;
1012: plot_struct *plot = plot_array;
1013:
1014: for (plot_number = 0, plot = plot_array;
1015: plot_number < MAX_WINDOWS;
1016: ++plot_number, ++plot) {
1017: if (plot->window) {
1018: FPRINTF((stderr, "Window for plot %d exists\n", plot_number));
1019: XUndefineCursor(dpy, plot->window);;
1020: }
1021: }
1022:
1023: FPRINTF((stderr, "Cursors reset\n"));
1024: return;
1025: }
1026:
1027: /*-----------------------------------------------------------------------------
1028: * resize - rescale last plot if window resized
1029: *---------------------------------------------------------------------------*/
1030:
1031: plot_struct *find_plot(window)
1032: Window window;
1033: {
1034: int plot_number;
1035: plot_struct *plot = plot_array;
1036:
1037: for (plot_number = 0, plot = plot_array;
1038: plot_number < MAX_WINDOWS;
1039: ++plot_number, ++plot) {
1040: if (plot->window == window) {
1041: FPRINTF((stderr, "Event for plot %d\n", plot_number));
1042: return plot;
1043: }
1044: }
1045:
1046: FPRINTF((stderr, "Bogus window 0x%x in event !\n", window));
1047: return NULL;
1048: }
1049:
1050: void process_event(event)
1051: XEvent *event;
1052: {
1053: FPRINTF((stderr, "Event 0x%x\n", event->type));
1054:
1055: switch (event->type) {
1056: case ConfigureNotify:
1057: {
1058: plot_struct *plot = find_plot(event->xconfigure.window);
1059: if (plot) {
1060: int w = event->xconfigure.width, h = event->xconfigure.height;
1061:
1062: /* store settings in case window is closed then recreated */
1063: plot->x = event->xconfigure.x;
1064: plot->y = event->xconfigure.y;
1065: plot->posn_flags = (plot->posn_flags & ~PPosition) | USPosition;
1066:
1067: if (w > 1 && h > 1 && (w != plot->width || h != plot->height)) {
1068: plot->width = w;
1069: plot->height = h;
1070: plot->posn_flags = (plot->posn_flags & ~PSize) | USSize;
1071: if (plot->pixmap) {
1072: /* it is the wrong size now */
1073: FPRINTF((stderr, "Free pixmap %d\n", 0));
1074: XFreePixmap(dpy, plot->pixmap);
1075: plot->pixmap = None;
1076: }
1077: display(plot);
1078: }
1079: }
1080: break;
1081: }
1082: case KeyPress:
1083: if (event->xkey.keycode == q_keycode) {
1084: plot_struct *plot = find_plot(event->xkey.window);
1085: if (plot)
1086: delete_plot(plot);
1087: }
1088: break;
1089: case ClientMessage:
1090: if (event->xclient.message_type == WM_PROTOCOLS &&
1091: event->xclient.format == 32 &&
1092: event->xclient.data.l[0] == WM_DELETE_WINDOW) {
1093: plot_struct *plot = find_plot(event->xclient.window);
1094: if (plot)
1095: delete_plot(plot);
1096: }
1097: break;
1098: #ifdef EXPORT_SELECTION
1099: case SelectionNotify:
1100: case SelectionRequest:
1101: handle_selection_event(event);
1102: break;
1103: #endif
1104: }
1105: }
1106:
1107: /*-----------------------------------------------------------------------------
1108: * preset - determine options, open display, create window
1109: *---------------------------------------------------------------------------*/
1110:
1111: #define On(v) ( !strcmp(v,"on") || !strcmp(v,"true") || \
1112: !strcmp(v,"On") || !strcmp(v,"True") || \
1113: !strcmp(v,"ON") || !strcmp(v,"TRUE") )
1114:
1115: #define AppDefDir "/usr/lib/X11/app-defaults"
1116: #ifndef MAXHOSTNAMELEN
1117: #define MAXHOSTNAMELEN 64
1118: #endif
1119:
1120: static XrmDatabase dbCmd, dbApp, dbDef, dbEnv, db = (XrmDatabase) 0;
1121:
1122: char *pr_GetR(), *getenv(), *type[20];
1123: XrmValue value;
1124:
1125: static XrmOptionDescRec options[] = {
1126: {"-mono", ".mono", XrmoptionNoArg, (caddr_t) "on"},
1127: {"-gray", ".gray", XrmoptionNoArg, (caddr_t) "on"},
1128: {"-clear", ".clear", XrmoptionNoArg, (caddr_t) "on"},
1129: {"-tvtwm", ".tvtwm", XrmoptionNoArg, (caddr_t) "on"},
1130: {"-pointsize", ".pointsize", XrmoptionSepArg, (caddr_t) NULL},
1131: {"-display", ".display", XrmoptionSepArg, (caddr_t) NULL},
1132: {"-name", ".name", XrmoptionSepArg, (caddr_t) NULL},
1133: {"-geometry", "*geometry", XrmoptionSepArg, (caddr_t) NULL},
1134: {"-background", "*background", XrmoptionSepArg, (caddr_t) NULL},
1135: {"-bg", "*background", XrmoptionSepArg, (caddr_t) NULL},
1136: {"-foreground", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
1137: {"-fg", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
1138: {"-bordercolor", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
1139: {"-bd", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
1140: {"-borderwidth", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
1141: {"-bw", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
1142: {"-font", "*font", XrmoptionSepArg, (caddr_t) NULL},
1143: {"-fn", "*font", XrmoptionSepArg, (caddr_t) NULL},
1144: {"-reverse", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
1145: {"-rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
1146: {"+rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "off"},
1147: {"-iconic", "*iconic", XrmoptionNoArg, (caddr_t) "on"},
1148: {"-synchronous", "*synchronous", XrmoptionNoArg, (caddr_t) "on"},
1149: {"-xnllanguage", "*xnllanguage", XrmoptionSepArg, (caddr_t) NULL},
1150: {"-selectionTimeout", "*selectionTimeout", XrmoptionSepArg, (caddr_t) NULL},
1151: {"-title", ".title", XrmoptionSepArg, (caddr_t) NULL},
1152: {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
1153: {"-raise", "*raise", XrmoptionNoArg, (caddr_t) "on"},
1154: {"-noraise", "*raise", XrmoptionNoArg, (caddr_t) "off"},
1155: {"-persist", "*persist", XrmoptionNoArg, (caddr_t) "on"}
1156: };
1157:
1158: #define Nopt (sizeof(options) / sizeof(options[0]))
1159:
1160: void preset(argc, argv)
1161: int argc;
1162: char *argv[];
1163: {
1164: int Argc = argc;
1165: char **Argv = argv;
1166:
1167: #ifdef VMS
1168: char *ldisplay = (char *) 0;
1169: #else
1170: char *ldisplay = getenv("DISPLAY");
1171: #endif
1172: char *home = getenv("HOME");
1173: char *server_defaults, *env, buffer[256];
1174:
1175: /* avoid bus error when env vars are not set */
1176: if (ldisplay == NULL)
1177: ldisplay = "";
1178: if (home == NULL)
1179: home = "";
1180:
1181: /*---set to ignore ^C and ^Z----------------------------------------------*/
1182:
1183: signal(SIGINT, SIG_IGN);
1184: #ifdef SIGTSTP
1185: signal(SIGTSTP, SIG_IGN);
1186: #endif
1187:
1188: /*---prescan arguments for "-name"----------------------------------------*/
1189:
1190: while (++Argv, --Argc > 0) {
1191: if (!strcmp(*Argv, "-name") && Argc > 1) {
1192: safe_strncpy(Name, Argv[1], sizeof(Name));
1193: safe_strncpy(Class, Argv[1], sizeof(Class));
1194: if (Class[0] >= 'a' && Class[0] <= 'z')
1195: Class[0] -= 0x20;
1196: }
1197: }
1198: Argc = argc;
1199: Argv = argv;
1200:
1201: /*---parse command line---------------------------------------------------*/
1202:
1203: XrmInitialize();
1204: XrmParseCommand(&dbCmd, options, Nopt, Name, &Argc, Argv);
1205: if (Argc > 1) {
1206: fprintf(stderr, "\n\
1207: gnuplot: bad option: %s\n\
1208: gnuplot: X11 aborted.\n", Argv[1]);
1209: EXIT(1);
1210: }
1211: if (pr_GetR(dbCmd, ".display"))
1212: ldisplay = (char *) value.addr;
1213:
1214: /*---open display---------------------------------------------------------*/
1215:
1216: dpy = XOpenDisplay(ldisplay);
1217: if (!dpy) {
1218: fprintf(stderr, "\n\
1219: gnuplot: unable to open display '%s'\n\
1220: gnuplot: X11 aborted.\n", ldisplay);
1221: EXIT(1);
1222: }
1223: scr = DefaultScreen(dpy);
1224: vis = DefaultVisual(dpy, scr);
1225: D = DefaultDepth(dpy, scr);
1226: root = DefaultRootWindow(dpy);
1227: server_defaults = XResourceManagerString(dpy);
1228:
1229: /*---get symcode for key q ---*/
1230:
1231: q_keycode = XKeysymToKeycode(dpy, XK_q);
1232:
1233: /**** atoms we will need later ****/
1234:
1235: WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
1236: WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1237:
1238:
1239: /*---get application defaults--(subset of Xt processing)------------------*/
1240:
1241: #ifdef VMS
1242: strcpy(buffer, "DECW$USER_DEFAULTS:GNUPLOT_X11.INI");
1243: #else
1244: # ifdef OS2
1245: /* for Xfree86 ... */
1246: {
1247: char *appdefdir = "XFree86/lib/X11/app-defaults";
1248: char *xroot = getenv("X11ROOT");
1249: sprintf(buffer, "%s/%s/%s", xroot, appdefdir, "Gnuplot");
1250: }
1251: # else
1252: sprintf(buffer, "%s/%s", AppDefDir, "Gnuplot");
1253: # endif /* !OS2 */
1254: #endif /* !VMS */
1255:
1256: dbApp = XrmGetFileDatabase(buffer);
1257: XrmMergeDatabases(dbApp, &db);
1258:
1259: /*---get server or ~/.Xdefaults-------------------------------------------*/
1260:
1261: if (server_defaults)
1262: dbDef = XrmGetStringDatabase(server_defaults);
1263: else {
1264: #ifdef VMS
1265: strcpy(buffer, "DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT");
1266: #else
1267: sprintf(buffer, "%s/.Xdefaults", home);
1268: #endif
1269: dbDef = XrmGetFileDatabase(buffer);
1270: }
1271: XrmMergeDatabases(dbDef, &db);
1272:
1273: /*---get XENVIRONMENT or ~/.Xdefaults-hostname---------------------------*/
1274:
1275: #ifndef VMS
1276: if ((env = getenv("XENVIRONMENT")) != NULL)
1277: dbEnv = XrmGetFileDatabase(env);
1278: else {
1279: char *p = NULL, host[MAXHOSTNAMELEN];
1280:
1281: if (GP_SYSTEMINFO(host) < 0) {
1282: fprintf(stderr, "gnuplot: %s failed. X11 aborted.\n", SYSINFO_METHOD);
1283: EXIT(1);
1284: }
1285: if ((p = strchr(host, '.')) != NULL)
1286: *p = '\0';
1287: sprintf(buffer, "%s/.Xdefaults-%s", home, host);
1288: dbEnv = XrmGetFileDatabase(buffer);
1289: }
1290: XrmMergeDatabases(dbEnv, &db);
1291: #endif /* not VMS */
1292:
1293: /*---merge command line options-------------------------------------------*/
1294:
1295: XrmMergeDatabases(dbCmd, &db);
1296:
1297: /*---set geometry, font, colors, line widths, dash styles, point size-----*/
1298:
1299: pr_geometry();
1300: pr_font();
1301: pr_color();
1302: pr_width();
1303: pr_dashes();
1304: pr_pointsize();
1305: pr_raise();
1306: pr_persist();
1307: }
1308:
1309: /*-----------------------------------------------------------------------------
1310: * pr_GetR - get resource from database using "-name" option (if any)
1311: *---------------------------------------------------------------------------*/
1312:
1313: char *
1314: pr_GetR(xrdb, resource)
1315: XrmDatabase xrdb;
1316: char *resource;
1317: {
1318: char name[128], class[128], *rc;
1319:
1320: strcpy(name, Name);
1321: strcat(name, resource);
1322: strcpy(class, Class);
1323: strcat(class, resource);
1324: rc = XrmGetResource(xrdb, name, class, type, &value)
1325: ? (char *) value.addr
1326: : (char *) 0;
1327: return (rc);
1328: }
1329:
1330: /*-----------------------------------------------------------------------------
1331: * pr_color - determine color values
1332: *---------------------------------------------------------------------------*/
1333:
1334: char color_keys[Ncolors][30] = {
1335: "background", "bordercolor", "text", "border", "axis",
1336: "line1", "line2", "line3", "line4",
1337: "line5", "line6", "line7", "line8"
1338: };
1339: char color_values[Ncolors][30] = {
1340: "white", "black", "black", "black", "black",
1341: "red", "green", "blue", "magenta",
1342: "cyan", "sienna", "orange", "coral"
1343: };
1344: char gray_values[Ncolors][30] = {
1345: "black", "white", "white", "gray50", "gray50",
1346: "gray100", "gray60", "gray80", "gray40",
1347: "gray90", "gray50", "gray70", "gray30"
1348: };
1349:
1350: void pr_color()
1351: {
1352: unsigned long black = BlackPixel(dpy, scr), white = WhitePixel(dpy, scr);
1353: char option[20], color[30], *v, *ctype;
1354: XColor xcolor;
1355: Colormap cmap;
1356: double intensity = -1;
1357: int n;
1358:
1359: pr_GetR(db, ".mono") && On(value.addr) && Mono++;
1360: pr_GetR(db, ".gray") && On(value.addr) && Gray++;
1361: pr_GetR(db, ".reverseVideo") && On(value.addr) && Rv++;
1362:
1363: if (!Gray && (vis->class == GrayScale || vis->class == StaticGray))
1364: Mono++;
1365:
1366: if (!Mono) {
1367: cmap = DefaultColormap(dpy, scr);
1368: ctype = (Gray) ? "Gray" : "Color";
1369:
1370: for (n = 0; n < Ncolors; n++) {
1371: strcpy(option, ".");
1372: strcat(option, color_keys[n]);
1373: (n > 1) && strcat(option, ctype);
1374: v = pr_GetR(db, option)
1375: ? (char *) value.addr
1376: : ((Gray) ? gray_values[n] : color_values[n]);
1377:
1378: if (sscanf(v, "%30[^,],%lf", color, &intensity) == 2) {
1379: if (intensity < 0 || intensity > 1) {
1380: fprintf(stderr, "\ngnuplot: invalid color intensity in '%s'\n",
1381: color);
1382: intensity = 1;
1383: }
1384: } else {
1385: strcpy(color, v);
1386: intensity = 1;
1387: }
1388:
1389: if (!XParseColor(dpy, cmap, color, &xcolor)) {
1390: fprintf(stderr, "\ngnuplot: unable to parse '%s'. Using black.\n",
1391: color);
1392: colors[n] = black;
1393: } else {
1394: xcolor.red *= intensity;
1395: xcolor.green *= intensity;
1396: xcolor.blue *= intensity;
1397: if (XAllocColor(dpy, cmap, &xcolor)) {
1398: colors[n] = xcolor.pixel;
1399: } else {
1400: fprintf(stderr, "\ngnuplot: can't allocate '%s'. Using black.\n",
1401: v);
1402: colors[n] = black;
1403: }
1404: }
1405: }
1406: } else {
1407: colors[0] = (Rv) ? black : white;
1408: for (n = 1; n < Ncolors; n++)
1409: colors[n] = (Rv) ? white : black;
1410: }
1411: }
1412:
1413: /*-----------------------------------------------------------------------------
1414: * pr_dashes - determine line dash styles
1415: *---------------------------------------------------------------------------*/
1416:
1417: char dash_keys[Ndashes][10] = {
1418: "border", "axis",
1419: "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
1420: };
1421:
1422: char dash_mono[Ndashes][10] = {
1423: "0", "16",
1424: "0", "42", "13", "44", "15", "4441", "42", "13"
1425: };
1426:
1427: char dash_color[Ndashes][10] = {
1428: "0", "16",
1429: "0", "0", "0", "0", "0", "0", "0", "0"
1430: };
1431:
1432: void pr_dashes()
1433: {
1434: int n, j, l, ok;
1435: char option[20], *v;
1436:
1437: for (n = 0; n < Ndashes; n++) {
1438: strcpy(option, ".");
1439: strcat(option, dash_keys[n]);
1440: strcat(option, "Dashes");
1441: v = pr_GetR(db, option)
1442: ? (char *) value.addr
1443: : ((Mono) ? dash_mono[n] : dash_color[n]);
1444: l = strlen(v);
1445: if (l == 1 && *v == '0') {
1446: dashes[n][0] = (unsigned char) 0;
1447: continue;
1448: }
1449: for (ok = 0, j = 0; j < l; j++) {
1450: v[j] >= '1' && v[j] <= '9' && ok++;
1451: }
1452: if (ok != l || (ok != 2 && ok != 4)) {
1453: fprintf(stderr, "gnuplot: illegal dashes value %s:%s\n", option, v);
1454: dashes[n][0] = (unsigned char) 0;
1455: continue;
1456: }
1457: for (j = 0; j < l; j++) {
1458: dashes[n][j] = (unsigned char) (v[j] - '0');
1459: }
1460: dashes[n][l] = (unsigned char) 0;
1461: }
1462: }
1463:
1464: /*-----------------------------------------------------------------------------
1465: * pr_font - determine font
1466: *---------------------------------------------------------------------------*/
1467:
1468: void pr_font()
1469: {
1470: char *fontname = pr_GetR(db, ".font");
1471:
1472: if (!fontname)
1473: fontname = FallbackFont;
1474: font = XLoadQueryFont(dpy, fontname);
1475: if (!font) {
1476: fprintf(stderr, "\ngnuplot: can't load font '%s'\n", fontname);
1477: fprintf(stderr, "gnuplot: using font '%s' instead.\n", FallbackFont);
1478: font = XLoadQueryFont(dpy, FallbackFont);
1479: if (!font) {
1480: fprintf(stderr, "\
1481: gnuplot: can't load font '%s'\n\
1482: gnuplot: no useable font - X11 aborted.\n", FallbackFont);
1483: EXIT(1);
1484: }
1485: }
1486: vchar = font->ascent + font->descent;
1487: }
1488:
1489: /*-----------------------------------------------------------------------------
1490: * pr_geometry - determine window geometry
1491: *---------------------------------------------------------------------------*/
1492:
1493: void pr_geometry()
1494: {
1495: char *geometry = pr_GetR(db, ".geometry");
1496: int x, y, flags;
1497: unsigned int w, h;
1498:
1499: if (geometry) {
1500: flags = XParseGeometry(geometry, &x, &y, &w, &h);
1501: if (flags & WidthValue)
1502: gW = w;
1503: if (flags & HeightValue)
1504: gH = h;
1505: if (flags & (WidthValue | HeightValue))
1506: gFlags = (gFlags & ~PSize) | USSize;
1507:
1508: if (flags & XValue)
1509: gX = (flags & XNegative) ? x + DisplayWidth(dpy, scr) - gW - BorderWidth * 2 : x;
1510:
1511: if (flags & YValue)
1512: gY = (flags & YNegative) ? y + DisplayHeight(dpy, scr) - gH - BorderWidth * 2 : y;
1513:
1514: if (flags & (XValue | YValue))
1515: gFlags = (gFlags & ~PPosition) | USPosition;
1516: }
1517: }
1518:
1519: /*-----------------------------------------------------------------------------
1520: * pr_pointsize - determine size of points for 'points' plotting style
1521: *---------------------------------------------------------------------------*/
1522:
1523: void pr_pointsize()
1524: {
1525: if (pr_GetR(db, ".pointsize")) {
1526: if (sscanf((char *) value.addr, "%lf", &pointsize) == 1) {
1527: if (pointsize <= 0 || pointsize > 10) {
1528: fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
1529: pointsize = 1;
1530: }
1531: } else {
1532: fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
1533: pointsize = 1;
1534: }
1535: } else {
1536: pointsize = 1;
1537: }
1538: }
1539:
1540: /*-----------------------------------------------------------------------------
1541: * pr_width - determine line width values
1542: *---------------------------------------------------------------------------*/
1543:
1544: char width_keys[Nwidths][30] = {
1545: "border", "axis",
1546: "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
1547: };
1548:
1549: void pr_width()
1550: {
1551: int n;
1552: char option[20], *v;
1553:
1554: for (n = 0; n < Nwidths; n++) {
1555: strcpy(option, ".");
1556: strcat(option, width_keys[n]);
1557: strcat(option, "Width");
1558: if ((v = pr_GetR(db, option)) != NULL) {
1559: if (*v < '0' || *v > '4' || strlen(v) > 1)
1560: fprintf(stderr, "gnuplot: illegal width value %s:%s\n", option, v);
1561: else
1562: widths[n] = (unsigned int) atoi(v);
1563: }
1564: }
1565: }
1566:
1567: /*-----------------------------------------------------------------------------
1568: * pr_window - create window
1569: *---------------------------------------------------------------------------*/
1570:
1571: Window pr_window(flags, x, y, width, height)
1572: unsigned int flags;
1573: int x, y;
1574: unsigned int width, height;
1575: {
1576: char *title = pr_GetR(db, ".title");
1577: static XSizeHints hints;
1578: int Tvtwm = 0;
1579:
1580: Window win = XCreateSimpleWindow(dpy, root, x, y, width, height, BorderWidth,
1581: colors[1], colors[0]);
1582:
1583: /* ask ICCCM-compliant window manager to tell us when close window
1584: * has been chosen, rather than just killing us
1585: */
1586:
1587: XChangeProperty(dpy, win, WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
1588: (unsigned char *) &WM_DELETE_WINDOW, 1);
1589:
1590: pr_GetR(db, ".clear") && On(value.addr) && Clear++;
1591: pr_GetR(db, ".tvtwm") && On(value.addr) && Tvtwm++;
1592:
1593: if (!Tvtwm) {
1594: hints.flags = flags;
1595: } else {
1596: hints.flags = (flags & ~USPosition) | PPosition; /* ? */
1597: }
1598: hints.x = gX;
1599: hints.y = gY;
1600: hints.width = width;
1601: hints.height = height;
1602:
1603: XSetNormalHints(dpy, win, &hints);
1604:
1605: if (pr_GetR(db, ".iconic") && On(value.addr)) {
1606: XWMHints wmh;
1607:
1608: wmh.flags = StateHint;
1609: wmh.initial_state = IconicState;
1610: XSetWMHints(dpy, win, &wmh);
1611: }
1612: XStoreName(dpy, win, ((title) ? title : Class));
1613:
1614: XSelectInput(dpy, win, KeyPressMask | StructureNotifyMask);
1615: XMapWindow(dpy, win);
1616:
1617: return win;
1618: }
1619:
1620:
1621: /***** pr_raise ***/
1622: void pr_raise()
1623: {
1624: if (pr_GetR(db, ".raise"))
1625: do_raise = (On(value.addr));
1626: }
1627:
1628:
1629: void pr_persist()
1630: {
1631: if (pr_GetR(db, ".persist"))
1632: persist = (On(value.addr));
1633: }
1634:
1635: /************ code to handle selection export *********************/
1636:
1637: #ifdef EXPORT_SELECTION
1638:
1639: /* bit of a bodge, but ... */
1640: static struct plot_struct *exported_plot;
1641:
1642: void export_graph(plot)
1643: struct plot_struct *plot;
1644: {
1645: FPRINTF((stderr, "export_graph(0x%x)\n", plot));
1646:
1647: XSetSelectionOwner(dpy, EXPORT_SELECTION, plot->window, CurrentTime);
1648: /* to check we have selection, we would have to do a
1649: * GetSelectionOwner(), but if it failed, it failed - no big deal
1650: */
1651: exported_plot = plot;
1652: }
1653:
1654: void handle_selection_event(event)
1655: XEvent *event;
1656: {
1657: switch (event->type) {
1658: case SelectionRequest:
1659: {
1660: XEvent reply;
1661:
1662: static Atom XA_TARGETS = (Atom) 0;
1663: if (XA_TARGETS == 0)
1664: XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
1665:
1666: reply.type = SelectionNotify;
1667: reply.xselection.send_event = True;
1668: reply.xselection.display = event->xselectionrequest.display;
1669: reply.xselection.requestor = event->xselectionrequest.requestor;
1670: reply.xselection.selection = event->xselectionrequest.selection;
1671: reply.xselection.target = event->xselectionrequest.target;
1672: reply.xselection.property = event->xselectionrequest.property;
1673: reply.xselection.time = event->xselectionrequest.time;
1674:
1675: FPRINTF((stderr, "selection request\n"));
1676:
1677: if (reply.xselection.target == XA_TARGETS) {
1678: static Atom targets[] = {XA_PIXMAP, XA_COLORMAP};
1679:
1680: FPRINTF((stderr, "Targets request from %d\n", reply.xselection.requestor));
1681:
1682: XChangeProperty(dpy, reply.xselection.requestor,
1683: reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
1684: (unsigned char *) targets, 2);
1685: } else if (reply.xselection.target == XA_COLORMAP) {
1686: Colormap cmap = DefaultColormap(dpy, 0);
1687:
1688: FPRINTF((stderr, "colormap request from %d\n", reply.xselection.requestor));
1689:
1690: XChangeProperty(dpy, reply.xselection.requestor,
1691: reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
1692: (unsigned char *) &cmap, 1);
1693: } else if (reply.xselection.target == XA_PIXMAP) {
1694:
1695: FPRINTF((stderr, "pixmap request from %d\n", reply.xselection.requestor));
1696:
1697: XChangeProperty(dpy, reply.xselection.requestor,
1698: reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
1699: (unsigned char *) &(exported_plot->pixmap), 1);
1700: } else {
1701: reply.xselection.property = None;
1702: }
1703:
1704: XSendEvent(dpy, reply.xselection.requestor, False, 0L, &reply);
1705: /* we never block on XNextEvent(), so must flush manually
1706: * (took me *ages* to find this out !)
1707: */
1708:
1709: XFlush(dpy);
1710: }
1711: break;
1712: }
1713: }
1714:
1715: #endif /* EXPORT_SELECTION */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>