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