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