1 #ifndef _POSIX_SOURCE
2 #define _POSIX_SOURCE
3 #endif
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <ctype.h>
8 #include <string.h>
9 #include <signal.h>
10 
11 #include <X11/Xos.h>
12 #include <X11/Xlib.h>
13 #include <X11/Xresource.h>
14 #include <X11/Xatom.h>
15 #include <X11/Xutil.h>
16 #include <X11/cursorfont.h>
17 
18 /*
19  * The following headers are included to define the setpgid() prototype.
20  */
21 #ifndef VMS
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <pwd.h>
25 #endif
26 
27 /*
28  * Client/server communication protocol revision number.
29  */
30 #define PGXWIN_REVISION 0
31 
32 /*
33  * Allow the expose-event handler name to be changed by compile
34  * time pre-definition of PGXWIN_SERVER. If pgxwin_server is modified in
35  * such a way as to become incompatible with an earlier version of xwdriv.c,
36  * its name should be changed by postfixing a small increasing integer
37  * to the name of the executable. New and old pgplot programs can then
38  * coexist as long as both versions of the server are
39  * retained. In order not to clutter up system directories, don't change
40  * this name unless absolutely necessary. This is also the name given to
41  * the server selection atom, so be sure that it remains valid for this
42  * purpose.
43  */
44 #ifndef PGXWIN_SERVER
45 #define PGXWIN_SERVER "pgxwin_server"
46 #endif
47 
48 #define XW_MAX_COLORS 256     /* Max number of colors to allocate */
49                               /* Note that the line_of_pixels opcode */
50                               /* assumes that there are at most 256 colors */
51 #define XW_MIN_COLORS 2       /* Min number of colors per colormap */
52 #define XW_DEF_COLORS 100     /* Default number of colors to allocate */
53 #define NCOLORS 16            /* Number of pre-defined PGPLOT colors */
54 #define XW_IMAGE_LEN 1280     /* Length of the line-of-pixels buffer */
55 #define COLORMULT 65535       /* Normalized color intensity multiplier */
56 
57 #define XW_DEV_NAME "XWINDOW (X Window display)" /* PGPLOT device name */
58 #define XW_WINDOW_NAME "PGPLOT Window" /* Window title */
59 #define XW_ICON_NAME "PGPLOT"          /* Name to place under the icon */
60 #define XW_BORDER ((unsigned int)4)    /* Window border width (pixels) */
61 
62 #define XW_DEF_ASPECT (8.5/11.0)   /* Default aspect (height/width) of window */
63 #define XW_DEF_WIDTH 867           /* Default width (pixels) */
64 #define XW_DEF_HEIGHT ((int) XW_DEF_WIDTH * XW_DEF_ASPECT)
65                                    /* Default height (pixels) */
66 #define XW_MIN_WIDTH 64            /* Minimum width (pixels) */
67 #define XW_MIN_HEIGHT 64           /* Minimum height (pixels) */
68 
69 /*
70  * Define equivalence values for the XParseGeometry bitmask bits, using
71  * values agreed upon by xwdriv.c and pgxwin_server.c, for use in
72  * communicating geometries between client and server.
73  */
74 #define XW_WidthValue 1
75 #define XW_HeightValue 2
76 #define XW_XValue 4
77 #define XW_YValue 8
78 #define XW_XNegative 16
79 #define XW_YNegative 32
80 
81 /*
82  * Enumerate the supported window close-down modes.
83  */
84 #define XW_DELETE 1
85 #define XW_PERSIST 2
86 #define XW_ICONIZE 3
87 
88 /*
89  * Enumerate property-data formats, named after the internal types that
90  * are used to communicate them with XChangeProperty() and
91  * XGetWindowProperty().
92  */
93 #define XW_CHAR_PROP 8
94 #define XW_SHORT_PROP 16
95 #define XW_LONG_PROP 32
96 
97 /*
98  * ANSI defines two exit value to indicate succesful and unsuccesful program
99  * termination. We should use these. On pre-ANSI machines we will assume
100  * the old K&R convention.
101  */
102 #ifndef EXIT_SUCCESS
103 #define EXIT_SUCCESS 0
104 #endif
105 #ifndef EXIT_FAILURE
106 #define EXIT_FAILURE 1
107 #endif
108 
109 /* A container used to record the geometry of the X-window */
110 
111 typedef struct {
112   int x,y;             /* Locus of top left corner of window (pixels) */
113   unsigned int width;  /* Width of window (pixels) */
114   unsigned int height; /* Height of window (pixels) */
115   int xpix_per_inch;   /* Number of pixels per inch along X */
116   int ypix_per_inch;   /* Number of pixels per inch along Y */
117   int xmargin;         /* X-axis 1/4" margin in pixels */
118   int ymargin;         /* Y-axis 1/4" margin in pixels */
119   int xmin,xmax;       /* Min/max X-axis pixels excluding 1/4" margins */
120   int ymin,ymax;       /* Min/max X-axis pixels excluding 1/4" margins */
121 } XWgeom;
122 
123 /*
124  * Declare a colormap descriptor.
125  */
126 typedef struct {
127   XVisualInfo *vi;      /* The colormap visual information descriptor */
128   Colormap cmap;        /* Colormap ID */
129   int ncol;             /* The number of colors available. ci = [0...ncol-1] */
130   unsigned long *pixel; /* Color pixels allocated */
131   int monochrome;       /* True we have to use a monochrome screen */
132   int default_class;    /* The class of the default visual of the screen */
133 } XWcolor;
134 
135 /* Declare a container for cursor IDs */
136 
137 typedef struct {
138   Cursor norm;   /* ID of cursor to use when cursor input is not expected */
139   Cursor live;   /* ID of cursor to use when cursor input is expected */
140   Cursor idle;   /* ID of cursor to use when the window is un-assigned */
141 } XWCursor;
142 
143 /* Declare a container in which to record resource database quarks */
144 
145 typedef struct { /* A Quark name/class resource pair */
146   XrmQuark name;
147   XrmQuark class;
148 } XWQPair;
149 
150 typedef struct {
151   XWQPair prog;       /* Program name/class quarks */
152   XWQPair display;    /* .display name/class quarks */
153   XWQPair server;     /* .server. name/class quark */
154   XWQPair geom;       /* PGWin geometry name/class quarks */
155   XWQPair iconize;    /* PGWin iconize name/class quarks */
156   XWQPair acceptquit; /* PGWin acceptQuit name/class quarks */
157   XWQPair mincolors;  /* PGWin minColors name/class quarks */
158   XWQPair maxcolors;  /* PGWin maxColors name/class quarks */
159   XWQPair visual;     /* PGWin visual name/class quarks */
160   XWQPair crosshair;  /* PGWin crosshair name/class quarks */
161   XWQPair visible;    /* Server visible name/class quarks */
162   XWQPair icongeom;   /* iconGeometry name/class quarks */
163   XrmQuark win_class; /* PGWin window-specification class quark */
164 } XWQuarks;
165 
166 /* Declare a container to record details of a given client window */
167 
168 typedef struct PGwin {
169   Window window;     /* PGPLOT /xw window ID */
170   Window parent;     /* Parent window of 'window' */
171   Window client;     /* Window ID of client using the window */
172   Pixmap pixmap;     /* Pixmap ID for buffering and expose-event handling */
173   GC gc;             /* Graphical context descriptor */
174   int protocol;      /* Client/server protocol revision to use */
175   int id;            /* PGPLOT selection ID */
176   int screen;        /* The screen on which the window appears */
177   int mapped;        /* True only after the window is first mapped */
178   int disposition;   /* Close-down mode: XW_PERSIST, XW_ICONIZE, XW_DELETE */
179   int acceptquit;     /* True if WM_DELETE_WINDOW events are to be obeyed on */
180                       /* Active windows */
181   int iconize;        /* If true, iconize inactive windows if persistent */
182   int mincol;         /* Min number of colors per colormap */
183   int maxcol;         /* Max number of colors per colormap */
184   int crosshair;      /* If true show crosshair cursor */
185   int visual_class;   /* If != -1, then this is the visual class to try for. */
186   XWgeom geom;       /* The size and position of the window */
187   XWcolor color;     /* Colormap descriptor */
188   XWCursor *curs;    /* Pointer to xw->col_cursor or xw->gry_cursor */
189   struct PGwin *next;/* Pointer to next window in list */
190 } PGwin;
191 
192 /* Declare a container for server data */
193 
194 typedef struct {
195   Display *display;   /* Connection to the display */
196   XrmDatabase xrdb;   /* X resource database */
197   int screen;         /* Screen number of windows */
198   Window pgxwin;      /* ID of top-level window of server */
199   Atom server_atom;   /* PGXWIN_SERVER selection atom */
200   Atom client_data;   /* PGXWIN_CLIENT_DATA property atom */
201   PGwin *active_list; /* LIFO list of active PGPLOT /xw windows */
202   PGwin *closed_list; /* Sorted list of un-connected PGPLOT /xw windows */
203   XWCursor col_cursor;/* Cursors for color visuals */
204   XWCursor gry_cursor;/* Cursors for gray and monochrome visuals */
205   XWQuarks quarks;    /* Resource database quarks */
206   Pixmap icon;        /* ID of icon pixmap */
207   Atom wm_protocols;  /* WM_PROTOCOLS atom */
208   Atom wm_delete_win; /* WM_DELETE_WINDOW atom */
209   Atom geom_atom;     /* Client/server geometry transaction atom */
210 } XWServer;
211 
212 #ifdef __STDC__
213 #define ARGS(args) args
214 #else
215 #define ARGS(args) ()
216 #endif
217 
218 static XWServer *new_XWServer ARGS((XrmDatabase xrdb));
219 static XWServer *del_XWServer ARGS((XWServer *xw));
220 static PGwin *new_PGwin ARGS((XWServer *xw, int id, int screen, Window client,
221 			      int disposition));
222 static PGwin *add_PGwin ARGS((PGwin **pglist, int sort, PGwin *pgw));
223 static PGwin *rem_PGwin ARGS((PGwin **pglist, PGwin *pgw));
224 static PGwin *del_PGwin ARGS((XWServer *xw, PGwin *pgw));
225 static Window xw_server_window ARGS((XWServer *xw));
226 static int xw_set_signals ARGS((void));
227 static int xw_handle_error ARGS((Display *display, XErrorEvent *event));
228 static int xw_event_loop ARGS((XWServer *xw));
229 static Bool xw_parse_bool ARGS((char *str, Bool def));
230 static int xw_parse_visual ARGS((char *str));
231 static int xw_same_string ARGS((char *s1, char *s2));
232 static int xw_client_message ARGS((XWServer *xw, XEvent *event));
233 static int xw_ret_cursor ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
234 static int xw_ret_colors ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
235 static int xw_ret_error ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
236 static int xw_new_window ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
237 static int xw_new_pixmap ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
238 static int xw_set_geom ARGS((XWServer *xw, PGwin *pgw, int x, int y,
239 		       unsigned int width, unsigned int height, int mask));
240 static int xw_new_geom ARGS((XWServer *xw, XEvent *event, PGwin *pgw));
241 static int xw_get_geom ARGS((XWServer *xw, PGwin *pgw));
242 static int xw_wm_message ARGS((XWServer *xw, XEvent *event));
243 static int xw_check_destroy ARGS((XWServer *xw, XEvent *event));
244 static int xw_expose_win ARGS((XWServer *xw, XEvent *event));
245 static int xw_get_visual ARGS((XWServer *xw, PGwin *pgw));
246 static int xw_find_visual ARGS((XWServer *xw, PGwin *pgw, int class));
247 static int xw_get_colorcells ARGS((XWServer *xw, PGwin *pgw, XVisualInfo *vi,
248 				   Colormap cmap));
249 static int xw_del_Colormap ARGS((XWServer *xw, PGwin *pgw, XVisualInfo *vi,
250 			   Colormap cmap, int ncol));
251 static XVisualInfo *xw_visual_info ARGS((Display *display, int screen,
252 					 Visual *visual));
253 static int xw_prep_window ARGS((XWServer *xw, PGwin *pgw, Window client,
254 				int protocol));
255 static unsigned long xw_send_data ARGS((XWServer *xw, PGwin *pgw,
256 		   unsigned char *data, int form, unsigned long n, Atom type));
257 static int xw_ini_cursors ARGS((XWServer *xw, XWCursor *curs));
258 static int xw_new_cursors ARGS((XWServer *xw, int usecolor, XWCursor *curs));
259 static int xw_del_cursors ARGS((XWServer *xw, XWCursor *curs));
260 static char *xw_home_dir ARGS((void));
261 static XrmDatabase xw_get_xrdb ARGS((Display *display, XrmDatabase cmd_xrdb));
262 static int xw_get_quarks ARGS((XWServer *xw));
263 static char *xw_get_default ARGS((XWServer *xw, int window_id, XWQPair *pair));
264 static int xw_get_config ARGS((XWServer *xw, PGwin *pgw));
265 static int xw_setwmhints ARGS((XWServer *xw, int screen, Window window,int id));
266 static int xw_name_window ARGS((XWServer *xw, Window window, char *w_name,
267 			  char *i_name));
268 static int xw_sync_error ARGS((XWServer *xw));
269 
270 
271 /* List resource command-line arguments */
272 
273 static XrmOptionDescRec cmd_opt[] = {
274   {"-display",            ".server.display",  XrmoptionSepArg, NULL},
275   {"-win_visual",         ".Win.visual",      XrmoptionSepArg, NULL},
276   {"-win_iconize",        ".Win.iconize",     XrmoptionSepArg, NULL},
277   {"-win_geometry",       ".Win.geometry",    XrmoptionSepArg, NULL},
278   {"-win_minColors",      ".Win.minColors",   XrmoptionSepArg, NULL},
279   {"-win_maxColors",      ".Win.maxColors",   XrmoptionSepArg, NULL},
280   {"-win_crosshair",      ".Win.crosshair",   XrmoptionSepArg, NULL},
281   {"-win_acceptQuit",     ".Win.acceptQuit",  XrmoptionSepArg, NULL},
282   {"-win_iconGeometry",   ".Win.iconGeometry",XrmoptionSepArg, NULL},
283   {"-server_visible",     ".server.visible",  XrmoptionSepArg, NULL},
284   {"-server_iconGeometry",".server.iconGeometry", XrmoptionSepArg, NULL},
285   {"-xrm",                NULL,               XrmoptionResArg, NULL}
286 };
287 
288 /* List usage of command-line arguments */
289 
290 static struct {
291   char *opt;
292   char *arg;
293 } cmd_usage[] = {
294   {"-help",               ""},
295   {"-display",            "display_name"},
296   {"-win_visual",         "default|monochrome|pseudocolor|directcolor|staticcolor|truecolor|grayscale|staticgray"},
297   {"-win_iconize",        "True|False"},
298   {"-win_geometry",       "WIDTHxHEIGHT+X+Y"},
299   {"-win_minColors",      "integer"},
300   {"-win_maxColors",      "integer"},
301   {"-win_crosshair",      "True|False"},
302   {"-win_acceptQuit",     "True|False"},
303   {"-win_iconGeometry",   "+X+Y"},
304   {"-server_visible",     "True|False"},
305   {"-server_iconGeometry","+X+Y"},
306   {"-xrm",       "Resource manager string, eg. \"pgxwin.win2.maxColors: 16\""}
307 };
308 
309 /*.......................................................................
310  * PGPLOT /xw driver multi-client window server.
311  *
312  * Input:
313  *  argv[1]  char *   The name of the display to connect to.
314  */
315 #ifdef __STDC__
main(int argc,char * argv[])316 int main(int argc, char *argv[])
317 #else
318 int main(argc, argv)
319   int argc; char *argv[];
320 #endif
321 {
322   XWServer *xw;                /* PGPLOT /xw server descriptor */
323   XrmDatabase cmd_xrdb=NULL;   /* Command-line X resource database */
324   int i;
325 /*
326  * Close stdin and stdout since we aren't going to use them.
327  */
328   fclose(stdin);
329   fclose(stdout);
330 /*
331  * Under UNIX make sure that we are not in the same process group as
332  * the process that spawned us. Otherwise, signals sent to the parent
333  * will be sent to us as well.
334  */
335 #ifndef VMS
336   setpgid(0,0);
337 #endif
338 /*
339  * Reset signal handlers.
340  */
341   xw_set_signals();
342 /*
343  * Get command-line X resource options.
344  */
345   XrmInitialize();
346   XrmParseCommand(&cmd_xrdb, cmd_opt,
347 		  (int)(sizeof(cmd_opt)/sizeof(XrmOptionDescRec)), "pgxwin",
348 			 &argc, argv);
349 /*
350  * The only legal remaining argument is -help.
351  */
352   if(argc > 1) {
353     if(strcmp(argv[1],"-help")!=0) {
354       fprintf(stderr,
355 	      "%s: Unknown command-line option \"%s\". Try the -help option.\n",
356 	      PGXWIN_SERVER, argv[1]);
357     } else {
358       fprintf(stderr, "Usage:\n\t %s [options]\n\n", PGXWIN_SERVER);
359       fprintf(stderr, "Where legal options and their arguments include:\n");
360       for(i=0; i<sizeof(cmd_usage)/sizeof(cmd_usage[0]); i++)
361 	fprintf(stderr, " %s\t %s\n", cmd_usage[i].opt, cmd_usage[i].arg);
362       fprintf(stderr, "\n");
363     };
364     return EXIT_FAILURE;
365   };
366 /*
367  * Start the server.
368  */
369   if((xw=new_XWServer(cmd_xrdb)) == NULL)
370     return EXIT_FAILURE;
371 /*
372  * Enter the event loop.
373  */
374   xw_event_loop(xw);
375 /*
376  * Clean up.
377  */
378   xw = del_XWServer(xw);
379   return EXIT_SUCCESS;
380 }
381 
382 /*.......................................................................
383  * Open a connection to the display, check whether another server is
384  * already running, and if not, create a simple unmapped window for
385  * communication, install its ID in a root-window property named PGXWIN,
386  * and return a descriptor for use with the new server.
387  *
388  * Input:
389  *  xrdb XrmDatabase    The X resource database initialized from command
390  *                      line arguments.
391  * Output:
392  *  xw      XWServer *  The descriptor of the server, or NULL on error.
393  */
394 #ifdef __STDC__
new_XWServer(XrmDatabase xrdb)395 static XWServer *new_XWServer(XrmDatabase xrdb)
396 #else
397 static XWServer *new_XWServer(xrdb)
398      XrmDatabase xrdb;
399 #endif
400 {
401   XWServer *xw;       /* The return descriptor */
402   char *display_name; /* The name of the display */
403 /*
404  * Allocate the container.
405  */
406   xw = (XWServer *) malloc(sizeof(XWServer));
407   if(xw==NULL) {
408     fprintf(stderr, "%s: Insufficient memory for server descriptor.\n",
409 	    PGXWIN_SERVER);
410     return NULL;
411   };
412 /*
413  * Initialize the container, at least to the point at which it can safely be
414  * passed to del_XWServer().
415  */
416   xw->display = NULL;
417   xw->xrdb = xrdb;
418   xw->screen = 0;
419   xw->pgxwin = None;
420   xw->server_atom = None;
421   xw->client_data = None;
422   xw->active_list = NULL;
423   xw->closed_list = NULL;
424 
425   xw_ini_cursors(xw, &xw->col_cursor);
426   xw_ini_cursors(xw, &xw->gry_cursor);
427   xw->icon = None;
428   xw->wm_protocols  = None;
429   xw->wm_delete_win = None;
430   xw->geom_atom = None;
431 /*
432  * Initialize the list of resource database quarks required by xw_get_config().
433  */
434   if(xw_get_quarks(xw))
435     return del_XWServer(xw);
436 /*
437  * Determine the display name.
438  */
439   display_name = xw_get_default(xw, 0, &xw->quarks.display);
440 /*
441  * Open a connection to the display.
442  */
443   if((xw->display = XOpenDisplay(display_name)) == NULL) {
444     fprintf(stderr, "%s: cannot connect to X server [%s]\n", PGXWIN_SERVER,
445 	    XDisplayName(display_name));
446     return del_XWServer(xw);
447   };
448 /*
449  * Get the X resource database for the display, combined with the
450  * command-line database.
451  */
452   xw->xrdb = xw_get_xrdb(xw->display, xw->xrdb);
453 /*
454  * Get the screen number referenced in the display name.
455  */
456   xw->screen = DefaultScreen(xw->display);
457 /*
458  * Install an error handler for non-fatal errors. If we don't do this then
459  * Xlib will do its own error handling, which includes killing the program.
460  */
461   XSetErrorHandler(xw_handle_error);
462 /*
463  * Get selected window-manager atoms.
464  */
465   xw->wm_protocols = XInternAtom(xw->display, "WM_PROTOCOLS", False);
466   xw->wm_delete_win = XInternAtom(xw->display, "WM_DELETE_WINDOW", False);
467 /*
468  * Get the window geometry client/server transaction atom.
469  */
470   xw->geom_atom = XInternAtom(xw->display, "PGXWIN_GEOMETRY", False);
471 /*
472  * Create a simple unmapped window to receive events on.
473  */
474   xw->pgxwin = xw_server_window(xw);
475   if(xw->pgxwin==None)
476     return del_XWServer(xw);
477 /*
478  * Get the server selection atom.
479  */
480   xw->server_atom = XInternAtom(xw->display, PGXWIN_SERVER, False);
481   if(xw->server_atom == None) {
482     fprintf(stderr, "%s: Failed to obtain %s selection atom.\n",
483 	    PGXWIN_SERVER, PGXWIN_SERVER);
484     return del_XWServer(xw);
485   };
486 /*
487  * See if another server already exists by checking if the PGXWIN_SERVER
488  * selection is currently owned by another window.
489  */
490   if(XGetSelectionOwner(xw->display, xw->server_atom) != None) {
491     fprintf(stderr, "%s: Another server is already active.\n", PGXWIN_SERVER);
492     return del_XWServer(xw);
493   };
494 /*
495  * Grab ownership of the PGXWIN_SERVER selection.
496  */
497   XSetSelectionOwner(xw->display, xw->server_atom, xw->pgxwin, CurrentTime);
498   XFlush(xw->display);
499 /*
500  * Did another server beat us to it?
501  */
502   if(XGetSelectionOwner(xw->display, xw->server_atom) != xw->pgxwin) {
503     fprintf(stderr, "%s: Another server is already active.\n", PGXWIN_SERVER);
504     return del_XWServer(xw);
505   };
506 /*
507  * Get the client data property atom.
508  */
509   xw->client_data = XInternAtom(xw->display, "PGXWIN_CLIENT_DATA", False);
510   if(xw->client_data == None) {
511     fprintf(stderr, "%s: Failed to obtain PGXWIN_CLIENT_DATA selection atom.\n",
512 	    PGXWIN_SERVER);
513     return del_XWServer(xw);
514   };
515 /*
516  * Create two cursors to be used by clients. The normal cursor is used
517  * when cursor input is not expected, and the live cursor is used when
518  * input is expected. Allocate two versions or these cursors - one for
519  * color visuals and another for gray/monochrome displays.
520  */
521   if(xw_new_cursors(xw, 1, &xw->col_cursor) ||
522      xw_new_cursors(xw, 0, &xw->gry_cursor))
523     return del_XWServer(xw);
524   return xw;
525 }
526 
527 /*.......................................................................
528  * Clean up, and delete a XWServer descriptor.
529  *
530  * Input:
531  *  xw     XWServer *  The server descriptor to be deleted.
532  * Output:
533  *  return XWServer *  Allways NULL.
534  */
535 #ifdef __STDC__
del_XWServer(XWServer * xw)536 static XWServer *del_XWServer(XWServer *xw)
537 #else
538 static XWServer *del_XWServer(xw)
539      XWServer *xw;
540 #endif
541 {
542   if(xw) {
543 /*
544  * Display connection acquired?
545  */
546     if(xw->display) {
547 /*
548  * Delete the communication window.
549  * This will also clear the ownership of the PGXWIN_SERVER selection.
550  */
551       if(xw->pgxwin != None)
552 	XDestroyWindow(xw->display, xw->pgxwin);
553 /*
554  * Delete all client windows.
555  */
556       while(xw->active_list)
557 	del_PGwin(xw, rem_PGwin(&xw->active_list, xw->active_list));
558       while(xw->closed_list)
559 	del_PGwin(xw, rem_PGwin(&xw->closed_list, xw->closed_list));
560 /*
561  * Delete the cursors.
562  */
563       xw_del_cursors(xw, &xw->col_cursor);
564       xw_del_cursors(xw, &xw->gry_cursor);
565 /*
566  * Delete the icon pixmap.
567  */
568     if(xw->icon != None)
569       XFreePixmap(xw->display, xw->icon);
570 /*
571  * Close the connection to the display.
572  */
573       XCloseDisplay(xw->display);
574     };
575 /*
576  * Delete the empty container.
577  */
578     free((char *)xw);
579   };
580   return NULL;
581 }
582 
583 /*.......................................................................
584  * Create and display the server window in its iconic state.
585  *
586  * Input:
587  *  xw    XWServer *  The descriptor of the server.
588  *                    Only the 'display', 'screen' and 'wm_delete_window'
589  *                    members are used.
590  * Output:
591  *  return  Window    The ID of the server window, or None on error.
592  */
593 #ifdef __STDC__
xw_server_window(XWServer * xw)594 static Window xw_server_window(XWServer *xw)
595 #else
596 static Window xw_server_window(xw)
597      XWServer *xw;
598 #endif
599 {
600   Window window = None;     /* The new server window */
601   unsigned int width = 200; /* The width of the window when mapped */
602   unsigned int height = 20; /* The height of the window when mapped */
603   int x = 0;                /* The X-position of the window when mapped */
604   int y = 0;                /* The Y-position of the window when mapped */
605 /*
606  * Create the window. Bracket the window acquisition with
607  * xw_sync_error() calls, to determine whether any window creation
608  * errors occur.
609  */
610   xw_sync_error(xw);
611   window = XCreateSimpleWindow(xw->display, DefaultRootWindow(xw->display),
612 				x, y, width, height, (unsigned)1,
613 				WhitePixel(xw->display, xw->screen),
614 				BlackPixel(xw->display, xw->screen));
615   if(xw_sync_error(xw) || window==None) {
616     fprintf(stderr, "%s: Failed to create the PGPLOT server window.\n",
617 	    PGXWIN_SERVER);
618     return None;
619   };
620 /*
621  * Name the server window and its icon.
622  */
623   if(xw_name_window(xw, window, "PGPLOT Server", "pgxwin")) {
624     XDestroyWindow(xw->display, window);
625     return None;
626   };
627 /*
628  * Tell the window manager how to dimension and locate the window.
629  */
630   {
631     XSizeHints *hints = XAllocSizeHints();
632     if(!hints) {
633       fprintf(stderr, "%s: Insufficient memory.\n", PGXWIN_SERVER);
634       XDestroyWindow(xw->display, window);
635       return None;
636     };
637     hints->flags = PPosition | PSize;
638     hints->x = x;
639     hints->y = y;
640     hints->width  = width;
641     hints->height = height;
642     XSetWMNormalHints(xw->display, window, hints);
643     XFree((char *)hints);
644   };
645 /*
646  * Set window manager hints to tell the window manager that the
647  * initial state of the window when mapped, should be iconic.
648  */
649   if(xw_setwmhints(xw, xw->screen, window, 0)) {
650     XDestroyWindow(xw->display, window);
651     return None;
652   };
653 /*
654  * Arrange to be informed of window manager "delete window" actions.
655  */
656   XSetWMProtocols(xw->display, window, &xw->wm_delete_win, 1);
657 /*
658  * Display the server window if requested.
659  */
660   {
661     char *def = xw_get_default(xw, 0, &xw->quarks.visible);
662     if(xw_parse_bool(def, True) == True)
663       XMapWindow(xw->display, window);
664   };
665   XFlush(xw->display);
666   return window;
667 }
668 
669 /*.......................................................................
670  * Remove a PGPLOT /xw window from a given list of windows.
671  *
672  * Input:
673  *  pglist  Pgwins ** Pointer to the head of the window list.
674  *  pgw      PGwin *  The descriptor of the window to be deleted.
675  * Output:
676  *  return   PGwin *  The descriptor of the removed window, or NULL
677  *                    if not found.
678  */
679 #ifdef __STDC__
rem_PGwin(PGwin ** pglist,PGwin * pgw)680 static PGwin *rem_PGwin(PGwin **pglist, PGwin *pgw)
681 #else
682 static PGwin *rem_PGwin(pglist, pgw)
683      PGwin **pglist; PGwin *pgw;
684 #endif
685 {
686   PGwin *prev;  /* Descriptor of window before current position in list */
687   PGwin *next;  /* Descriptor of next window to be checked */
688 /*
689  * Search for the location of the window on the xw->pgwins list.
690  */
691   prev = NULL;
692   next = *pglist;
693   while(next!=NULL && next!=pgw) {
694     prev = next;
695     next = next->next;
696   };
697 /*
698  * Window not found?
699  */
700   if(next==NULL) {
701     fprintf(stderr, "%s(rem_PGwin): No such window.\n", PGXWIN_SERVER);
702     return NULL;
703   };
704 /*
705  * Relink around the window.
706  */
707   if(prev==NULL)
708     *pglist = next->next;
709   else
710     prev->next = next->next;
711 /*
712  * The descriptor is no longer in a list.
713  */
714   next->next = NULL;
715 /*
716  * Return the window descriptor.
717  */
718   return next;
719 }
720 
721 /*.......................................................................
722  * Add a PGPLOT /xw window to a given list of windows. The window is
723  * is inserted such that the list is maintained in order of window
724  * number.
725  *
726  * Input:
727  *  pglist  Pgwins ** Pointer to the head of the window list.
728  *  sort       int    If true, insert the window such that a list sorted
729  *                    in order of increasing pgw->number is maintained
730  *                    in that order. Otherwise insert at the head of
731  *                    the list to implement a LIFO list.
732  *  pgw      PGwin *  The descriptor of the window to be added.
733  * Output:
734  *  return   PGwin *  The descriptor of the added window.
735  */
736 #ifdef __STDC__
add_PGwin(PGwin ** pglist,int sort,PGwin * pgw)737 static PGwin *add_PGwin(PGwin **pglist, int sort, PGwin *pgw)
738 #else
739 static PGwin *add_PGwin(pglist, sort, pgw)
740      PGwin **pglist; int sort; PGwin *pgw;
741 #endif
742 {
743   PGwin *prev;   /* Pointer to previous window in list */
744   PGwin *next;   /* Pointer to next window in list */
745   if(pgw==NULL) {
746     fprintf(stderr, "%s(add_PGwin): NULL window descriptor.\n", PGXWIN_SERVER);
747     return NULL;
748   };
749 /*
750  * Maintain a sorted list?
751  */
752   if(sort) {
753 /*
754  * Find the correct position for the window in the window list.
755  */
756     prev = NULL;
757     next = *pglist;
758     while(next && next->id < pgw->id) {
759       prev = next;
760       next = next->next;
761     };
762 /*
763  * Insert the window between 'prev' and 'next'.
764  */
765     pgw->next = next;
766     if(prev==NULL)
767       *pglist = pgw;
768     else
769       prev->next = pgw;
770 /*
771  * To implement a LIFO list, insert the window at the head of the list.
772  */
773   } else {
774     pgw->next = *pglist;
775     *pglist = pgw;
776   };
777   return pgw;
778 }
779 
780 /*.......................................................................
781  * Delete a PGPLOT /xw window. Note that if the descriptor comes from
782  * a list of windows, it must first be removed from the list by
783  * rem_PGwin().
784  *
785  * Input:
786  *  xw    XWServer *  The descriptor of the server.
787  *  pgw      PGwin *  The descriptor of the window to be deleted.
788  * Output:
789  *  return   PGwin *  Allways NULL.
790  */
791 #ifdef __STDC__
del_PGwin(XWServer * xw,PGwin * pgw)792 static PGwin *del_PGwin(XWServer *xw, PGwin *pgw)
793 #else
794 static PGwin *del_PGwin(xw, pgw)
795      XWServer *xw; PGwin *pgw;
796 #endif
797 {
798   if(pgw) {
799 /*
800  * Remove the PGPLOT window from the display.
801  */
802     if(pgw->window != None)
803       XUnmapWindow(xw->display, pgw->window);
804 /*
805  * Destroy the graphical context descriptor.
806  */
807     if(pgw->gc)
808       XFreeGC(xw->display, pgw->gc);
809 /*
810  * Delete the colormap, any private color cells and the visual info descriptor.
811  */
812     if(pgw->color.vi) {
813       xw_del_Colormap(xw, pgw, pgw->color.vi, pgw->color.cmap,
814 		      pgw->color.ncol);
815       XFree((char *)pgw->color.vi);
816       pgw->color.vi = NULL;
817     };
818 /*
819  * Delete the array of pixel indexes.
820  */
821     if(pgw->color.pixel)
822       free((char *)pgw->color.pixel);
823 /*
824  * Destroy the PGPLOT /xw window.
825  */
826     if(pgw->window != None)
827       XDestroyWindow(xw->display, pgw->window);
828 /*
829  * Destroy its pixmap.
830  */
831     if(pgw->pixmap != None)
832       XFreePixmap(xw->display, pgw->pixmap);
833 /*
834  * Delete the container.
835  */
836     free((char *)pgw);
837   };
838   return NULL;
839 }
840 
841 /*.......................................................................
842  * Set up signal handlers.
843  */
844 #ifdef __STDC__
xw_set_signals(void)845 static int xw_set_signals(void)
846 #else
847 static int xw_set_signals()
848 #endif
849 {
850   signal(SIGINT, SIG_DFL);
851 /*
852  * We shouldn't be receiving any alarms, but just in case we do, arrange
853  * to ignore them.
854  */
855 #ifdef SIGALRM
856   signal(SIGALRM, SIG_IGN);
857 #endif
858 #ifdef SIGTSTP
859   signal(SIGTSTP, SIG_DFL);
860 #endif
861   signal(SIGTERM, SIG_DFL);
862   signal(SIGFPE, SIG_DFL);
863 #ifdef SIGABRT
864   signal(SIGABRT, SIG_DFL);
865 #endif
866 #ifdef SIGQUIT
867   signal(SIGQUIT, SIG_DFL);
868 #endif
869 /*
870  * We have arranged for this process to be a process group leader,
871  * and the only process in its group (to avoid receiving signals sent to
872  * the process that created it). POSIX.1 says that if such a process is
873  * orphaned when in a stopped state, the process will be sent SIGHUP
874  * followed by SIGCONT. Arrange to ignore the SIGHUP.
875  */
876 #ifdef SIGHUP
877   signal(SIGHUP, SIG_IGN);
878 #endif
879 #ifdef SIGPOLL
880   signal(SIGPOLL, SIG_DFL);
881 #endif
882   return 0;
883 }
884 
885 /*.......................................................................
886  * This function is called by X whenever a non-fatal error occurs
887  * on a given display connection. For the moment it does nothing but
888  * count such errors in an internal static error counter. This counter
889  * can then be queried and reset by sending a NULL error event pointer.
890  *
891  * Input:
892  *  display    Display *  The display connection on which the error occured.
893  *  event  XErrorEvent *  The descriptor of the error event, or NULL to
894  *                        request that the error counter be queried and reset.
895  * Output:
896  *  return         int    The return value is not specified by Xlib, so
897  *                        for Xlib calls we will simply return 0. For
898  *                        none Xlib calls (distinguishable by sending
899  *                        event==NULL), the value of the error counter
900  *                        is returned.
901  */
902 #ifdef __STDC__
xw_handle_error(Display * display,XErrorEvent * event)903 static int xw_handle_error(Display *display, XErrorEvent *event)
904 #else
905 static int xw_handle_error(display, event)
906      Display *display; XErrorEvent *event;
907 #endif
908 {
909   static int error_count = 0;
910 /*
911  * To query and reset the error counter, this program calls xw_handle_error()
912  * with a NULL error event pointer. This distinguishes it from a call
913  * from Xlib.
914  */
915   if(!event) {
916     int ret_count = error_count;
917     error_count = 0;   /* Reset the error counter */
918     return ret_count;  /* Return the pre-reset value of the error counter */
919 #ifdef DEBUG
920   } else {
921     char errtxt[81]; /* Buffer to receive error message in */
922 /*
923  * Get a message describing the error.
924  */
925     XGetErrorText(display, (int)event->error_code, errtxt, (int)sizeof(errtxt));
926     fprintf(stderr, "%s: XErrorEvent: %s\n", PGXWIN_SERVER, errtxt);
927 /*
928  * Report the operation that caused it. These opcode numbers are listed in
929  * <X11/Xproto.h>.
930  */
931     fprintf(stderr, "%s: Major opcode: %d, Resource ID: 0x%lx%s.\n",
932 	 PGXWIN_SERVER, (int) event->request_code,
933 	 (unsigned long) event->resourceid,
934          (event->resourceid==DefaultRootWindow(display)?" (Root window)":""));
935 #endif
936   };
937 /*
938  * Keep a record of the number of errors that have occurred since the
939  * error counter was last cleared.
940  */
941   error_count++;
942   return 0;
943 }
944 
945 /*.......................................................................
946  * This is the main server event loop, which listens for client events
947  * on client windows and the main event window. It returns only on
948  * server shutdown.
949  *
950  * Input:
951  *  xw   XWServer *   The server descriptor.
952  * Output:
953  *  return    int     0 - OK.
954  *                    1 - Error.
955  */
956 #ifdef __STDC__
xw_event_loop(XWServer * xw)957 static int xw_event_loop(XWServer *xw)
958 #else
959 static int xw_event_loop(xw)
960      XWServer *xw;
961 #endif
962 {
963   XEvent event;          /* The descriptor of the lastest X-event */
964   int have_selection=1;  /* If the server selection is stolen set this to 0 */
965 /*
966  * Enter the event loop.
967  */
968   do {
969     XNextEvent(xw->display, &event);
970     switch(event.type) {
971 /*
972  * Handle client-server messages.
973  */
974     case ClientMessage:
975       if(event.xclient.message_type == xw->wm_protocols) {
976 	if(xw_wm_message(xw, &event))
977 	  return 0;
978       } else {
979 	if(xw_client_message(xw, &event))
980 	  return 0;
981       };
982       break;
983 /*
984  * Has somebody else grabbed the selection atom?
985  */
986     case SelectionClear:
987       fprintf(stderr, "%s: Server selection usurped.\n", PGXWIN_SERVER);
988       have_selection = 0;
989       break;
990 /*
991  * Refuse all selection requests.
992  */
993     case SelectionRequest:
994       {
995 	XEvent reply;
996 	reply.xselection.type = SelectionNotify;
997 	reply.xselection.requestor = event.xselectionrequest.requestor;
998 	reply.xselection.selection = event.xselectionrequest.selection;
999 	reply.xselection.target = event.xselectionrequest.target;
1000 	reply.xselection.time = event.xselectionrequest.time;
1001 	reply.xselection.property = None;
1002 	XSendEvent(xw->display, event.xselection.requestor, False, (long)0,
1003 		   &reply);
1004       };
1005       break;
1006 /*
1007  * Handle window exposure events.
1008  */
1009     case Expose:
1010       if(xw_expose_win(xw, &event))
1011 	return 0;
1012       break;
1013 /*
1014  * Watch for client windows being destroyed.
1015  */
1016     case DestroyNotify:
1017       if(xw_check_destroy(xw, &event))
1018 	return 0;
1019       break;
1020     default:
1021       break;
1022     };
1023 /*
1024  * Quit if the selection atom has been stolen and no clients are connected.
1025  */
1026   } while(have_selection || xw->closed_list!=NULL);
1027   return 0;
1028 }
1029 
1030 /*.......................................................................
1031  * Handle messages sent to the server by PGPLOT /xw clients.
1032  *
1033  * Input:
1034  *  xw               XWServer *  The server descriptor.
1035  *  event  XEvent *  The descriptor of the message.
1036  * Output:
1037  *  return    int    0 - OK.
1038  *                   1 - Close server.
1039  */
1040 #ifdef __STDC__
xw_client_message(XWServer * xw,XEvent * event)1041 static int xw_client_message(XWServer *xw, XEvent *event)
1042 #else
1043 static int xw_client_message(xw, event)
1044      XWServer *xw; XEvent *event;
1045 #endif
1046 {
1047   Window client;  /* Source client window */
1048   PGwin *pgw;     /* Descriptor of the associated PGPLOT window */
1049 /*
1050  * The window argument contains the window of the client that sent the
1051  * event.
1052  */
1053   client = event->xclient.window;
1054 /*
1055  * New window required?
1056  */
1057   if(event->xclient.message_type == XA_WINDOW) {
1058     xw_new_window(xw, event, (PGwin *)0);
1059   } else {
1060 /*
1061  * Locate the descriptor of the PGPLOT /xw window that is connected to
1062  * the client (or NULL if not yet connected).
1063  */
1064     for(pgw=xw->active_list; pgw && pgw->client!=client; pgw=pgw->next);
1065 /*
1066  * Handle the specified message type.
1067  */
1068     if(pgw) {
1069       Atom type = event->xclient.message_type;
1070       switch(type) {
1071       case XA_PIXMAP:
1072 	xw_new_pixmap(xw, event, pgw);
1073 	break;
1074       case XA_CURSOR:
1075 	xw_ret_cursor(xw, event, pgw);
1076 	break;
1077       case XA_COLORMAP:
1078 	xw_ret_colors(xw, event, pgw);
1079 	break;
1080       default:
1081 	if(type == xw->geom_atom)
1082 	  xw_new_geom(xw, event, pgw);
1083 	else
1084 	  xw_ret_error(xw, event, pgw);  /* Unknown message type */
1085 	break;
1086       };
1087     };
1088   };
1089   return 0;
1090 }
1091 
1092 /*.......................................................................
1093  * Reply to a client that has requested the IDs of the normal and active
1094  * cursors.
1095  *
1096  * Input:
1097  *  xw    XWServer *  The server descriptor.
1098  *  event   XEvent *  The descriptor of the message.
1099  *  pgw      PGwin *  Descriptor of the client PGPLOT window.
1100  * Output:
1101  *  return     int    0 - OK.
1102  */
1103 #ifdef __STDC__
xw_ret_cursor(XWServer * xw,XEvent * event,PGwin * pgw)1104 static int xw_ret_cursor(XWServer *xw, XEvent *event, PGwin *pgw)
1105 #else
1106 static int xw_ret_cursor(xw, event, pgw)
1107      XWServer *xw; XEvent *event; PGwin *pgw;
1108 #endif
1109 {
1110 /*
1111  * Assign the cursor IDs to the return message descriptor.
1112  */
1113   event->xclient.data.l[0] = pgw->curs->norm;
1114   event->xclient.data.l[1] = pgw->curs->live;
1115   event->xclient.data.l[2] = pgw->crosshair;
1116   if(!XSendEvent(xw->display, pgw->client, False, (long)0, event))
1117     return 1;
1118   XFlush(xw->display);
1119   return 0;
1120 }
1121 
1122 /*.......................................................................
1123  * Reply to a client that has requested an unknown message type by
1124  * returning a message with the message_type field set to None.
1125  *
1126  * Input:
1127  *  xw    XWServer *  The server descriptor.
1128  *  event   XEvent *  The descriptor of the message.
1129  *  pgw      PGwin *  Descriptor of the client PGPLOT window (or NULL
1130  *                    if this is not known).
1131  * Output:
1132  *  return     int    0 - OK.
1133  */
1134 #ifdef __STDC__
xw_ret_error(XWServer * xw,XEvent * event,PGwin * pgw)1135 static int xw_ret_error(XWServer *xw, XEvent *event, PGwin *pgw)
1136 #else
1137 static int xw_ret_error(xw, event, pgw)
1138      XWServer *xw; XEvent *event; PGwin *pgw;
1139 #endif
1140 {
1141   event->xclient.message_type = None;
1142   if(!XSendEvent(xw->display, event->xclient.window, False, (long)0, event))
1143     return 1;
1144   XFlush(xw->display);
1145   return 0;
1146 }
1147 
1148 /*.......................................................................
1149  * Reply to a client that has requested colormap details.
1150  *
1151  * Input:
1152  *  xw    XWServer *  The server descriptor.
1153  *  event   XEvent *  The descriptor of the message.
1154  *  pgw      PGwin *  Descriptor of the client PGPLOT window.
1155  * Output:
1156  *  return     int    0 - OK.
1157  */
1158 #ifdef __STDC__
xw_ret_colors(XWServer * xw,XEvent * event,PGwin * pgw)1159 static int xw_ret_colors(XWServer *xw, XEvent *event,
1160 			 PGwin *pgw)
1161 #else
1162 static int xw_ret_colors(xw, event, pgw)
1163      XWServer *xw; XEvent *event; PGwin *pgw;
1164 #endif
1165 {
1166 /*
1167  * Assign the colormap attributes to the return message descriptor.
1168  */
1169   event->xclient.data.l[0] = pgw->color.cmap;
1170   event->xclient.data.l[1] = pgw->color.ncol;
1171   if(!XSendEvent(xw->display, pgw->client, False, (long)0, event))
1172     return 1;
1173   XFlush(xw->display);
1174 /*
1175  * If any colors were allocated, send the client the colormap pixel
1176  * indexes by placing them in the PGXWIN_CLIENT_DATA property on the
1177  * client's communication window.
1178  */
1179   if(pgw->color.cmap != None && xw_send_data(xw, pgw,
1180 					 (unsigned char *)&pgw->color.pixel[0],
1181 					 XW_LONG_PROP,
1182 					 (unsigned long)pgw->color.ncol,
1183 					 XA_INTEGER)==0)
1184     return 1;
1185   return 0;
1186 }
1187 
1188 /*.......................................................................
1189  * Respond to a client request for a new window.
1190  *
1191  * Input:
1192  *  xw    XWServer *  The server descriptor.
1193  *  event   XEvent *  The descriptor of the message.
1194  *  pgw      PGwin *  Descriptor of the client PGPLOT window.
1195  * Output:
1196  *  return     int    0 - OK.
1197  */
1198 #ifdef __STDC__
xw_new_window(XWServer * xw,XEvent * event,PGwin * pgw)1199 static int xw_new_window(XWServer *xw, XEvent *event, PGwin *pgw)
1200 #else
1201 static int xw_new_window(xw, event, pgw)
1202      XWServer *xw; XEvent *event; PGwin *pgw;
1203 #endif
1204 {
1205   int protocol = event->xclient.data.l[0];/* Protocol revision */
1206   int id = event->xclient.data.l[1];      /* Window number requested */
1207   int screen = event->xclient.data.l[2];  /* Screen to put window on */
1208   int disposition = event->xclient.data.l[3]; /* Close-down disposition */
1209   Window client = event->xclient.window;  /* Client communication window */
1210 /*
1211  * Limit the requested communication protocol to one that we can handle.
1212  */
1213   if(protocol > PGXWIN_REVISION)
1214     protocol = PGXWIN_REVISION;
1215 /*
1216  * Treat -ve window ids as equivalent to the 0 wildcard.
1217  */
1218   if(id<0)
1219     id = 0;
1220 /*
1221  * New window required?
1222  */
1223   if(pgw==NULL) {
1224 /*
1225  * See if the request can be satisfied by a currently unassigned
1226  * window.
1227  */
1228     if(xw->closed_list != NULL) {
1229 /*
1230  * Use the first window if no particular number has been requested.
1231  */
1232       if(id==0)
1233 	id = xw->closed_list->id;
1234 /*
1235  * Search for a window that has the required numeric id.
1236  */
1237       for(pgw=xw->closed_list; pgw && pgw->id != id; pgw=pgw->next);
1238 /*
1239  * If found, remove the window from the inactive list and register
1240  * it to the new client.
1241  */
1242       if(pgw) {
1243 	rem_PGwin(&xw->closed_list, pgw);
1244 	pgw->client = client;
1245       };
1246     };
1247 /*
1248  * If a window with the required ID was found, but it is displayed on
1249  * a different screen than the client now wants, destroy it so that a
1250  * new window of the requested ID can be created on the specified screen.
1251  */
1252     if(pgw && pgw->screen != screen)
1253       pgw = del_PGwin(xw, pgw);
1254 /*
1255  * Create a new window?
1256  */
1257     if(pgw==NULL) {
1258 /*
1259  * Determine an unused window number if no number was specified.
1260  * Note that the window list is arranged in increasing order
1261  * of window number.
1262  */
1263       if(id==0) {
1264 	PGwin *tmpwin = xw->active_list;
1265 	for(id=1; tmpwin && tmpwin->id==id; tmpwin=tmpwin->next,id++);
1266       };
1267 /*
1268  * See if the requested ID is already in use.
1269  */
1270       for(pgw=xw->active_list; pgw && pgw->id != id; pgw=pgw->next);
1271 /*
1272  * If the required id is not in use create a new window.
1273  */
1274       pgw = pgw ? NULL : new_PGwin(xw, id, screen, client, disposition);
1275     };
1276 /*
1277  * If a new window was acquired, add it to the active list and prepare it
1278  * for use. If during preparing the new client window, it turns out to have
1279  * been destroyed, return the PGPLOT window to the inactive list.
1280  */
1281     if(pgw) {
1282       if(xw_prep_window(xw, pgw, client, protocol)) {
1283 	add_PGwin(&xw->closed_list, 0, pgw);
1284 	pgw = NULL;
1285       };
1286     };
1287   };
1288 /*
1289  * If a window was assigned to the new client record its details in
1290  * the return client-message descriptor.
1291  */
1292   if(pgw && pgw->client == client) {
1293     event->xclient.data.l[0] = pgw->protocol;
1294     event->xclient.data.l[1] = pgw->id;
1295     event->xclient.data.l[2] = pgw->window;
1296     event->xclient.data.l[3] = pgw->disposition;
1297   } else {
1298     event->xclient.data.l[0] = protocol;
1299     event->xclient.data.l[1] = 0;
1300     event->xclient.data.l[2] = None;  /* No window available */
1301     event->xclient.data.l[3] = 0;
1302   };
1303   if(!XSendEvent(xw->display, client, False, (long)0, event))
1304     return 1;
1305   XFlush(xw->display);
1306   return 0;
1307 }
1308 
1309 /*.......................................................................
1310  * Set and return the window geometry.
1311  *
1312  * Input:
1313  *  xw    XWServer *  The server descriptor.
1314  *  event   XEvent *  The descriptor of the message.
1315  *  pgw      PGwin *  Descriptor of the client PGPLOT window.
1316  * Output:
1317  *  return     int    0 - OK.
1318  */
1319 #ifdef __STDC__
xw_new_geom(XWServer * xw,XEvent * event,PGwin * pgw)1320 static int xw_new_geom(XWServer *xw, XEvent *event, PGwin *pgw)
1321 #else
1322 static int xw_new_geom(xw, event, pgw)
1323      XWServer *xw; XEvent *event; PGwin *pgw;
1324 #endif
1325 {
1326   int x = event->xclient.data.l[0];
1327   int y = event->xclient.data.l[1];
1328   unsigned int width = event->xclient.data.l[2];
1329   unsigned int height = event->xclient.data.l[3];
1330   int xw_mask = event->xclient.data.l[4];
1331   int mask = 0; /* XParseGeometry() bit-mask */
1332 /*
1333  * Translate from the PGXWIN defined bitmap values to the local
1334  * XParseGeometry() bitmap values.
1335  */
1336   if(xw_mask & XW_WidthValue)
1337     mask |= WidthValue;
1338   if(xw_mask & XW_HeightValue)
1339     mask |= HeightValue;
1340   if(xw_mask & XW_XValue)
1341     mask |= XValue;
1342   if(xw_mask & XW_YValue)
1343     mask |= YValue;
1344   if(xw_mask & XW_XNegative)
1345     mask |= XNegative;
1346   if(xw_mask & XW_YNegative)
1347     mask |= YNegative;
1348 /*
1349  * Install the new geometry in the pgw->geom descriptor.
1350  */
1351   xw_set_geom(xw, pgw, x,y, width,height, mask);
1352 /*
1353  * Update the window-manager size hints for the current window.
1354  */
1355   {
1356     XSizeHints *hints = XAllocSizeHints();
1357     if(hints) {
1358       hints->flags = USPosition | USSize | PMinSize;
1359       hints->x = pgw->geom.x;
1360       hints->y = pgw->geom.y;
1361       hints->width = pgw->geom.width;
1362       hints->height = pgw->geom.height;
1363       hints->min_width = XW_MIN_WIDTH;
1364       hints->min_height = XW_MIN_HEIGHT;
1365 /*
1366  * Instate the new size hints in the WM_NORMAL_HINTS property.
1367  */
1368       XSetWMNormalHints(xw->display, pgw->window, hints);
1369       XFree((char *)hints);
1370     };
1371   };
1372 /*
1373  * Resize the window if requested.
1374  */
1375   if(mask & (WidthValue | HeightValue))
1376     XResizeWindow(xw->display, pgw->window, pgw->geom.width, pgw->geom.height);
1377 /*
1378  * Move the window if requested.
1379  */
1380   if(mask & (XValue | YValue))
1381     XMoveWindow(xw->display, pgw->window, pgw->geom.x, pgw->geom.y);
1382 /*
1383  * If the window has not previously been mapped, map it now.
1384  */
1385   if(!pgw->mapped) {
1386     XMapRaised(xw->display, pgw->window);
1387     pgw->mapped = 1;
1388   };
1389 /*
1390  * Return details of the new geometry to the client.
1391  */
1392   event->xclient.data.l[0] = pgw->geom.x;
1393   event->xclient.data.l[1] = pgw->geom.y;
1394   event->xclient.data.l[2] = pgw->geom.width;
1395   event->xclient.data.l[3] = pgw->geom.height;
1396   if(!XSendEvent(xw->display, pgw->client, False, (long)0, event))
1397     return 1;
1398   XFlush(xw->display);
1399   return 0;
1400 }
1401 
1402 /*.......................................................................
1403  * Respond to a client request for a new pixmap.
1404  *
1405  * Input:
1406  *  xw    XWServer *  The server descriptor.
1407  *  event   XEvent *  The descriptor of the message.
1408  *  pgw      PGwin *  Descriptor of the client PGPLOT window.
1409  * Output:
1410  *  return     int    0 - OK.
1411  */
1412 #ifdef __STDC__
xw_new_pixmap(XWServer * xw,XEvent * event,PGwin * pgw)1413 static int xw_new_pixmap(XWServer *xw, XEvent *event,
1414 			 PGwin *pgw)
1415 #else
1416 static int xw_new_pixmap(xw, event, pgw)
1417      XWServer *xw; XEvent *event; PGwin *pgw;
1418 #endif
1419 {
1420   unsigned long fill_pixel = event->xclient.data.l[0];
1421 /*
1422  * Delete the current pixmap if it doesn't have the required size.
1423  */
1424   if(pgw->pixmap != None) {
1425     Window root;
1426     int x, y;
1427     unsigned width, height, border, depth;
1428 /*
1429  * Determine the size of the existing pixmap.
1430  */
1431     XGetGeometry(xw->display, pgw->pixmap, &root, &x, &y, &width, &height,
1432 		 &border, &depth);
1433 /*
1434  * If the pixmap doesn't have a size equal to that requested in the last
1435  * PGXWIN_GEOMETRY transaction, delete it.
1436  */
1437     if(width != pgw->geom.width || height != pgw->geom.height) {
1438       XFreePixmap(xw->display, pgw->pixmap);
1439       pgw->pixmap = None;
1440     };
1441   };
1442 /*
1443  * Create a new pixmap if necessary.
1444  */
1445   if(pgw->pixmap == None) {
1446 /*
1447  * Bracket the pixmap acquisition with xw_sync_error() calls, to
1448  * determine whether any errors occur.
1449  */
1450     xw_sync_error(xw);
1451     pgw->pixmap = XCreatePixmap(xw->display, pgw->window, pgw->geom.width,
1452 			   pgw->geom.height, (unsigned) pgw->color.vi->depth);
1453     if(xw_sync_error(xw) || pgw->pixmap==None) {
1454       fprintf(stderr, "%s: Failed to allocate %dx%d pixmap.\n", PGXWIN_SERVER,
1455 	      pgw->geom.width, pgw->geom.height);
1456       pgw->pixmap = None;
1457     };
1458   };
1459 /*
1460  * Set the fill-color to that specified by the client.
1461  */
1462   XSetForeground(xw->display, pgw->gc, fill_pixel);
1463 /*
1464  * Clear the pixmap.
1465  */
1466   if(pgw->pixmap != None)
1467     XFillRectangle(xw->display, pgw->pixmap, pgw->gc, 0, 0,
1468 		   pgw->geom.width, pgw->geom.height);
1469 /*
1470  * Clear the window.
1471  */
1472   XClearWindow(xw->display, pgw->window);
1473   XFlush(xw->display);
1474 /*
1475  * Return the ID of the new pixmap and its size.
1476  */
1477   event->xclient.data.l[0] = pgw->pixmap;
1478   if(!XSendEvent(xw->display, pgw->client, False, (long)0, event))
1479     return 1;
1480   XFlush(xw->display);
1481   return 0;
1482 }
1483 
1484 /*.......................................................................
1485  * Check a resource string value against boolean values.
1486  *
1487  * Input:
1488  *  str       char *  The string value to be tested (NULL is ok).
1489  *  def       Bool    The default boolean value to take if the string
1490  *                    matches none of the recognized boolean strings.
1491  * Output:
1492  *  return    Bool    The boolean value of the string.
1493  */
1494 #ifdef __STDC__
xw_parse_bool(char * str,Bool def)1495 static Bool xw_parse_bool(char *str, Bool def)
1496 #else
1497 static Bool xw_parse_bool(str, def)
1498      char *str; Bool def;
1499 #endif
1500 {
1501 /*
1502  * Check for truth values.
1503  */
1504   if(xw_same_string(str, "true") || xw_same_string(str, "yes") ||
1505      xw_same_string(str, "t")    || xw_same_string(str, "on")  ||
1506      xw_same_string(str, "1"))
1507     def = True;
1508 /*
1509  * Check for false values.
1510  */
1511   else if(xw_same_string(str, "false") || xw_same_string(str, "no") ||
1512      xw_same_string(str, "f")    || xw_same_string(str, "off")  ||
1513      xw_same_string(str, "0"))
1514     def = False;
1515   return def;
1516 }
1517 
1518 /*.......................................................................
1519  * Check a resource string value against visual class names.
1520  *
1521  * Input:
1522  *  str       char *  The string value to be tested (NULL is ok).
1523  * Output:
1524  *  return     int    The Visual class parsed, or -1 to select the default.
1525  */
1526 #ifdef __STDC__
xw_parse_visual(char * str)1527 static int xw_parse_visual(char *str)
1528 #else
1529 static int xw_parse_visual(str)
1530      char *str;
1531 #endif
1532 {
1533 /*
1534  * Create a lookup table of recognised visual classes.
1535  */
1536   static struct {
1537     char *name;  /* Name of visual class */
1538     int class;   /* Enumerated identifier of visual class */
1539   } classes[] = {
1540     {"monochrome",  -2},
1541     {"default",     -1},
1542     {"pseudocolor", PseudoColor},
1543     {"directcolor", TrueColor},    /* We can't handle DirectColor */
1544     {"staticcolor", StaticColor},
1545     {"truecolor",   TrueColor},
1546     {"grayscale",   GrayScale},
1547     {"staticgray",  StaticGray}
1548   };
1549   int i;
1550 /*
1551  * Lookup the given class name.
1552  */
1553   if(str) {
1554     for(i=0; i<sizeof(classes)/sizeof(classes[0]); i++) {
1555       if(xw_same_string(str, classes[i].name))
1556 	return classes[i].class;
1557     };
1558 /*
1559  * Class name not recognised.
1560  */
1561     fprintf(stderr, "%s: Unrecognised visual type: \"%s\".\n",
1562 	    PGXWIN_SERVER, str);
1563   };
1564   return -1;
1565 }
1566 
1567 /*.......................................................................
1568  * Perform a case-insensitive string comparison. Leading and trailing
1569  * white-space are not significant.
1570  *
1571  * Input:
1572  *  s1,s2  char *   The strings to be compared.
1573  * Output:
1574  *  return  int     0 - The strings are not the same.
1575  *                  1 - The strings are the same.
1576  */
1577 #ifdef __STDC__
xw_same_string(char * s1,char * s2)1578 static int xw_same_string(char *s1, char *s2)
1579 #else
1580 static int xw_same_string(s1, s2)
1581      char *s1; char *s2;
1582 #endif
1583 {
1584 /*
1585  * If either of the strings are NULL pointers, report that they are equal
1586  * only if both are NULL.
1587  */
1588   if(s1==NULL || s2==NULL)
1589     return s1==NULL && s2==NULL;
1590 /*
1591  * Skip leading white-space.
1592  */
1593   while(*s1 && isspace(*s1))
1594     s1++;
1595   while(*s2 && isspace(*s2))
1596     s2++;
1597 /*
1598  * Find the section of the strings that are identical.
1599  */
1600   while(*s1 && *s2 &&
1601    (islower(*s1) ? toupper(*s1) : *s1) == (islower(*s2) ? toupper(*s2) : *s2)) {
1602     s1++;
1603     s2++;
1604   };
1605 /*
1606  * Skip trailing white-space.
1607  */
1608   while(*s1 && isspace(*s1))
1609     s1++;
1610   while(*s2 && isspace(*s2))
1611     s2++;
1612 /*
1613  * Are the strings equal?
1614  */
1615   return (*s1=='\0' && *s2=='\0');
1616 }
1617 
1618 /*.......................................................................
1619  * Record a given window geometry. As much or as little information may
1620  * be provided as is known and defaults will be substituted as necessary.
1621  * The values and mask returned by the XParseGeometry() Xlib function
1622  * may be presented directly to this function. If pgw->window!=None the
1623  * defaults will be those of the current window. The other defaults
1624  * use the appropriate combination of XW_DEF_WIDTH and XW_DEF_ASPECT
1625  * macros, the optional PGPLOT_XW_WIDTH environment variable and where
1626  * positions are not given, the size of the display, used to center the plot.
1627  *
1628  * Input:
1629  *  xw      XWServer *  The PGPLOT /xw server descriptor. Only the display
1630  *                      and screen members are required.
1631  *  pgw        PGwin *  The PGPLOT window descriptor.
1632  *  mask         int    A bit mask to specify which values have been provided
1633  *                      and how they should be interpretted. The mask is the
1634  *                      union of the following:
1635  *                        WidthValue  -  Use the given width value.
1636  *                       HeightValue  -  Use the given height value.
1637  *                            XValue  -  Use the given value of 'x'.
1638  *                            YValue  -  Use the given value of 'y'.
1639  *                         XNegative  -  x is wrt the right of the display.
1640  *                         YNegative  -  y is wrt the left of the display.
1641  *  x            int    The left edge of the window.
1642  *  y            int    The top edge of the window.
1643  *  width   unsigned    The width of the window.
1644  *  height  unsigned    The height of the window.
1645  * Output:
1646  *  pgw->geom XWgeom    The new window geometry.
1647  *  return       int    0 - OK.
1648  */
1649 #ifdef __STDC__
xw_set_geom(XWServer * xw,PGwin * pgw,int x,int y,unsigned int width,unsigned int height,int mask)1650 static int xw_set_geom(XWServer *xw, PGwin *pgw, int x, int y,
1651 		       unsigned int width, unsigned int height, int mask)
1652 #else
1653 static int xw_set_geom(xw, pgw, x, y, width, height, mask)
1654     XWServer *xw; PGwin *pgw; int x; int y;
1655      unsigned int width; unsigned int height; int mask;
1656 #endif
1657 {
1658   unsigned int d_pix_width;   /* Display width in pixels */
1659   unsigned int d_pix_height;  /* Display height in pixels */
1660   unsigned int d_mm_width;    /* Display width in mm */
1661   unsigned int d_mm_height;   /* DIsplay height in mm */
1662   unsigned int w_width=0;     /* Current window width (pixels) */
1663   unsigned int w_height=0;    /* Current window height (pixels) */
1664   int w_x;                    /* Current window x offset (pixels) */
1665   int w_y;                    /* Current window y offset (pixels) */
1666 /*
1667  * Determine the current display width and height in mm and pixels.
1668  */
1669   d_pix_width = DisplayWidth(xw->display, pgw->screen);
1670   d_mm_width = DisplayWidthMM(xw->display, pgw->screen);
1671   d_pix_height = DisplayHeight(xw->display, pgw->screen);
1672   d_mm_height = DisplayHeightMM(xw->display, pgw->screen);
1673 /*
1674  * If the window is already open, get its attributes.
1675  */
1676   if(pgw->window != None) {
1677     XWindowAttributes attr;     /* Current window attributes */
1678     Window child;
1679     XGetWindowAttributes(xw->display, pgw->window, &attr);
1680 /*
1681  * Translate from parent-relative to absolute X and Y window offsets.
1682  */
1683     XTranslateCoordinates(xw->display, pgw->window, attr.root,
1684 			  0, 0, &w_x, &w_y, &child);
1685     w_x -= XW_BORDER;
1686     w_y -= XW_BORDER;
1687     w_width = attr.width;
1688     w_height = attr.height;
1689   };
1690 /*
1691  * Ensure that all given values are positive.
1692  */
1693   if((mask & XValue) && x < 0) {
1694     mask |= XNegative;
1695     x = -x;
1696   };
1697   if((mask & YValue) && y < 0) {
1698     mask |= YNegative;
1699     y = -y;
1700   };
1701 /*
1702  * Is either the width or height unspecified?
1703  */
1704   if(!(mask & WidthValue) || !(mask & HeightValue)) {
1705 /*
1706  * Width given but not height?
1707  */
1708     if(mask & WidthValue) {
1709       height = (pgw->window!=None) ? w_height : (int)(width * XW_DEF_ASPECT);
1710 /*
1711  * Height given but not width?
1712  */
1713     } else if(mask & HeightValue) {
1714       width = (pgw->window!=None) ? w_width : (int)(height / XW_DEF_ASPECT);
1715     }
1716 /*
1717  * Neither width nor height given?
1718  */
1719     else {
1720       if(pgw->window != None) {
1721 	width = w_width;
1722 	height = w_height;
1723       } else {
1724 	char *envptr;
1725 /*
1726  * Use the XW_DEF_WIDTH macro to set the default width.
1727  */
1728 	width = XW_DEF_WIDTH;
1729 /*
1730  * The user PGPLOT_XW_WIDTH environment variable overrides the default width.
1731  */
1732 	if((envptr=getenv("PGPLOT_XW_WIDTH")) != NULL) {
1733 	  float frac_width;
1734 	  if(sscanf(envptr, "%f", &frac_width) != 1 || frac_width <= 0.0 ||
1735 	     frac_width > 2.0) {
1736 	    fprintf(stderr, "%s: Ignoring bad PGPLOT_XW_WIDTH=\"%s\"\n",
1737 		    PGXWIN_SERVER, envptr);
1738 	  } else {
1739 	    width = (unsigned int) (frac_width * d_pix_width);
1740 	  };
1741 	};
1742 /*
1743  * Use a hieght given by the default aspect ratio and the default width.
1744  */
1745 	height = width * XW_DEF_ASPECT;
1746       };
1747     };
1748   };
1749 /*
1750  * Apply width and height bounds.
1751  */
1752   if(width < XW_MIN_WIDTH)
1753     width = XW_MIN_WIDTH;
1754   if(height < XW_MIN_HEIGHT)
1755     height = XW_MIN_HEIGHT;
1756 /*
1757  * Assign the return width and height values.
1758  */
1759   pgw->geom.width = width;
1760   pgw->geom.height = height;
1761 /*
1762  * Determine the horizontal offset of the left edge of the window.
1763  */
1764   if(mask & XValue) {
1765     pgw->geom.x = (mask & XNegative) ? (d_pix_width - x - pgw->geom.width) : x;
1766     if(pgw->geom.x < 0)
1767       pgw->geom.x = 0;
1768   } else if(pgw->window != None) {
1769     pgw->geom.x = w_x;
1770   } else {
1771     pgw->geom.x = (d_pix_width - pgw->geom.width) / 2;  /* Center the window */
1772   };
1773 /*
1774  * Determine the vertical offset of the top edge of the window.
1775  */
1776   if(mask & YValue) {
1777     pgw->geom.y = (mask & YNegative) ?(d_pix_height - y - pgw->geom.height) : y;
1778     if(pgw->geom.y < 0)
1779       pgw->geom.y = 0;
1780   } else if(pgw->window != None) {
1781     pgw->geom.y = w_y;
1782   } else {
1783     pgw->geom.y = (d_pix_height - pgw->geom.height) / 2; /* Center the window */
1784   };
1785 /*
1786  * Determine the device resolution in pixels per inch.
1787  */
1788   pgw->geom.xpix_per_inch = 25.4 * ((double)d_pix_width / (double)d_mm_width);
1789   pgw->geom.ypix_per_inch = 25.4 * ((double)d_pix_height / (double)d_mm_height);
1790 /*
1791  * Determine the number of pixels needed to form a 1/4" margin around the
1792  * the plot area.
1793  */
1794   pgw->geom.xmargin = (int) (0.25 * pgw->geom.xpix_per_inch + 0.5);
1795   pgw->geom.ymargin = (int) (0.25 * pgw->geom.ypix_per_inch + 0.5);
1796 /*
1797  * Determine the pixel indexes that enclose an area bounded by 1/4" margins.
1798  */
1799   pgw->geom.xmin = pgw->geom.xmargin;
1800   pgw->geom.xmax = pgw->geom.width - pgw->geom.xmargin;
1801   pgw->geom.ymin = pgw->geom.ymargin;
1802   pgw->geom.ymax = pgw->geom.height - pgw->geom.ymargin;
1803   return 0;
1804 }
1805 
1806 /*.......................................................................
1807  * Determine the default geometry for a new window.
1808  *
1809  * Input:
1810  *  xw    XWServer *   The PGPLOT /xw server descriptor.
1811  *  pgw      PGwin *   The PGPLOT window descriptor.
1812  * Output:
1813  *  return  int     0 - OK.
1814  *                  1 - Error.
1815  */
1816 #ifdef __STDC__
xw_get_geom(XWServer * xw,PGwin * pgw)1817 static int xw_get_geom(XWServer *xw, PGwin *pgw)
1818 #else
1819 static int xw_get_geom(xw, pgw)
1820      XWServer *xw; PGwin *pgw;
1821 #endif
1822 {
1823   int x,y;             /* The offset of the window on the screen (pixels) */
1824   unsigned int width;  /* The width of the window (pixels) */
1825   unsigned int height; /* The height of the window (pixels) */
1826   int mask;            /* A bit mask to specify which values are known */
1827   char *geometry;      /* The X-default geometry string */
1828 /*
1829  * Get the optional pgxwin.geometry: resource string.
1830  */
1831   geometry = xw_get_default(xw, pgw->id, &xw->quarks.geom);
1832 /*
1833  * XParseGeometry() returns values specified in the geometry string and
1834  * a mask used to specify which values were found and how they should be
1835  * interpretted. If no geometry string was found, specify the mask for
1836  * an empty set.
1837  */
1838   mask = geometry ? XParseGeometry(geometry, &x, &y, &width, &height) : 0;
1839 /*
1840  * Send the values and the selection mask to xw_set_geom(). It will fill
1841  * in default values for members not marked in the mask.
1842  */
1843   return xw_set_geom(xw, pgw, x, y, width, height, mask);
1844 }
1845 
1846 /*.......................................................................
1847  * Handle expose-events on client windows.
1848  *
1849  * Input:
1850  *  xw     XWServer *  The server descriptor.
1851  *  event    XEvent *  The descriptor of the expose event.
1852  * Output:
1853  *  return      int    0 - OK.
1854  *                     1 - Close server.
1855  */
1856 #ifdef __STDC__
xw_expose_win(XWServer * xw,XEvent * event)1857 static int xw_expose_win(XWServer *xw, XEvent *event)
1858 #else
1859 static int xw_expose_win(xw, event)
1860      XWServer *xw; XEvent *event;
1861 #endif
1862 {
1863   Window window;  /* The window on which the expose event was generated */
1864   PGwin *pgw;     /* Descriptor of the connected PGPLOT /xw window */
1865 /*
1866  * The window argument contains the window of the client that sent the
1867  * event.
1868  */
1869   window = event->xexpose.window;
1870 /*
1871  * Locate the descriptor of the PGPLOT /xw window requiring an update.
1872  */
1873   for(pgw=xw->active_list; pgw && pgw->window!=window; pgw=pgw->next);
1874   if(pgw==NULL)
1875     for(pgw=xw->closed_list; pgw && pgw->window!=window; pgw=pgw->next);
1876 /*
1877  * If it is one of our windows we have a backing pixmap to repair
1878  * the damaged part of the window, copy the exposed area from the
1879  * pixmap to the window.
1880  */
1881   if(pgw && pgw->pixmap != None) {
1882     XCopyArea(xw->display, pgw->pixmap, pgw->window, pgw->gc,
1883 	      event->xexpose.x, event->xexpose.y,
1884 	      (unsigned) event->xexpose.width, (unsigned) event->xexpose.height,
1885 	      event->xexpose.x, event->xexpose.y);
1886     XFlush(xw->display);
1887   };
1888   return 0;
1889 }
1890 
1891 /*.......................................................................
1892  * Handle messages sent to the server by the window manager.
1893  *
1894  * Input:
1895  *  xw    XWServer *  The server descriptor.
1896  *  event   XEvent *  The descriptor of the message.
1897  * Output:
1898  *  return     int    0 - OK.
1899  *                    1 - Close server.
1900  */
1901 #ifdef __STDC__
xw_wm_message(XWServer * xw,XEvent * event)1902 static int xw_wm_message(XWServer *xw, XEvent *event)
1903 #else
1904 static int xw_wm_message(xw, event)
1905      XWServer *xw; XEvent *event;
1906 #endif
1907 {
1908   PGwin *pgw;     /* Descriptor of a PGPLOT window */
1909   Window window;  /* Window to which the message was sent */
1910 /*
1911  * Hopefully the window argument contains the window of the client that
1912  * sent the event. My book doesn't say.
1913  */
1914   window = event->xclient.window;
1915 /*
1916  * Handle the specific window-manager message.
1917  */
1918   if(event->xclient.data.l[0] == xw->wm_delete_win) {  /* Delete window */
1919 /*
1920  * Was the message sent to the server window?
1921  */
1922     if(window == xw->pgxwin) {
1923 /*
1924  * Delete inactive windows.
1925  */
1926       while(xw->closed_list)
1927 	del_PGwin(xw, rem_PGwin(&xw->closed_list, xw->closed_list));
1928 /*
1929  * If there are no remaining windows the server should be closed down.
1930  */
1931       return xw->active_list == NULL;
1932     } else {
1933 /*
1934  * Find out if it is a window from the active list.
1935  */
1936       for(pgw=xw->active_list; pgw && pgw->window!=window; pgw=pgw->next);
1937       if(pgw) {
1938 	if(pgw->acceptquit) {
1939 	  XKillClient(xw->display, pgw->client);
1940 	  rem_PGwin(&xw->active_list, pgw);
1941 	  del_PGwin(xw, pgw);
1942 	} else {
1943 	  pgw->disposition = XW_DELETE; /* Defer deletion until inactive */
1944 	};
1945       };
1946 /*
1947  * Find out if it is a window from the inactive list.
1948  */
1949       for(pgw=xw->closed_list; pgw && pgw->window!=window; pgw=pgw->next);
1950       if(pgw) {
1951 	rem_PGwin(&xw->closed_list, pgw);
1952 	del_PGwin(xw, pgw);
1953       };
1954     };
1955   };
1956   return 0;
1957 }
1958 
1959 /*.......................................................................
1960  * Check a DestroyNotify event to see if it came from one of our
1961  * client windows. If it did, close the connection to that client.
1962  *
1963  * Input:
1964  *  xw    XWServer *  The server descriptor.
1965  *  event   XEvent *  The descriptor of the message.
1966  * Output:
1967  *  return     int    0 - OK.
1968  *                    1 - Close server.
1969  */
1970 #ifdef __STDC__
xw_check_destroy(XWServer * xw,XEvent * event)1971 static int xw_check_destroy(XWServer *xw, XEvent *event)
1972 #else
1973 static int xw_check_destroy(xw, event)
1974      XWServer *xw; XEvent *event;
1975 #endif
1976 {
1977   PGwin *pgw;     /* Descriptor of the PGPLOT window */
1978   Window window;  /* The window wo which the event was sent */
1979 /*
1980  * The destroyed window is recorded in the 'window' member.
1981  */
1982   window = event->xdestroywindow.window;
1983 /*
1984  * See if the window is a client of one of the windows managed by us.
1985  */
1986   for(pgw=xw->active_list; pgw && pgw->client!=window; pgw=pgw->next);
1987 /*
1988  * If it was one of our clients, remove its PGPLOT window from the active
1989  * list.
1990  */
1991   if(pgw) {
1992     rem_PGwin(&xw->active_list, pgw);
1993 /*
1994  * Mark the window as unused by changing the cursor.
1995  */
1996     XDefineCursor(xw->display, pgw->window, pgw->curs->idle);
1997 /*
1998  * If the window should be retained mapped, move it to the inactive
1999  * window list. Otherwise delete it.
2000  */
2001     if(pgw->disposition == XW_DELETE) {
2002       del_PGwin(xw, pgw);
2003     } else {
2004       add_PGwin(&xw->closed_list, 0, pgw);
2005       if(pgw->disposition == XW_ICONIZE)
2006 	XIconifyWindow(xw->display, pgw->window, pgw->screen);
2007     };
2008 /*
2009  * See if one of our PGPLOT windows got destroyed by another program.
2010  * In principle this shouldn't happen because other programs shouldn't
2011  * be deleting resources that we created. Unfortunately there is at
2012  * least one program that does do this. The TkSteal program steals
2013  * windows from other applications and adds them to the window
2014  * hierarchy of a given Tk application. When the Tk program exits
2015  * the window then gets destroyed - arrgh!
2016  */
2017   } else {
2018 /*
2019  * Check the list of active windows first.
2020  */
2021     for(pgw=xw->active_list; pgw && pgw->window!=window; pgw=pgw->next);
2022     if(pgw) {
2023       fprintf(stderr,
2024 	      "\n%s: Active PGPLOT window %d destroyed by another program!\n",
2025 	      PGXWIN_SERVER, pgw->id);
2026       del_PGwin(xw, rem_PGwin(&xw->active_list, pgw));
2027 /*
2028  * Check the list of inactive windows if not found in the active list.
2029  */
2030     } else {
2031       for(pgw=xw->closed_list; pgw && pgw->window!=window; pgw=pgw->next);
2032       if(pgw)
2033 	del_PGwin(xw, rem_PGwin(&xw->closed_list, pgw));
2034     };
2035   };
2036   return 0;
2037 }
2038 
2039 /*.......................................................................
2040  * Create a new PGPLOT window.
2041  *
2042  * Input:
2043  *  xw     XWServer * The PGPLOT /xw server descriptor.
2044  *  id          int   The numeric id used by PGPLOT users to refer to the
2045  *                    window.
2046  *  screen      int   The screen on which to create the window.
2047  *  client   Window   The window ID of the client to which the new window
2048  *                    is to be assigned.
2049  *  disposition int   The close-down mode desired for the window when
2050  *                    the client disconnects:
2051  *                      XW_PERSIST - Keep the window mapped.
2052  *                      XW_ICONIZE - Iconize the window.
2053  *                      XW_DELETE  - Delete window.
2054  * Output:
2055  *  return  PGwin * The new PGPLOT window descriptor, or NULL on error.
2056  */
2057 #ifdef __STDC__
new_PGwin(XWServer * xw,int id,int screen,Window client,int disposition)2058 static PGwin *new_PGwin(XWServer *xw, int id, int screen, Window client,
2059 			int disposition)
2060 #else
2061 static PGwin *new_PGwin(xw, id, screen, client, disposition)
2062      XWServer *xw; int id; int screen; Window client; int disposition;
2063 #endif
2064 {
2065   PGwin *pgw;   /* The return descriptor */
2066 /*
2067  * Allocate the descriptor.
2068  */
2069   pgw = (PGwin *) malloc(sizeof(PGwin));
2070   if(pgw==NULL) {
2071     fprintf(stderr, "%s: Insufficient memory for new PGPLOT window.\n",
2072 	    PGXWIN_SERVER);
2073     return del_PGwin(xw, pgw);
2074   };
2075 /*
2076  * Initialize all members of the descriptor at least to the point at which
2077  * the descriptor can safely be sent to del_PGwin(). All pointers must
2078  * be assigned NULL and XIDs assigned None, so that del_PGwin() knows what
2079  * hasn't been allocated yet.
2080  */
2081   pgw->window = None;
2082   pgw->parent = None;
2083   pgw->client = client;
2084   pgw->protocol = PGXWIN_REVISION;
2085   pgw->pixmap = None;
2086   pgw->gc = NULL;
2087   pgw->id = id;
2088   pgw->screen = screen;
2089   pgw->mapped = 0;
2090   pgw->disposition = disposition;
2091   pgw->color.vi = NULL;
2092   pgw->color.cmap = None;
2093   pgw->color.ncol = 0;
2094   pgw->color.pixel = NULL;
2095   pgw->color.monochrome = 1;
2096   pgw->color.default_class = 0;
2097   pgw->curs = NULL;
2098   pgw->next = NULL;
2099 /*
2100  * Get the configuration defaults for the window.
2101  */
2102   if(xw_get_config(xw, pgw))
2103     return del_PGwin(xw, pgw);
2104 /*
2105  * If a persistent window has been requested, see if it should be iconized
2106  * when inactive.
2107  */
2108   if(pgw->disposition == XW_PERSIST && pgw->iconize)
2109     pgw->disposition = XW_ICONIZE;
2110 /*
2111  * Record the parent window ID.
2112  */
2113   pgw->parent = RootWindow(xw->display, pgw->screen);
2114 /*
2115  * Get a visual and colormap for the pending window.
2116  */
2117   if(xw_get_visual(xw, pgw))
2118     return del_PGwin(xw, pgw);
2119 /*
2120  * Get the default geometry for the window.
2121  */
2122   if(xw_get_geom(xw, pgw))
2123     return del_PGwin(xw, pgw);
2124 /*
2125  * Get color or black-and-white cursors for the window.
2126  */
2127   if(DisplayCells(xw->display, pgw->screen) < 10 ||
2128      pgw->color.default_class == GrayScale ||
2129      pgw->color.default_class == StaticGray) {
2130     pgw->curs = &xw->gry_cursor;
2131   } else {
2132     pgw->curs = &xw->col_cursor;
2133   };
2134 /*
2135  * Create the window.
2136  */
2137   {
2138     XSetWindowAttributes attr;
2139     unsigned long mask = CWEventMask | CWDontPropagate |
2140                          CWBorderPixel | CWBackPixel | CWCursor;
2141     attr.event_mask    = ExposureMask | StructureNotifyMask;
2142     attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
2143                             KeyPressMask | KeyReleaseMask;
2144     attr.border_pixel  = WhitePixel(xw->display, pgw->screen);
2145     attr.background_pixel = BlackPixel(xw->display, pgw->screen);
2146     attr.cursor = pgw->curs->idle;
2147     if(!pgw->color.monochrome) {
2148       mask |= CWColormap;
2149       attr.colormap = pgw->color.cmap;
2150     };
2151 /*
2152  * Bracket the window acquisition with xw_sync_error() calls, to
2153  * determine whether any window creation errors occur.
2154  */
2155     xw_sync_error(xw);
2156     pgw->window = XCreateWindow(xw->display, pgw->parent, pgw->geom.x,
2157 		      pgw->geom.y, pgw->geom.width, pgw->geom.height,
2158 		      XW_BORDER, pgw->color.vi->depth, InputOutput,
2159 		      pgw->color.vi->visual, mask, &attr);
2160     if(xw_sync_error(xw) || pgw->window == None) {
2161       fprintf(stderr,
2162        "%s: Failed to create window with visual: id=0x%lx class=%d depth=%u.\n",
2163 	      PGXWIN_SERVER, (unsigned long)pgw->color.vi->visualid,
2164 	      pgw->color.vi->class, pgw->color.vi->depth);
2165       fprintf(stderr, "%s: Colormap id=0x%lx.\n", PGXWIN_SERVER,
2166 	      (unsigned long) pgw->color.cmap);
2167       pgw->window = None;
2168       return del_PGwin(xw, pgw);
2169     };
2170   };
2171 /*
2172  * Arrange to be informed of window manager "delete window" actions.
2173  */
2174   XSetWMProtocols(xw->display, pgw->window, &xw->wm_delete_win, 1);
2175 /*
2176  * Give the window and icon names.
2177  */
2178   {
2179     char window_name[sizeof(XW_WINDOW_NAME)+10];
2180     char icon_name[sizeof(XW_ICON_NAME)+10];
2181     sprintf(window_name, "%s %d", XW_WINDOW_NAME, pgw->id);
2182     sprintf(icon_name, "%s%d", XW_ICON_NAME, pgw->id);
2183     if(xw_name_window(xw, pgw->window, window_name, icon_name))
2184       return del_PGwin(xw, pgw);
2185   };
2186 /*
2187  * Specify window-state hints to the window manager.
2188  */
2189   if(xw_setwmhints(xw, pgw->screen, pgw->window, pgw->id))
2190     return del_PGwin(xw, pgw);
2191 /*
2192  * Create and initialize a graphical context descriptor. This is where
2193  * Line widths, line styles, fill styles, plot color etc.. are
2194  * recorded.
2195  */
2196   {
2197     XGCValues gcv;
2198     gcv.graphics_exposures = False;
2199     xw_sync_error(xw);
2200     pgw->gc = XCreateGC(xw->display, pgw->window, (unsigned long)
2201 			(GCGraphicsExposures), &gcv);
2202   };
2203   if(xw_sync_error(xw) || pgw->gc==NULL) {
2204     fprintf(stderr,
2205 	    "%s: Failed to allocate graphical context for window 0x%lx.\n",
2206 	    PGXWIN_SERVER, (unsigned long) pgw->window);
2207     return del_PGwin(xw, pgw);
2208   };
2209 /*
2210  * Return the initialized descriptor for use.
2211  */
2212   return pgw;
2213 }
2214 
2215 /*.......................................................................
2216  * Set up the visual and colormap for the /xw window.
2217  *
2218  * Input:
2219  *  xw  XWServer *  The PGPLOT /xw server descriptor.
2220  *  pgw    PGwin *  The PGPLOT window descriptor.
2221  * Output:
2222  *  pgw->color.vi             The info descriptor of the visual to be used.
2223  *  pgw->color.cmap           The ID of the colormap to use.
2224  *  pgw->color.ncol           The number of colors available.
2225  *  pgw->color.pixel[0..ncol] The color cell pixel indexes.
2226  *  pgw->color.monochrome     If true, use black and white instead of the above
2227  *                           values.
2228  *
2229  *  return   int     0 - OK.
2230  *                   1 - Error.
2231  */
2232 #ifdef __STDC__
xw_get_visual(XWServer * xw,PGwin * pgw)2233 static int xw_get_visual(XWServer *xw, PGwin *pgw)
2234 #else
2235 static int xw_get_visual(xw, pgw)
2236      XWServer *xw; PGwin *pgw;
2237 #endif
2238 {
2239 /*
2240  * Initialize the color descriptor.
2241  */
2242   pgw->color.vi = NULL;
2243   pgw->color.cmap = None;
2244   pgw->color.ncol = 2;
2245   pgw->color.pixel = NULL;
2246   pgw->color.monochrome = 1;
2247   pgw->color.default_class = 0;
2248 /*
2249  * Get the XVisualInfo structure for the default visual.
2250  */
2251   pgw->color.vi = xw_visual_info(xw->display, pgw->screen,
2252 				 DefaultVisual(xw->display, pgw->screen));
2253   if(!pgw->color.vi)
2254     return 1;
2255 /*
2256  * Allocate an array to store pixel indexes in.
2257  */
2258   pgw->color.pixel=(unsigned long *)malloc(sizeof(unsigned long) * pgw->maxcol);
2259   if(pgw->color.pixel==NULL) {
2260     fprintf(stderr, "%s: Insufficient memory for new PGPLOT window.\n",
2261 	    PGXWIN_SERVER);
2262     return 1;
2263   };
2264 /*
2265  * Record the class of the default colormap.
2266  */
2267   pgw->color.default_class = pgw->color.vi->class;
2268 /*
2269  * Check for user preferences before starting the default visual search.
2270  */
2271   if(pgw->visual_class != -2 &&
2272      (pgw->visual_class<0 || !xw_find_visual(xw, pgw, pgw->visual_class))) {
2273 /*
2274  * Color display?
2275  */
2276     switch(pgw->color.default_class) {
2277     case PseudoColor:
2278     case StaticColor:
2279     case DirectColor:
2280     case TrueColor:
2281       if(xw_find_visual(xw, pgw, PseudoColor) ||
2282 	 xw_find_visual(xw, pgw, StaticColor) ||
2283 	 xw_find_visual(xw, pgw, TrueColor))
2284 	return 0;
2285       break;
2286 /*
2287  * Gray-scale display?
2288  */
2289     case GrayScale:
2290     case StaticGray:
2291       if(xw_find_visual(xw, pgw, GrayScale) ||
2292 	 xw_find_visual(xw, pgw, StaticGray))
2293 	return 0;
2294       break;
2295     };
2296   };
2297 /*
2298  * Use the monochrome default if no usable colormap was found.
2299  */
2300   return 0;
2301 }
2302 
2303 /*.......................................................................
2304  * Private function of xw_get_visual(), used to find a visual of a given
2305  * class and at least pgw->mincol colors. The pgw->color structure will
2306  * be left untouched unless a good colormap is located. It is assumed
2307  * that pgw->color.vi is initialized with a info structure for the
2308  * default visual returned by xw_visual_info().
2309  *
2310  * Input:
2311  *  xw   XWServer *  The PGPLOT /xw server descriptor.
2312  *  pgw     PGwin *  The PGPLOT window descriptor.
2313  *  class     int    The type of colormap required, chosen from:
2314  *                      PseudoColor,StaticColor,GrayScale,StaticGray.
2315  * Input/Output:
2316  *
2317  *  return    int    0 - No colormap was found - pgw->color.* remain
2318  *                       at the values that they had on input.
2319  *                   1 - A suitable colormap was found. The following
2320  *                       members of pgw->color will be set as indicated.
2321  *                        vi    -  The info descriptor of the located visual.
2322  *                        cmap  -  The ID of the located colormap.
2323  *                        pixel -  The color cell pixel indexes.
2324  *                        ncol  -  The number of colors available.
2325  *                       Note that the returned colormap and pixels must
2326  *                       be deleted via xw_del_Colormap() and the vi structure
2327  *                       via XFree() when the window is destroyed.
2328  */
2329 #ifdef __STDC__
xw_find_visual(XWServer * xw,PGwin * pgw,int class)2330 static int xw_find_visual(XWServer *xw, PGwin *pgw, int class)
2331 #else
2332 static int xw_find_visual(xw, pgw, class)
2333      XWServer *xw; PGwin *pgw; int class;
2334 #endif
2335 {
2336   Colormap cmap=None;   /* The new colormap */
2337   int ncol=0;           /* The number of colors allocated */
2338   XVisualInfo *vi=NULL; /* The visual info of a private colormap */
2339 /*
2340  * See if the default (shared) visual supports the required class of
2341  * colormap.
2342  */
2343   if(class == pgw->color.vi->class) {
2344     cmap = DefaultColormap(xw->display, pgw->screen);
2345     ncol = xw_get_colorcells(xw, pgw, pgw->color.vi, cmap);
2346     if(ncol >= pgw->maxcol) {
2347       pgw->color.cmap = cmap;
2348       pgw->color.ncol = ncol;
2349       pgw->color.monochrome = 0;
2350       return 1;
2351     };
2352     xw_del_Colormap(xw, pgw, pgw->color.vi, cmap, ncol);
2353   };
2354 /*
2355  * Acquire a private colormap.
2356  */
2357   {
2358     XVisualInfo vi_template;     /* Visual search template */
2359     XVisualInfo *vi_list = NULL; /* List of matching visuals */
2360     int nmatch;                  /* Number of matching visuals in vi_list[] */
2361 /*
2362  * Get a list of all visuals of the requested class.
2363  */
2364     vi_template.class = class;
2365     vi_list = XGetVisualInfo(xw->display, (long)VisualClassMask, &vi_template,
2366 			     &nmatch);
2367 /*
2368  * Search the list for a visual that has a colormap size that
2369  * best matches pgw->maxcol. Note that the colormap_size memeber of
2370  * the visual info structure effectively provides the number of
2371  * "independant" color table entries. Thus the following algorithm
2372  * works even for colormaps of TrueColor and DirectColor where the
2373  * colormap_size attribute refers to the size of a single primary color
2374  * table.
2375  */
2376     if(vi_list) {
2377       XVisualInfo *vi_below = NULL;
2378       XVisualInfo *vi_above = NULL;
2379       for(vi=vi_list; vi<vi_list+nmatch; vi++) {
2380 	if(vi->colormap_size < pgw->maxcol) {
2381 	  if(!vi_below || vi->colormap_size > vi_below->colormap_size)
2382 	    vi_below = vi;
2383 	} else {
2384 	  if(!vi_above || vi->colormap_size < vi_above->colormap_size)
2385 	    vi_above = vi;
2386 	};
2387       };
2388 /*
2389  * If available, use a visual that has at least pgw->maxcol independant
2390  * colors.
2391  */
2392       if(vi_above)
2393 	vi = vi_above;
2394       else if(vi_below)
2395 	vi = vi_below;
2396       else
2397 	vi = NULL;
2398 /*
2399  * Did we get a usable visual?
2400  */
2401       if(vi && vi->colormap_size > 2)
2402 	vi = xw_visual_info(xw->display, pgw->screen, vi->visual);
2403       XFree((char *) vi_list);
2404     };
2405   };
2406 /*
2407  * Bracket the colormap acquisition with xw_sync_error() calls, to
2408  * determine whether any allocation errors occur.
2409  */
2410   if(vi) {
2411     xw_sync_error(xw);
2412     cmap = XCreateColormap(xw->display, pgw->parent, vi->visual, AllocNone);
2413     if(xw_sync_error(xw) || cmap == None) {
2414       fprintf(stderr,
2415          "%s: XCreateColormap failed for visual: id=0x%lx class=%d depth=%u.\n",
2416 	 PGXWIN_SERVER, (unsigned long)vi->visualid, vi->class, vi->depth);
2417 /*
2418  * Allocate color-cells in the new colormap.
2419  */
2420     } else if((ncol = xw_get_colorcells(xw, pgw, vi, cmap)) >= pgw->mincol) {
2421       XFree((char *) pgw->color.vi);
2422       pgw->color.vi   = vi;
2423       pgw->color.cmap = cmap;
2424       pgw->color.ncol = ncol;
2425       pgw->color.monochrome = 0;
2426 #ifdef DEBUG
2427       fprintf(stderr, "%s: Got %d colors in colormap 0x%lx, visual id=0x%lx class=%d depth=%u.\n", PGXWIN_SERVER, ncol, (unsigned long)cmap, (unsigned long) vi->visualid, vi->class, vi->depth);
2428 #endif
2429       return 1;
2430     } else {
2431       xw_del_Colormap(xw, pgw, vi, cmap, ncol);
2432     };
2433     XFree((char *) vi);
2434   };
2435 /*
2436  * Failed to get a colormap of the requested class.
2437  */
2438   return 0;
2439 }
2440 
2441 /*.......................................................................
2442  * Private function of xw_find_visual(), used to allocate color cells for a
2443  * given colormap and return a count of the number allocated.
2444  *
2445  * Input:
2446  *  xw     XWServer *  The PGPLOT /xw server descriptor.
2447  *  pgw       PGwin *  The PGPLOT window descriptor.
2448  *  vi  XVisualInfo *  The info descripto of the visual containing the colormap.
2449  *  cmap   Colormap    The colormap ID to associate the cells with.
2450  * Output:
2451  *  pgw->color.pixel[] The colorcell indexes.
2452  *  return      int    The number of colors allocated.
2453  */
2454 #ifdef __STDC__
xw_get_colorcells(XWServer * xw,PGwin * pgw,XVisualInfo * vi,Colormap cmap)2455 static int xw_get_colorcells(XWServer *xw, PGwin *pgw, XVisualInfo *vi,
2456 			     Colormap cmap)
2457 #else
2458 static int xw_get_colorcells(xw, pgw, vi, cmap)
2459      XWServer *xw; PGwin *pgw; XVisualInfo *vi; Colormap cmap;
2460 #endif
2461 {
2462   unsigned long maxcol; /* The max number of cells to attempt to allocate */
2463   int ncol;             /* The number of color-cells allocated */
2464 /*
2465  * Determine the number of color cells in the colormap.
2466  */
2467   switch(vi->class) {
2468   case PseudoColor:
2469   case GrayScale:
2470   case StaticColor:
2471   case StaticGray:
2472     maxcol = vi->colormap_size;
2473     break;
2474   case TrueColor:
2475   case DirectColor:
2476 /*
2477  * Determine the maximum number of significant colors available
2478  * by looking at the total number of bits set in the pixel bit-masks.
2479  */
2480     maxcol = 1;
2481     {
2482       unsigned long rgb_mask = (vi->red_mask | vi->green_mask | vi->blue_mask);
2483       do {
2484 	if(rgb_mask & (unsigned long)0x1)
2485 	  maxcol <<= (unsigned long)1;
2486       } while(maxcol < pgw->maxcol && (rgb_mask >>= (unsigned long)1) != 0);
2487     };
2488     break;
2489   default:
2490     maxcol = 0;
2491     break;
2492   };
2493 /*
2494  * Limit the number of colorcells to the size of the pgw->color.pixel[] array.
2495  */
2496   if(maxcol > pgw->maxcol)
2497     maxcol = pgw->maxcol;
2498 /*
2499  * Don't try to allocate anything if there are too few colors available.
2500  */
2501   if(maxcol < pgw->mincol) {
2502     ncol = 0;
2503   } else {
2504     unsigned long planes[1];
2505     unsigned int nplanes = 0;
2506 /*
2507  * Dynamic colormaps require one to allocate cells explicitly.
2508  * Allocate up to maxcol color cells.
2509  */
2510     switch(vi->class) {
2511     case PseudoColor:
2512     case GrayScale:
2513     case DirectColor:
2514 /*
2515  * See if we can get all of the colors requested.
2516  */
2517       if(XAllocColorCells(xw->display, cmap, False, planes, nplanes,
2518 			  pgw->color.pixel, (unsigned) maxcol)) {
2519 	ncol = maxcol;
2520 /*
2521  * If there aren't at least pgw->mincol color cells available, then
2522  * give up on this colormap.
2523  */
2524       } else if(!XAllocColorCells(xw->display, cmap, False, planes, nplanes,
2525 				  pgw->color.pixel, (unsigned) pgw->mincol)) {
2526 	ncol = 0;
2527       } else {
2528 /*
2529  * Since we were able to allocate pgw->mincol cells, we may be able to
2530  * allocate more. First discard the pgw->mincol cells, so that we can
2531  * try for a bigger number.
2532  */
2533 	XFreeColors(xw->display, cmap, pgw->color.pixel, (int) pgw->mincol,
2534 		    (unsigned long)0);
2535 /*
2536  * Since there is no direct method to determine the number of allocatable
2537  * color cells available in a colormap, perform a binary search for the
2538  * max number that can be allocated. Note that it is possible that another
2539  * client may allocate colors from the same colormap while we search. This
2540  * invalidates the result of the search and is the reason for the outer
2541  * while loop.
2542  */
2543 	ncol = 0;
2544 	do {
2545 	  int lo = pgw->mincol;
2546 	  int hi = maxcol;
2547 	  while(lo<=hi) {
2548 	    int mid = (lo+hi)/2;
2549 	    if(XAllocColorCells(xw->display, cmap, False, planes, nplanes,
2550 				pgw->color.pixel, (unsigned) mid)) {
2551 	      ncol = mid;
2552 	      lo = mid + 1;
2553 	      XFreeColors(xw->display, cmap, pgw->color.pixel, mid,
2554 			  (unsigned long)0);
2555 	    } else {
2556 	      hi = mid - 1;
2557 	    };
2558 	  };
2559 	} while(ncol >= pgw->mincol &&
2560 		!XAllocColorCells(xw->display, cmap, False, planes, nplanes,
2561 				  pgw->color.pixel, (unsigned) ncol));
2562       };
2563       break;
2564 /*
2565  * For static color maps, color-cell pixel indexes will be assigned later
2566  * with XAllocColor() in xw_set_rgb(). For now simply assign 0 to all
2567  * pixels.
2568  */
2569     case StaticColor:
2570     case TrueColor:
2571     case StaticGray:
2572       for(ncol=0; ncol<maxcol; ncol++)
2573 	pgw->color.pixel[ncol] = 0;
2574       ncol = maxcol;
2575       break;
2576     default:
2577       ncol = 0;
2578       break;
2579     };
2580   };
2581   return (ncol >= pgw->mincol) ? ncol : 0;
2582 }
2583 
2584 /*.......................................................................
2585  * Delete the color-cells of a colormap if pertinent and the colormap itself.
2586  *
2587  * Input:
2588  *  xw    XWServer *  The PGPLOT /xw server descriptor.
2589  *  pgw      PGwin *  The PGPLOT window descriptor.
2590  *  vi XVisualInfo *  The info descriptor of the visual containing the colormap.
2591  *  cmap  Colormap    The colormap ID to be deleted.
2592  *  ncol       int    The number of color cells allocated.
2593  *                    If <= 0 cell de-allocation will not be performed.
2594  * Output:
2595  *  return     int    0.
2596  */
2597 #ifdef __STDC__
xw_del_Colormap(XWServer * xw,PGwin * pgw,XVisualInfo * vi,Colormap cmap,int ncol)2598 static int xw_del_Colormap(XWServer *xw, PGwin *pgw, XVisualInfo *vi,
2599 			   Colormap cmap, int ncol)
2600 #else
2601 static int xw_del_Colormap(xw, pgw, vi, cmap, ncol)
2602      XWServer *xw; PGwin *pgw; XVisualInfo *vi; Colormap cmap; int ncol;
2603 #endif
2604 {
2605 /*
2606  * Is there a colormap to be deleted?
2607  */
2608   if(cmap != None) {
2609 /*
2610  * Delete colorcells if necessary.
2611  */
2612     switch(vi->class) {
2613     case PseudoColor:
2614     case GrayScale:
2615     case DirectColor:
2616       if(ncol > 0)
2617 	XFreeColors(xw->display, cmap, pgw->color.pixel, ncol,(unsigned long)0);
2618       break;
2619     };
2620 /*
2621  * Delete the colormap if necessary.
2622  */
2623     if(cmap != DefaultColormap(xw->display, pgw->screen))
2624       XFreeColormap(xw->display, cmap);
2625   };
2626   return 0;
2627 }
2628 
2629 /*.......................................................................
2630  * Prepare an existing PGPLOT window for active duty with a new PGPLOT
2631  * client. This involves installing the window on the active window list,
2632  * associating it with the new client, and arranging to detect pertinent
2633  * events on the client and PGPLOT window.
2634  *
2635  *
2636  * Input:
2637  *  xw     XWServer *  The PGPLOT /xw server descriptor.
2638  *  pgw       PGwin *  The PGPLOT window descriptor.
2639  *  client   Window    The client being assigned to this window.
2640  *  protocol    int    The client/server communication protocol to use.
2641  * Output:
2642  *  return     int    0 - OK.
2643  */
2644 #ifdef __STDC__
xw_prep_window(XWServer * xw,PGwin * pgw,Window client,int protocol)2645 static int xw_prep_window(XWServer *xw, PGwin *pgw, Window client, int protocol)
2646 #else
2647 static int xw_prep_window(xw, pgw, client, protocol)
2648      XWServer *xw; PGwin *pgw; Window client; int protocol;
2649 #endif
2650 {
2651 /*
2652  * Associate the window with the new client.
2653  */
2654   pgw->client = client;
2655   pgw->protocol = protocol;
2656   pgw->mapped = 0;
2657 /*
2658  * Select the events that we want to detect on the client's communication
2659  * window. Bracket the call with xw_sync_error() calls to determine
2660  * whether it generates any errors. An error here would mean that
2661  * the client communication window ID was invalid. Note that the
2662  * second xw_sync_error() call also has the effect of flushing the
2663  * event mask to the display so that hereafter if the window id becomes
2664  * invalid we will be informed of it through a DestroyNotify event.
2665  */
2666   xw_sync_error(xw);
2667   XSelectInput(xw->display, pgw->client, (long)
2668 	       (StructureNotifyMask|PropertyChangeMask));
2669   if(xw_sync_error(xw)) {
2670     fprintf(stderr,
2671       "%s: Failed to select events on client communication window (0x%lx).\n",
2672 	    PGXWIN_SERVER, (unsigned long) pgw->client);
2673     return 1;
2674   };
2675 /*
2676  * Install the window in the active list.
2677  */
2678   add_PGwin(&xw->active_list, 1, pgw);
2679   return 0;
2680 }
2681 
2682 /*.......................................................................
2683  * Send data to a client by placing data in the client's xw->client_data
2684  * property.
2685  *
2686  * Input:
2687  *  xw        XWServer * The PGPLOT /xw server descriptor.
2688  *  pgw          PGwin * The PGPLOT window to send to.
2689  *  data unsigned char * The data to be sent, cast to (char *).
2690  *  form           int   The format for the property. Recognised values and
2691  *                       the data types used to send them in data[] are:
2692  *                         XW_CHAR_PROP  -  (char)
2693  *                         XW_SHORT_PROP -  (short)
2694  *                         XW_LONG_PROP  -  (long)
2695  *  n    unsigned long   The number of items to be sent, in multiples of
2696  *                       'size'.
2697  *  type          Atom   The output property type (eg. XA_INTEGER).
2698  * Output:
2699  *  return unsigned long The number of items sent==n, or 0 on error.
2700  */
2701 #ifdef __STDC__
xw_send_data(XWServer * xw,PGwin * pgw,unsigned char * data,int form,unsigned long n,Atom type)2702 static unsigned long xw_send_data(XWServer *xw, PGwin *pgw, unsigned char *data,
2703 				  int form, unsigned long n, Atom type)
2704 #else
2705 static unsigned long xw_send_data(xw, pgw, data, form, n, type)
2706      XWServer *xw; PGwin *pgw; unsigned char *data; int form; unsigned long n;
2707      Atom type;
2708 #endif
2709 {
2710   XEvent event;         /* Used to check for property-notify events */
2711   long max_item;        /* Max number of items transfereable in one go */
2712   long ndone;           /* The number of items sent so far */
2713   long nnew;            /* The number of items sent in the latest iteration */
2714   unsigned long size;   /* Size of property data element */
2715   int waserr=0;         /* True after an error */
2716 /*
2717  * The property data expected by XChangeProperty is arranged as an array of
2718  * (char) if form=8, (short) if form=16, and (long) if form=32,
2719  * irrespective of the sizes of these types. Get the size of one such
2720  * element in bytes.
2721  */
2722   switch(form) {
2723   case XW_CHAR_PROP:
2724     size = sizeof(char);
2725     break;
2726   case XW_SHORT_PROP:
2727     size = sizeof(short);
2728     break;
2729   case XW_LONG_PROP:
2730     size = sizeof(long);
2731     break;
2732   default:
2733     fprintf(stderr, "%s: Unknown property format: %d\n", PGXWIN_SERVER, form);
2734     return 0;
2735     break;
2736   };
2737 /*
2738  * Determine the current maximum number of items that can be transfered
2739  * in one go. (Note that the units of XMaxRequestSize are mutliples of
2740  * 4 bytes).
2741  */
2742   max_item = (4*XMaxRequestSize(xw->display))/size;
2743 /*
2744  * Send the data in one or more chunks of up to max_item items.
2745  */
2746   for(ndone=0; !waserr && ndone<n; ndone+=nnew) {
2747 /*
2748  * How many complete elements can be sent this time around?
2749  */
2750     nnew = (n-ndone > max_item) ? max_item : (n-ndone);
2751 /*
2752  * Place the latest set of nnew items in the client's data property.
2753  */
2754     XChangeProperty(xw->display, pgw->client, xw->client_data, type, form,
2755 		    PropModeReplace, data+ndone, (int)nnew);
2756     XFlush(xw->display);
2757 /*
2758  * Wait for the property to be deleted before sending more data.
2759  */
2760     do {
2761       XWindowEvent(xw->display, pgw->client, (long)
2762 		   (StructureNotifyMask|PropertyChangeMask), &event);
2763 /*
2764  * If the client window is destroyed, rather than blocking forever waiting
2765  * for a property notify event, put the event back to be handled by
2766  * xw_event_loop(), cleanup and return the error status.
2767  */
2768       if(event.type == DestroyNotify) {
2769 	XPutBackEvent(xw->display, &event);
2770 	return 0;
2771       };
2772     } while(!waserr && !(event.type == PropertyNotify &&
2773 			 event.xproperty.window == pgw->client &&
2774 			 event.xproperty.atom   == xw->client_data &&
2775 			 event.xproperty.state  == PropertyDelete));
2776   };
2777 /*
2778  * Terminate the transaction by sending a zero-length property value.
2779  */
2780   XChangeProperty(xw->display, pgw->client, xw->client_data, type, form,
2781 		  PropModeReplace, data, 0);
2782   XFlush(xw->display);
2783   return ndone;
2784 }
2785 
2786 /*.......................................................................
2787  * Create two cursors for use by clients. One cursor is for use when
2788  * cursor input is expected, and the other for when it is not expected.
2789  * Also create a cursor for use by the server, to show when a window
2790  * is unassigned to any client.
2791  *
2792  *  xw    XWServer * The PGPLOT /xw server descriptor.
2793  *  usecolor   int   0 - Create a black and white cursor.
2794  *                   1 - Create a color cursor.
2795  * Input/Output:
2796  *  curs  XWCursor * The cursor container to be filled.
2797  * Output:
2798  *  return     int   0 - OK.
2799  *                   1 - Error.
2800  */
2801 #ifdef __STDC__
xw_new_cursors(XWServer * xw,int usecolor,XWCursor * curs)2802 static int xw_new_cursors(XWServer *xw, int usecolor, XWCursor *curs)
2803 #else
2804 static int xw_new_cursors(xw, usecolor, curs)
2805      XWServer *xw; int usecolor; XWCursor *curs;
2806 #endif
2807 {
2808   XColor bg,fg;   /* Background and foreground colors */
2809 /*
2810  * Create the new cursors.
2811  */
2812   curs->norm = XCreateFontCursor(xw->display, XC_spider);
2813   curs->live = XCreateFontCursor(xw->display, XC_crosshair);
2814   curs->idle = XCreateFontCursor(xw->display, XC_pirate);
2815   if(curs->norm==None || curs->live==None || curs->idle==None) {
2816     fprintf(stderr, "%s: Error creating cursor.\n", PGXWIN_SERVER);
2817     return 1;
2818   };
2819 /*
2820  * Initialize the common parts of the color descriptors.
2821  */
2822   bg.pixel = fg.pixel = 0;
2823   bg.flags = fg.flags = DoRed | DoGreen | DoBlue;
2824   bg.pad = fg.pad = 0;
2825 /*
2826  * A black background will be used for all cursors.
2827  */
2828   bg.red = bg.green = bg.blue = 0;
2829 /*
2830  * Give the normal cursor a yellow foreground color.
2831  */
2832   fg.red   = fg.green = COLORMULT;
2833   fg.blue  = usecolor ? 0 : COLORMULT;
2834   XRecolorCursor(xw->display, curs->norm, &fg, &bg);
2835 /*
2836  * Give the active cursor a red foreground color.
2837  */
2838   fg.red   = COLORMULT;
2839   fg.green = fg.blue = usecolor ? 0:COLORMULT;
2840   XRecolorCursor(xw->display, curs->live, &fg, &bg);
2841 /*
2842  * Give the idle cursor a white foreground color.
2843  */
2844   fg.red = fg.green = fg.blue = COLORMULT;
2845   XRecolorCursor(xw->display, curs->idle, &fg, &bg);
2846   return 0;
2847 }
2848 
2849 /*.......................................................................
2850  * Delete cursors created by xw_new_cursors().
2851  *
2852  *  xw    XWServer * The PGPLOT /xw server descriptor.
2853  *  curs  XWCursor * The cursor container to be emptied.
2854  * Output:
2855  *  return     int   0 - OK.
2856  */
2857 #ifdef __STDC__
xw_del_cursors(XWServer * xw,XWCursor * curs)2858 static int xw_del_cursors(XWServer *xw, XWCursor *curs)
2859 #else
2860 static int xw_del_cursors(xw, curs)
2861      XWServer *xw; XWCursor *curs;
2862 #endif
2863 {
2864   if(curs->norm != None)
2865     XFreeCursor(xw->display, curs->norm);
2866   curs->norm = None;
2867   if(curs->live != None)
2868     XFreeCursor(xw->display, curs->live);
2869   curs->live = None;
2870   if(curs->idle != None)
2871     XFreeCursor(xw->display, curs->idle);
2872   curs->idle = None;
2873   return 0;
2874 }
2875 
2876 /*.......................................................................
2877  * Initialize a new cursor container to be empty. This must be called
2878  * before xw_new_cursors or xw_del_cursors so that it is clear which
2879  * cursors have been created and need to be deleted.
2880  *
2881  *  xw    XWServer * The PGPLOT /xw server descriptor.
2882  *  curs  XWCursor * The cursor container to be initialized.
2883  * Output:
2884  *  return     int   0 - OK.
2885  */
2886 #ifdef __STDC__
xw_ini_cursors(XWServer * xw,XWCursor * curs)2887 static int xw_ini_cursors(XWServer *xw, XWCursor *curs)
2888 #else
2889 static int xw_ini_cursors(xw, curs)
2890      XWServer *xw; XWCursor *curs;
2891 #endif
2892 {
2893   curs->norm = None;
2894   curs->live = None;
2895   curs->idle = None;
2896   return 0;
2897 }
2898 
2899 /*.......................................................................
2900  * Return a dynamically allocated visual info structure for a given
2901  * visual. This is simply a more convenient interface to XGetVisualInfo()
2902  * and XVisualIDFromVisual().
2903  *
2904  * Input:
2905  *  display    Display *   The display connection to which the visual
2906  *                         belongs.
2907  *  screen         int     The screen to which the visual belongs.
2908  *  visual      Visual *   The visual for which information is required.
2909  * Output:
2910  *  return XVisualInfo *   The required information descriptor, or NULL
2911  *                         on error.
2912  */
2913 #ifdef __STDC__
xw_visual_info(Display * display,int screen,Visual * visual)2914 static XVisualInfo *xw_visual_info(Display *display, int screen, Visual *visual)
2915 #else
2916 static XVisualInfo *xw_visual_info(display, screen, visual)
2917      Display *display; int screen; Visual *visual;
2918 #endif
2919 {
2920   XVisualInfo *vi=NULL;  /* The return descriptor */
2921   XVisualInfo template;  /* The search template */
2922   int nret = 0;          /* The number of descriptors returned */
2923 /*
2924  * Using the visual ID and the screen should unambiguously select the
2925  * information for the specified visual.
2926  */
2927   template.visualid = XVisualIDFromVisual(visual);
2928   template.screen = screen;
2929   vi = XGetVisualInfo(display, (long)(VisualIDMask | VisualScreenMask),
2930 		      &template, &nret);
2931   if(vi == NULL || nret < 1) {
2932     fprintf(stderr,
2933       "%s: Error getting visual information for visual ID 0x%lx, screen %d.\n",
2934       PGXWIN_SERVER, (unsigned long)template.visualid, screen);
2935     vi = NULL;
2936   };
2937   return vi;
2938 }
2939 
2940 /*.......................................................................
2941  * Get X-resource configurable PGPLOT window attributes for a new window.
2942  *
2943  * Input:
2944  *  display
2945  */
2946 #ifdef __STDC__
xw_get_config(XWServer * xw,PGwin * pgw)2947 static int xw_get_config(XWServer *xw, PGwin *pgw)
2948 #else
2949 static int xw_get_config(xw, pgw)
2950      XWServer *xw; PGwin *pgw;
2951 #endif
2952 {
2953   char *def = NULL;  /* X resource value */
2954   XWQuarks *qrk = &xw->quarks;
2955 /*
2956  * Initialize with server resource defaults.
2957  */
2958   pgw->acceptquit = 0;
2959   pgw->iconize = 0;
2960   pgw->mincol = NCOLORS;
2961   pgw->maxcol = XW_DEF_COLORS<XW_MAX_COLORS ? XW_DEF_COLORS:XW_MAX_COLORS;
2962   pgw->crosshair = 0;
2963   pgw->visual_class = -1;
2964 /*
2965  * Override current defaults.
2966  *
2967  * Record whether WM_DELETE_WINDOW actions are to be accepted on
2968  * active windows.
2969  */
2970   if((def = xw_get_default(xw, pgw->id, &qrk->acceptquit)))
2971     pgw->acceptquit = xw_parse_bool(def, False) == True;
2972 /*
2973  * Record whether persistent windows should be iconized when inactive.
2974  */
2975   if((def = xw_get_default(xw, pgw->id, &qrk->iconize)))
2976     pgw->iconize = xw_parse_bool(def, False) == True;
2977 /*
2978  * Override the default minimum number of colors per colormap.
2979  */
2980   if((def = xw_get_default(xw, pgw->id, &qrk->mincolors))) {
2981     pgw->mincol = atoi(def);
2982     if(pgw->mincol < XW_MIN_COLORS)
2983       pgw->mincol = XW_MIN_COLORS;
2984     if(pgw->mincol > XW_MAX_COLORS)
2985       pgw->mincol = XW_MAX_COLORS;
2986   };
2987 /*
2988  * Override the default max number of colors per window.
2989  */
2990   if((def = xw_get_default(xw, pgw->id, &qrk->maxcolors))) {
2991     pgw->maxcol = atoi(def);
2992     if(pgw->maxcol < XW_MIN_COLORS)
2993       pgw->maxcol = XW_MIN_COLORS;
2994     if(pgw->maxcol > XW_MAX_COLORS)
2995       pgw->maxcol = XW_MAX_COLORS;
2996   };
2997 /*
2998  * Ensure that maxcol >= mincol.
2999  */
3000   if(pgw->mincol > pgw->maxcol)
3001     pgw->maxcol = pgw->mincol;
3002 /*
3003  * See if a crosshair cursor should be used.
3004  */
3005   if((def = xw_get_default(xw, pgw->id, &qrk->crosshair)))
3006     pgw->crosshair = xw_parse_bool(def, False) == True;
3007 /*
3008  * See what the default visual type should be.
3009  */
3010   if((def = xw_get_default(xw, pgw->id, &qrk->visual)))
3011     pgw->visual_class = xw_parse_visual(def);
3012   return 0;
3013 }
3014 
3015 /*.......................................................................
3016  * Lookup a resource value from the X resource database.
3017  * This function must not be called before xw_get_xrdb() or xw_get_quarks().
3018  *
3019  * Input:
3020  *  xw        XWServer *   The server descriptor.
3021  *  window_id      int     The numeric ID of the window to look up a
3022  *                         resource for, or 0 for a server resource.
3023  *  pair       XWQPair *   Name/class quark pair of the resource to be
3024  *                         looked up.
3025  * Output:
3026  *  return        char *   The resource value, or NULL if no value is
3027  *                         available. This is a pointer to an internal
3028  *                         static buffer.
3029  */
3030 #ifdef __STDC__
xw_get_default(XWServer * xw,int window_id,XWQPair * pair)3031 static char *xw_get_default(XWServer *xw, int window_id, XWQPair *pair)
3032 #else
3033 static char *xw_get_default(xw, window_id, pair)
3034      XWServer *xw; int window_id; XWQPair *pair;
3035 #endif
3036 {
3037   static char resource[80];   /* Buffer for returned value */
3038   XrmName win_name;           /* Window specification quark */
3039   XrmName name_list[4];       /* List of resource name components */
3040   XrmClass class_list[4];     /* List of resource class components */
3041   XrmRepresentation rep_type; /* Returned representation of resource */
3042   XrmValue value;             /* Resource value */
3043   int have_value = 0;         /* True once a resource value has been acquired */
3044 /*
3045  * All resources share the initial program component.
3046  */
3047   name_list[0]  = xw->quarks.prog.name;
3048   class_list[0] = xw->quarks.prog.class;
3049 /*
3050  * If a specific window has been specified determine the window component
3051  * name to use and convert it to a quark.
3052  */
3053   if(window_id) {
3054     sprintf(resource, "win%d", window_id);
3055     win_name = XrmStringToName(resource);
3056     name_list[1]  = win_name;
3057     name_list[2]  = pair->name;
3058     name_list[3]  = NULLQUARK;
3059     class_list[1] = xw->quarks.win_class;
3060     class_list[2] = pair->class;
3061     class_list[3] = NULLQUARK;
3062     have_value = XrmQGetResource(xw->xrdb, name_list, class_list, &rep_type,
3063 			&value)==True && value.size + 1 <= sizeof(resource);
3064 /*
3065  * For compatibility with the first version of pgxwin_server, allow
3066  * pgxwin.resource_name to be an alias for pgxwin.Win.resource_name.
3067  */
3068     if(!have_value) {
3069       name_list[1]  = pair->name;
3070       name_list[2]  = NULLQUARK;
3071       class_list[1] = pair->class;
3072       class_list[2] = NULLQUARK;
3073       have_value = XrmQGetResource(xw->xrdb, name_list, class_list, &rep_type,
3074 			  &value)==True && value.size + 1 <= sizeof(resource);
3075     };
3076 /*
3077  * Get server resource.
3078  */
3079   } else {
3080     name_list[1]  = xw->quarks.server.name;
3081     name_list[2]  = pair->name;
3082     name_list[3]  = NULLQUARK;
3083     class_list[1] = xw->quarks.server.class;
3084     class_list[2] = pair->class;
3085     class_list[3] = NULLQUARK;
3086     have_value = XrmQGetResource(xw->xrdb, name_list, class_list, &rep_type,
3087 			&value)==True && value.size + 1 <= sizeof(resource);
3088   };
3089 /*
3090  * Return a '\0' terminated copy of the resource value, or NULL if not
3091  * available.
3092  */
3093   if(have_value) {
3094     strncpy(resource, (char *)value.addr, (int)value.size);
3095     resource[(int)value.size] = '\0';
3096     return resource;
3097   };
3098   return NULL;
3099 }
3100 
3101 /*.......................................................................
3102  * Create the X resource database.
3103  *
3104  * Input:
3105  *  display    Display *  The display connection over which to check for the
3106  *                        RESOURCE_MANAGER root window property.
3107  *  cmd_db XrmDatabase    The command line resource database.
3108  * Output:
3109  *  return XrmDatabase    The initialized database.
3110  */
3111 #ifdef __STDC__
xw_get_xrdb(Display * display,XrmDatabase cmd_db)3112 static XrmDatabase xw_get_xrdb(Display *display, XrmDatabase cmd_db)
3113 #else
3114 static XrmDatabase xw_get_xrdb(display, cmd_db)
3115      Display *display; XrmDatabase cmd_db;
3116 #endif
3117 {
3118   XrmDatabase user_db = NULL;  /* User specified database */
3119   XrmDatabase env_db = NULL;   /* Environment-specific database */
3120 /*
3121  * Initialize the database manager.
3122  */
3123   XrmInitialize();
3124 /*
3125  * Get the XA_RESOURCE_MANAGER property from the root window.
3126  */
3127   if(XResourceManagerString(display)) {
3128     user_db = XrmGetStringDatabase(XResourceManagerString(display));
3129   } else {
3130 /*
3131  * If there was nothing on the root window, attempt to read the users
3132  * .Xdefaults file.
3133  */
3134 #ifdef VMS
3135     user_db = XrmGetFileDatabase("DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT");
3136 #else
3137     char *dir = xw_home_dir();
3138     char *sep = "/";
3139     char *file = ".Xdefaults";
3140     if(dir) {
3141       char *path = (char *) malloc(sizeof(char) *
3142 				   (strlen(dir)+strlen(sep)+strlen(file) + 1));
3143       if(path) {
3144 	sprintf(path, "%s%s%s", dir, sep, file);
3145 	user_db = XrmGetFileDatabase(path);
3146 	free(path);
3147       };
3148     };
3149 #endif
3150   };
3151 /*
3152  * See if an environment-specific database exists.
3153  */
3154   {
3155     char *env = getenv("XENVIRONMENT");
3156     if(env)
3157       env_db = XrmGetFileDatabase(env);
3158   };
3159 /*
3160  * Merge the databases.
3161  */
3162   XrmMergeDatabases(env_db, &user_db);
3163 /*
3164  * Override selected resources from the command-line resource database.
3165  */
3166   XrmMergeDatabases(cmd_db, &user_db);
3167   return user_db;
3168 }
3169 
3170 /*.......................................................................
3171  * Get the user's home directory.
3172  *
3173  * Output:
3174  *  return   char *  A statically allocated string containing the user's
3175  *                   home directory name, or NULL if not available.
3176  */
3177 #ifdef __STDC__
xw_home_dir(void)3178 static char *xw_home_dir(void)
3179 #else
3180 static char *xw_home_dir()
3181 #endif
3182 {
3183   char *home = NULL;
3184 #ifdef VMS
3185   home = "SYS$LOGIN";
3186 #else
3187   if((home=getenv("HOME")) == NULL) {
3188     struct passwd *pwd = getpwuid(getuid());
3189     if(pwd)
3190       home = pwd->pw_dir;
3191   };
3192 #endif
3193   return home;
3194 }
3195 
3196 /*.......................................................................
3197  * Record quarks for frequently used resource-database components, in
3198  * xw->quarks. This must be called before xw_get_config().
3199  *
3200  * Input:
3201  *  xw     XWServer *  The server who's quark database is to be initialized.
3202  * Output:
3203  *  return      int    0 - OK.
3204  *                     1 - Error.
3205  */
3206 #ifdef __STDC__
xw_get_quarks(XWServer * xw)3207 static int xw_get_quarks(XWServer *xw)
3208 #else
3209 static int xw_get_quarks(xw)
3210      XWServer *xw;
3211 #endif
3212 {
3213   XWQuarks *q = &xw->quarks;
3214   q->prog.name       = XrmStringToName("pgxwin");
3215   q->prog.class      = XrmStringToClass("Pgxwin");
3216   q->display.name    = XrmStringToName("display");
3217   q->display.class   = XrmStringToClass("Display");
3218   q->server.name     = XrmStringToName("server");
3219   q->server.class    = XrmStringToClass("Server");
3220   q->geom.name       = XrmStringToName("geometry");
3221   q->geom.class      = XrmStringToClass("Geometry");
3222   q->iconize.name    = XrmStringToName("iconize");
3223   q->iconize.class   = XrmStringToClass("Iconize");
3224   q->acceptquit.name = XrmStringToName("acceptQuit");
3225   q->acceptquit.class= XrmStringToClass("AcceptQuit");
3226   q->mincolors.name  = XrmStringToName("minColors");
3227   q->mincolors.class = XrmStringToClass("MinColors");
3228   q->maxcolors.name  = XrmStringToName("maxColors");
3229   q->maxcolors.class = XrmStringToClass("MaxColors");
3230   q->visual.name     = XrmStringToName("visual");
3231   q->visual.class    = XrmStringToClass("Visual");
3232   q->crosshair.name  = XrmStringToName("crosshair");
3233   q->crosshair.class = XrmStringToClass("Crosshair");
3234   q->visible.name    = XrmStringToName("visible");
3235   q->visible.class   = XrmStringToClass("Visible");
3236   q->icongeom.name    = XrmStringToName("iconGeometry");
3237   q->icongeom.class   = XrmStringToClass("IconGeometry");
3238   q->win_class = XrmStringToClass("Win");
3239   return 0;
3240 }
3241 
3242 /*.......................................................................
3243  * Specify window state hints to the window manager.
3244  *
3245  * Input:
3246  *  xw    XWServer *  The server descriptor.
3247  *  screen     int    The screen on which the window resides.
3248  *  window  Window    The window to which the hints apply.
3249  *  id         int    The PGwin window number, or 0 for the server window.
3250  * Output:
3251  *  return     int    0 - OK.
3252  *                    1 - Error.
3253  */
3254 #ifdef __STDC__
xw_setwmhints(XWServer * xw,int screen,Window window,int id)3255 static int xw_setwmhints(XWServer *xw, int screen, Window window, int id)
3256 #else
3257 static int xw_setwmhints(xw, screen, window, id)
3258      XWServer *xw; int screen; Window window; int id;
3259 #endif
3260 {
3261   XWMHints *hints;
3262   char *icongeom;         /* Icon geometry resource value */
3263 /*
3264  * Allocate the hints structure as recommended.
3265  */
3266   hints = XAllocWMHints();
3267 /*
3268  * Start with no hints specified.
3269  */
3270   if(hints) {
3271     hints->flags = 0;
3272 /*
3273  * Server-specific hints.
3274  */
3275     if(id==0) {
3276       hints->flags |= StateHint;  /* The server window should start iconified */
3277       hints->initial_state = IconicState;
3278 /*
3279  * PGPLOT window specific hints.
3280  */
3281     } else {
3282       hints->flags |= InputHint;   /* Register interest in keyboard input */
3283       hints->input = True;
3284     };
3285 /*
3286  * See if a geometry has been specified for the window icon.
3287  */
3288     icongeom = xw_get_default(xw, id, &xw->quarks.icongeom);
3289     if(icongeom) {
3290       int x,y;
3291       unsigned int width;
3292       unsigned int height;
3293       int mask = XParseGeometry(icongeom, &x, &y, &width, &height);
3294       hints->flags |= IconPositionHint;
3295       if(mask & XValue)
3296 	x = (mask & XNegative) ? DisplayWidth(xw->display, screen) - x : x;
3297       else
3298 	x = 0;
3299       if(mask & YValue)
3300 	y = (mask & YNegative) ? DisplayHeight(xw->display, screen) - y : y;
3301       else
3302 	y = 0;
3303       hints->icon_x = (mask & XValue) ? x:0;
3304       hints->icon_y = (mask & YValue) ? y:0;
3305     };
3306 /*
3307  * Install the hints if any were provided.
3308  */
3309     if(hints->flags)
3310       XSetWMHints(xw->display, window, hints);
3311     XFree((char *)hints);
3312   } else {
3313     fprintf(stderr, "%s: Insufficient memory for position and state hints.\n",
3314 	    PGXWIN_SERVER);
3315     return 1;
3316   };
3317   return 0;
3318 }
3319 
3320 /*.......................................................................
3321  * Set the window name and icon names for a window.
3322  *
3323  * Input:
3324  *  xw      XWServer *   The server descriptor.
3325  *  window    Window     The window to name.
3326  *  w_name      char *   The name for the window.
3327  *  i_name      char *   The name for the icon.
3328  * Output:
3329  *  return       int     0 - OK.
3330  *                       1 - Error.
3331  */
3332 #ifdef __STDC__
xw_name_window(XWServer * xw,Window window,char * w_name,char * i_name)3333 static int xw_name_window(XWServer *xw, Window window, char *w_name,
3334 			  char *i_name)
3335 #else
3336 static int xw_name_window(xw, window, w_name, i_name)
3337      XWServer *xw; Window window; char *w_name; char *i_name;
3338 #endif
3339 {
3340 /*
3341  * Get text-property version of the window name and assign it to the window.
3342  */
3343   {
3344     XTextProperty window_name;
3345     if(XStringListToTextProperty(&w_name, 1, &window_name) == 0) {
3346       fprintf(stderr, "%s: Error allocating window name.\n", PGXWIN_SERVER);
3347       return 1;
3348     };
3349     XSetWMName(xw->display, window, &window_name);
3350     XFree((char *)window_name.value);
3351   };
3352 /*
3353  * Get text-property versions of the icon name and assign it to the window.
3354  */
3355   {
3356     XTextProperty icon_name;
3357     if(XStringListToTextProperty(&i_name, 1, &icon_name) == 0) {
3358       fprintf(stderr, "%s: Error allocating icon name.\n", PGXWIN_SERVER);
3359       return 1;
3360     };
3361     XSetWMIconName(xw->display, window, &icon_name);
3362     XFree((char *)icon_name.value);
3363   };
3364   return 0;
3365 }
3366 
3367 /*.......................................................................
3368  * Acquire an up to date count of the number of error events generated
3369  * from all previous Xlib calls since the last time that this function
3370  * was called. This involves calling XSync() to ensure that all pending
3371  * requests have been processed, and clears the xw_handle_error() error
3372  * counter before returning.
3373  *
3374  * Thus, to determine whether a given function call causes any errors,
3375  * bracket it with two calls to xw_sync_error().
3376  *
3377  * Input:
3378  *  xw     XWServer * The PGPLOT server descriptor.
3379  * Output:
3380  *  return      int   The number of error events.
3381  */
3382 #ifdef __STDC__
xw_sync_error(XWServer * xw)3383 static int xw_sync_error(XWServer *xw)
3384 #else
3385 static int xw_sync_error(xw)
3386      XWServer *xw;
3387 #endif
3388 {
3389 /*
3390  * Force queued X requests to the server and wait for them to be processed.
3391  */
3392   XSync(xw->display, False);
3393 /*
3394  * Ask the error handler for the current count of error events and to
3395  * clear its error counter by sending it a NULL XErrorEvent pointer.
3396  */
3397   return xw_handle_error(xw->display, (XErrorEvent *) 0);
3398 }
3399