Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/gdevxini.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gdevxini.c,v 1.14 2004/05/26 04:10:58 dan Exp $ */
18
/* X Windows driver initialization/finalization */
19
#include "memory_.h"
20
#include "x_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gxdevice.h"
24
#include "gxdevmem.h"
25
#include "gsparamx.h"
26
#include "gdevbbox.h"
27
#include "gdevx.h"
28
 
29
extern char *getenv(const char *);
30
 
31
extern const gx_device_bbox gs_bbox_device;
32
extern const gx_device_X gs_x11_device;
33
 
34
extern const gx_device_bbox_procs_t gdev_x_box_procs;
35
 
36
/* Define constants for orientation from ghostview */
37
/* Number represents clockwise rotation of the paper in degrees */
38
typedef enum {
39
    Portrait = 0,		/* Normal portrait orientation */
40
    Landscape = 90,		/* Normal landscape orientation */
41
    Upsidedown = 180,		/* Don't think this will be used much */
42
    Seascape = 270		/* Landscape rotated the wrong way */
43
} orientation;
44
 
45
/* GC descriptors */
46
private_st_x11fontmap();
47
 
48
/* ---------------- Opening/initialization ---------------- */
49
 
50
/* Forward references */
51
private void gdev_x_setup_fontmap(gx_device_X *);
52
 
53
/* Catch the alloc error when there is not enough resources for the
54
 * backing pixmap.  Automatically shut off backing pixmap and let the
55
 * user know when this happens.
56
 *
57
 * Because the X API was designed without adequate thought to reentrancy,
58
 * these variables must be allocated statically.  We do not see how this
59
 * code can work reliably in the presence of multi-threading.
60
 */
61
private struct xv_ {
62
    Boolean alloc_error;
63
    XErrorHandler orighandler;
64
    XErrorHandler oldhandler;
65
} x_error_handler;
66
 
67
private int
68
x_catch_alloc(Display * dpy, XErrorEvent * err)
69
{
70
    if (err->error_code == BadAlloc)
71
	x_error_handler.alloc_error = True;
72
    if (x_error_handler.alloc_error)
73
	return 0;
74
    return x_error_handler.oldhandler(dpy, err);
75
}
76
 
77
int
78
x_catch_free_colors(Display * dpy, XErrorEvent * err)
79
{
80
    if (err->request_code == X_FreeColors)
81
	return 0;
82
    return x_error_handler.orighandler(dpy, err);
83
}
84
 
85
/* Open the X device */
86
int
87
gdev_x_open(gx_device_X * xdev)
88
{
89
    XSizeHints sizehints;
90
    char *window_id;
91
    XEvent event;
92
    XVisualInfo xvinfo;
93
    int nitems;
94
    XtAppContext app_con;
95
    Widget toplevel;
96
    Display *dpy;
97
    XColor xc;
98
    int zero = 0;
99
    int xid_height, xid_width;
100
    int code;
101
 
102
#ifdef DEBUG
103
# ifdef have_Xdebug
104
    if (gs_debug['X']) {
105
	extern int _Xdebug;
106
 
107
	_Xdebug = 1;
108
    }
109
# endif
110
#endif
111
    if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
112
	char *dispname = getenv("DISPLAY");
113
 
114
	eprintf1("Cannot open X display `%s'.\n",
115
		 (dispname == NULL ? "(null)" : dispname));
116
	return_error(gs_error_ioerror);
117
    }
118
    xdev->dest = 0;
119
    if ((window_id = getenv("GHOSTVIEW"))) {
120
	if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
121
				       &(xdev->win), &(xdev->dest)))) {
122
	    eprintf("Cannot get Window ID from ghostview.\n");
123
	    return_error(gs_error_ioerror);
124
	}
125
    }
126
    if (xdev->pwin != (Window) None) {	/* pick up the destination window parameters if specified */
127
	XWindowAttributes attrib;
128
 
129
	xdev->win = xdev->pwin;
130
	if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
131
	    xdev->scr = attrib.screen;
132
	    xvinfo.visual = attrib.visual;
133
	    xdev->cmap = attrib.colormap;
134
	    xid_width = attrib.width;
135
	    xid_height = attrib.height;
136
	} else {
137
	    /* No idea why we can't get the attributes, but */
138
	    /* we shouldn't let it lead to a failure below. */
139
	    xid_width = xid_height = 0;
140
	}
141
    } else if (xdev->ghostview) {
142
	XWindowAttributes attrib;
143
	Atom type;
144
	int format;
145
	unsigned long nitems, bytes_after;
146
	char *buf;
147
	Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);
148
 
149
	if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
150
	    xdev->scr = attrib.screen;
151
	    xvinfo.visual = attrib.visual;
152
	    xdev->cmap = attrib.colormap;
153
	    xdev->width = attrib.width;
154
	    xdev->height = attrib.height;
155
	}
156
	/* Delete property if explicit dest is given */
157
	if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
158
			       256, (xdev->dest != 0), XA_STRING,
159
			       &type, &format, &nitems, &bytes_after,
160
			       (unsigned char **)&buf) == 0 &&
161
	    type == XA_STRING) {
162
	    int llx, lly, urx, ury;
163
	    int left_margin = 0, bottom_margin = 0;
164
	    int right_margin = 0, top_margin = 0;
165
 
166
	    /* We declare page_orientation as an int so that we can */
167
	    /* use an int * to reference it for sscanf; compilers */
168
	    /* might be tempted to use less space to hold it if */
169
	    /* it were declared as an orientation. */
170
	    int /*orientation */ page_orientation;
171
	    float xppp, yppp;	/* pixels per point */
172
 
173
	    nitems = sscanf(buf,
174
			    "%ld %d %d %d %d %d %f %f %d %d %d %d",
175
			    &(xdev->bpixmap), &page_orientation,
176
			    &llx, &lly, &urx, &ury,
177
			    &(xdev->x_pixels_per_inch),
178
			    &(xdev->y_pixels_per_inch),
179
			    &left_margin, &bottom_margin,
180
			    &right_margin, &top_margin);
181
	    if (!(nitems == 8 || nitems == 12)) {
182
		eprintf("Cannot get ghostview property.\n");
183
		return_error(gs_error_ioerror);
184
	    }
185
	    if (xdev->dest && xdev->bpixmap) {
186
		eprintf("Both destination and backing pixmap specified.\n");
187
		return_error(gs_error_rangecheck);
188
	    }
189
	    if (xdev->dest) {
190
		Window root;
191
		int x, y;
192
		unsigned int width, height;
193
		unsigned int border_width, depth;
194
 
195
		if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
196
				 &width, &height, &border_width, &depth)) {
197
		    xdev->width = width;
198
		    xdev->height = height;
199
		}
200
	    }
201
	    xppp = xdev->x_pixels_per_inch / 72.0;
202
	    yppp = xdev->y_pixels_per_inch / 72.0;
203
	    switch (page_orientation) {
204
		case Portrait:
205
		    xdev->initial_matrix.xx = xppp;
206
		    xdev->initial_matrix.xy = 0.0;
207
		    xdev->initial_matrix.yx = 0.0;
208
		    xdev->initial_matrix.yy = -yppp;
209
		    xdev->initial_matrix.tx = -llx * xppp;
210
		    xdev->initial_matrix.ty = ury * yppp;
211
		    break;
212
		case Landscape:
213
		    xdev->initial_matrix.xx = 0.0;
214
		    xdev->initial_matrix.xy = yppp;
215
		    xdev->initial_matrix.yx = xppp;
216
		    xdev->initial_matrix.yy = 0.0;
217
		    xdev->initial_matrix.tx = -lly * xppp;
218
		    xdev->initial_matrix.ty = -llx * yppp;
219
		    break;
220
		case Upsidedown:
221
		    xdev->initial_matrix.xx = -xppp;
222
		    xdev->initial_matrix.xy = 0.0;
223
		    xdev->initial_matrix.yx = 0.0;
224
		    xdev->initial_matrix.yy = yppp;
225
		    xdev->initial_matrix.tx = urx * xppp;
226
		    xdev->initial_matrix.ty = -lly * yppp;
227
		    break;
228
		case Seascape:
229
		    xdev->initial_matrix.xx = 0.0;
230
		    xdev->initial_matrix.xy = -yppp;
231
		    xdev->initial_matrix.yx = -xppp;
232
		    xdev->initial_matrix.yy = 0.0;
233
		    xdev->initial_matrix.tx = ury * xppp;
234
		    xdev->initial_matrix.ty = urx * yppp;
235
		    break;
236
	    }
237
 
238
	    /* The following sets the imageable area according to the */
239
	    /* bounding box and margins sent by ghostview.            */
240
	    /* This code has been patched many times; its current state */
241
	    /* is per a recommendation by Tim Theisen on 4/28/95. */
242
 
243
	    xdev->ImagingBBox[0] = llx - left_margin;
244
	    xdev->ImagingBBox[1] = lly - bottom_margin;
245
	    xdev->ImagingBBox[2] = urx + right_margin;
246
	    xdev->ImagingBBox[3] = ury + top_margin;
247
	    xdev->ImagingBBox_set = true;
248
 
249
	} else if (xdev->pwin == (Window) None) {
250
	    eprintf("Cannot get ghostview property.\n");
251
	    return_error(gs_error_ioerror);
252
	}
253
    } else {
254
	Screen *scr = DefaultScreenOfDisplay(xdev->dpy);
255
 
256
	xdev->scr = scr;
257
	xvinfo.visual = DefaultVisualOfScreen(scr);
258
	xdev->cmap = DefaultColormapOfScreen(scr);
259
	if (xvinfo.visual->class != TrueColor) {
260
	    int scrno = DefaultScreen(xdev->dpy);
261
	    if ( XMatchVisualInfo(xdev->dpy, scrno, 24, TrueColor, &xvinfo) ||
262
		 XMatchVisualInfo(xdev->dpy, scrno, 32, TrueColor, &xvinfo) || 
263
		 XMatchVisualInfo(xdev->dpy, scrno, 16, TrueColor, &xvinfo) ||
264
		 XMatchVisualInfo(xdev->dpy, scrno, 15, TrueColor, &xvinfo)  ) {
265
		xdev->cmap = XCreateColormap (xdev->dpy, 
266
					      DefaultRootWindow(xdev->dpy),
267
					      xvinfo.visual, AllocNone ); 
268
	    }
269
	}
270
    }
271
    xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
272
    xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
273
    if (xdev->vinfo == NULL) {
274
	eprintf("Cannot get XVisualInfo.\n");
275
	return_error(gs_error_ioerror);
276
    }
277
    /* Buggy X servers may cause a Bad Access on XFreeColors. */
278
    x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);
279
 
280
    /* Get X Resources.  Use the toolkit for this. */
281
    XtToolkitInitialize();
282
    app_con = XtCreateApplicationContext();
283
    XtAppSetFallbackResources(app_con, gdev_x_fallback_resources);
284
    dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
285
			NULL, 0, &zero, NULL);
286
    toplevel = XtAppCreateShell(NULL, "Ghostscript",
287
				applicationShellWidgetClass, dpy, NULL, 0);
288
    XtGetApplicationResources(toplevel, (XtPointer) xdev,
289
			      gdev_x_resources, gdev_x_resource_count,
290
			      NULL, 0);
291
 
292
    /* Reserve foreground and background colors under the regular connection. */
293
    xc.pixel = xdev->foreground;
294
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
295
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
296
    xdev->foreground = xc.pixel;
297
    xc.pixel = xdev->background;
298
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
299
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
300
    xdev->background = xc.pixel;
301
 
302
    code = gdev_x_setup_colors(xdev);
303
    if (code < 0) {
304
	XCloseDisplay(xdev->dpy);
305
	return code;
306
    }
307
    /* Now that the color map is setup check if the device is separable. */
308
    check_device_separable((gx_device *)xdev);
309
 
310
    gdev_x_setup_fontmap(xdev);
311
 
312
    if (!xdev->ghostview) {
313
	XWMHints wm_hints;
314
	XSetWindowAttributes xswa;
315
	gx_device *dev = (gx_device *) xdev;
316
 
317
	/* Take care of resolution and paper size. */
318
	if (xdev->x_pixels_per_inch == FAKE_RES ||
319
	    xdev->y_pixels_per_inch == FAKE_RES) {
320
	    float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
321
	    float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
322
 
323
	    if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
324
		float dpi, xdpi, ydpi;
325
 
326
		xdpi = 25.4 * WidthOfScreen(xdev->scr) /
327
		    WidthMMOfScreen(xdev->scr);
328
		ydpi = 25.4 * HeightOfScreen(xdev->scr) /
329
		    HeightMMOfScreen(xdev->scr);
330
		dpi = min(xdpi, ydpi);
331
		/*
332
		 * Some X servers provide very large "virtual screens", and
333
		 * return the virtual screen size for Width/HeightMM but the
334
		 * physical size for Width/Height.  Attempt to detect and
335
		 * correct for this now.  This is a KLUDGE required because
336
		 * the X server provides no way to read the screen
337
		 * resolution directly.
338
		 */
339
		if (dpi < 30)
340
		    dpi = 75;	/* arbitrary */
341
		else {
342
		    while (xsize * dpi > WidthOfScreen(xdev->scr) - 32 ||
343
			   ysize * dpi > HeightOfScreen(xdev->scr) - 32)
344
			dpi *= 0.95;
345
		}
346
		xdev->x_pixels_per_inch = dpi;
347
		xdev->y_pixels_per_inch = dpi;
348
	    } else {
349
		xdev->x_pixels_per_inch = xdev->xResolution;
350
		xdev->y_pixels_per_inch = xdev->yResolution;
351
	    }
352
	    if (xdev->width > WidthOfScreen(xdev->scr)) {
353
		xdev->width = xsize * xdev->x_pixels_per_inch;
354
	    }
355
	    if (xdev->height > HeightOfScreen(xdev->scr)) {
356
		xdev->height = ysize * xdev->y_pixels_per_inch;
357
	    }
358
	    xdev->MediaSize[0] =
359
		(float)xdev->width / xdev->x_pixels_per_inch * 72;
360
	    xdev->MediaSize[1] =
361
		(float)xdev->height / xdev->y_pixels_per_inch * 72;
362
	}
363
	sizehints.x = 0;
364
	sizehints.y = 0;
365
	sizehints.width = xdev->width;
366
	sizehints.height = xdev->height;
367
	sizehints.flags = 0;
368
 
369
	if (xdev->geometry != NULL) {
370
	    /*
371
	     * Note that border_width must be set first.  We can't use
372
	     * scr, because that is a Screen*, and XWMGeometry wants
373
	     * the screen number.
374
	     */
375
	    char gstr[40];
376
	    int bitmask;
377
 
378
	    sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
379
		    sizehints.height, sizehints.x, sizehints.y);
380
	    bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
381
				  xdev->geometry, gstr, xdev->borderWidth,
382
				  &sizehints,
383
				  &sizehints.x, &sizehints.y,
384
				  &sizehints.width, &sizehints.height,
385
				  &sizehints.win_gravity);
386
 
387
	    if (bitmask & (XValue | YValue))
388
		sizehints.flags |= USPosition;
389
	}
390
	gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));
391
 
392
	if (xdev->pwin != (Window) None && xid_width != 0 && xid_height != 0) {
393
#if 0				/*************** */
394
 
395
	    /*
396
	     * The user who originally implemented the WindowID feature
397
	     * provided the following code to scale the displayed output
398
	     * to fit in the window.  We think this is a bad idea,
399
	     * since it doesn't track window resizing and is generally
400
	     * completely at odds with the way Ghostscript treats
401
	     * window or paper size in all other contexts.  We are
402
	     * leaving the code here in case someone decides that
403
	     * this really is the behavior they want.
404
	     */
405
 
406
	    /* Scale to fit in the window. */
407
	    xdev->initial_matrix.xx
408
		= xdev->initial_matrix.xx *
409
		(float)xid_width / (float)xdev->width;
410
	    xdev->initial_matrix.yy
411
		= xdev->initial_matrix.yy *
412
		(float)xid_height / (float)xdev->height;
413
 
414
#endif /*************** */
415
	    xdev->width = xid_width;
416
	    xdev->height = xid_height;
417
	    xdev->initial_matrix.ty = xdev->height;
418
	} else {		/* !xdev->pwin */
419
	    xswa.event_mask = ExposureMask;
420
	    xswa.background_pixel = xdev->background;
421
	    xswa.border_pixel = xdev->borderColor;
422
	    xswa.colormap = xdev->cmap;
423
	    xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
424
				      sizehints.x, sizehints.y,		/* upper left */
425
				      xdev->width, xdev->height,
426
				      xdev->borderWidth,
427
				      xdev->vinfo->depth,
428
				      InputOutput,	/* class        */
429
				      xdev->vinfo->visual,	/* visual */
430
				      CWEventMask | CWBackPixel |
431
				      CWBorderPixel | CWColormap,
432
				      &xswa);
433
	    XStoreName(xdev->dpy, xdev->win, "ghostscript");
434
	    XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
435
	    wm_hints.flags = InputHint;
436
	    wm_hints.input = False;
437
	    XSetWMHints(xdev->dpy, xdev->win, &wm_hints);	/* avoid input focus */
438
	}
439
    }
440
    /***
441
     *** According to Ricard Torres (torres@upf.es), we have to wait until here
442
     *** to close the toolkit connection, which we formerly did
443
     *** just after the calls on XAllocColor above.  I suspect that
444
     *** this will cause things to be left dangling if an error occurs
445
     *** anywhere in the above code, but I'm willing to let users
446
     *** fight over fixing it, since I have no idea what's right.
447
     ***/
448
 
449
    /* And close the toolkit connection. */
450
    XtDestroyWidget(toplevel);
451
    XtCloseDisplay(dpy);
452
    XtDestroyApplicationContext(app_con);
453
 
454
    xdev->ht.pixmap = (Pixmap) 0;
455
    xdev->ht.id = gx_no_bitmap_id;;
456
    xdev->fill_style = FillSolid;
457
    xdev->function = GXcopy;
458
    xdev->fid = (Font) 0;
459
 
460
    /* Set up a graphics context */
461
    xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
462
    XSetFunction(xdev->dpy, xdev->gc, GXcopy);
463
    XSetLineAttributes(xdev->dpy, xdev->gc, 0,
464
		       LineSolid, CapButt, JoinMiter);
465
 
466
    gdev_x_clear_window(xdev);
467
 
468
    if (!xdev->ghostview) {	/* Make the window appear. */
469
	XMapWindow(xdev->dpy, xdev->win);
470
 
471
	/* Before anything else, do a flush and wait for */
472
	/* an exposure event. */
473
	XSync(xdev->dpy, False);
474
	if (xdev->pwin == (Window) None) {	/* there isn't a next event for existing windows */
475
	    XNextEvent(xdev->dpy, &event);
476
	}
477
	/* Now turn off graphics exposure events so they don't queue up */
478
	/* indefinitely.  Also, since we can't do anything about real */
479
	/* Expose events, mask them out. */
480
	XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
481
	XSelectInput(xdev->dpy, xdev->win, NoEventMask);
482
    } else {
483
	/* Create an unmapped window, that the window manager will ignore.
484
	 * This invisible window will be used to receive "next page"
485
	 * events from ghostview */
486
	XSetWindowAttributes attributes;
487
 
488
	attributes.override_redirect = True;
489
	xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
490
				   0, 0, 1, 1, 0, CopyFromParent,
491
				   CopyFromParent, CopyFromParent,
492
				   CWOverrideRedirect, &attributes);
493
	xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
494
	xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
495
	xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
496
    }
497
 
498
    xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
499
				       xdev->vinfo->depth);
500
 
501
    return 0;
502
}
503
 
504
/* Set up or take down buffering in a RAM image. */
505
private int
506
x_set_buffer(gx_device_X * xdev)
507
{
508
    /*
509
     * We must use the stable memory here, since the existence of the
510
     * buffer is independent of save/restore.
511
     */
512
    gs_memory_t *mem = gs_memory_stable(xdev->memory);
513
    bool buffered = xdev->MaxBitmap > 0;
514
    const gx_device_procs *procs;
515
 
516
 setup:
517
    if (buffered) {
518
	/* We want to buffer. */
519
	/* Check that we can set up a memory device. */
520
	gx_device_memory *mdev = (gx_device_memory *)xdev->target;
521
 
522
	if (mdev == 0 || mdev->color_info.depth != xdev->color_info.depth) {
523
	    const gx_device_memory *mdproto =
524
		gdev_mem_device_for_bits(xdev->color_info.depth);
525
 
526
	    if (!mdproto) {
527
		buffered = false;
528
		goto setup;
529
	    }
530
	    if (mdev) {
531
		/* Update the pointer we're about to overwrite. */
532
		gx_device_set_target((gx_device_forward *)mdev, NULL);
533
	    } else {
534
		mdev = gs_alloc_struct(mem, gx_device_memory,
535
				       &st_device_memory, "memory device");
536
		if (mdev == 0) {
537
		    buffered = false;
538
		    goto setup;
539
		}
540
	    }
541
	    /*
542
	     * We want to forward image drawing to the memory device.
543
	     * That requires making the memory device forward its color
544
	     * mapping operations back to the X device, creating a circular
545
	     * pointer structure.  This is not a disaster, we just need to
546
	     * be aware that this is going on.
547
	     */
548
	    gs_make_mem_device(mdev, mdproto, mem, 0, (gx_device *)xdev);
549
	    gx_device_set_target((gx_device_forward *)xdev, (gx_device *)mdev);
550
	    xdev->is_buffered = true;
551
	}
552
	if (mdev->width != xdev->width || mdev->height != xdev->height) {
553
	    byte *buffer;
554
	    ulong space;
555
 
556
	    space = gdev_mem_data_size(mdev, xdev->width, xdev->height);
557
	    if (space > xdev->MaxBitmap) {
558
		buffered = false;
559
		goto setup;
560
	    }
561
	    buffer =
562
		(xdev->buffer ?
563
		 (byte *)gs_resize_object(mem, xdev->buffer, space, "buffer") :
564
		 gs_alloc_bytes(mem, space, "buffer"));
565
	    if (!buffer) {
566
		buffered = false;
567
		goto setup;
568
	    }
569
	    xdev->buffer_size = space;
570
	    xdev->buffer = buffer;
571
	    mdev->width = xdev->width;
572
	    mdev->height = xdev->height;
573
	    mdev->color_info = xdev->color_info;
574
	    mdev->base = xdev->buffer;
575
	    gdev_mem_open_scan_lines(mdev, xdev->height);
576
	}
577
	xdev->white = gx_device_white((gx_device *)xdev);
578
	xdev->black = gx_device_black((gx_device *)xdev);
579
	procs = &gs_bbox_device.procs;
580
    } else {
581
	/* Not buffering.  Release the buffer and memory device. */
582
	gs_free_object(mem, xdev->buffer, "buffer");
583
	xdev->buffer = 0;
584
	xdev->buffer_size = 0;
585
	if (!xdev->is_buffered)
586
	    return 0;
587
	gx_device_set_target((gx_device_forward *)xdev->target, NULL);
588
	gx_device_set_target((gx_device_forward *)xdev, NULL);
589
	xdev->is_buffered = false;
590
	procs = &gs_x11_device.procs;
591
    }
592
    if (dev_proc(xdev, fill_rectangle) != procs->fill_rectangle) {
593
#define COPY_PROC(p) set_dev_proc(xdev, p, procs->p)
594
	COPY_PROC(fill_rectangle);
595
	COPY_PROC(copy_mono);
596
	COPY_PROC(copy_color);
597
	COPY_PROC(copy_alpha);
598
	COPY_PROC(fill_path);
599
	COPY_PROC(stroke_path);
600
	COPY_PROC(fill_mask);
601
	COPY_PROC(fill_trapezoid);
602
	COPY_PROC(fill_parallelogram);
603
	COPY_PROC(fill_triangle);
604
	COPY_PROC(draw_thin_line);
605
	COPY_PROC(strip_tile_rectangle);
606
	COPY_PROC(strip_copy_rop);
607
	COPY_PROC(begin_typed_image);
608
	COPY_PROC(create_compositor);
609
	COPY_PROC(text_begin);
610
#undef COPY_PROC
611
	if (xdev->is_buffered) {
612
    	    check_device_separable((gx_device *)xdev);
613
	    gx_device_forward_fill_in_procs((gx_device_forward *)xdev);
614
	    xdev->box_procs = gdev_x_box_procs;
615
	    xdev->box_proc_data = xdev;
616
	} else {
617
    	    check_device_separable((gx_device *)xdev);
618
	    gx_device_fill_in_procs((gx_device *)xdev);
619
	}
620
    }
621
    return 0;
622
}
623
 
624
/* Allocate the backing pixmap, if any, and clear the window. */
625
void
626
gdev_x_clear_window(gx_device_X * xdev)
627
{
628
    if (!xdev->ghostview) {
629
	if (xdev->useBackingPixmap) {
630
	    if (xdev->bpixmap == 0) {
631
		x_error_handler.oldhandler = XSetErrorHandler(x_catch_alloc);
632
		x_error_handler.alloc_error = False;
633
		xdev->bpixmap =
634
		    XCreatePixmap(xdev->dpy, xdev->win,
635
				  xdev->width, xdev->height,
636
				  xdev->vinfo->depth);
637
		XSync(xdev->dpy, False);	/* Force the error */
638
		if (x_error_handler.alloc_error) {
639
		    xdev->useBackingPixmap = False;
640
#ifdef DEBUG
641
		    eprintf("Warning: Failed to allocated backing pixmap.\n");
642
#endif
643
		    if (xdev->bpixmap) {
644
			XFreePixmap(xdev->dpy, xdev->bpixmap);
645
			xdev->bpixmap = None;
646
			XSync(xdev->dpy, False);	/* Force the error */
647
		    }
648
		}
649
		x_error_handler.oldhandler =
650
		    XSetErrorHandler(x_error_handler.oldhandler);
651
	    }
652
	} else {
653
	    if (xdev->bpixmap != 0) {
654
		XFreePixmap(xdev->dpy, xdev->bpixmap);
655
		xdev->bpixmap = (Pixmap) 0;
656
	    }
657
	}
658
    }
659
    x_set_buffer(xdev);
660
    /* Clear the destination pixmap to avoid initializing with garbage. */
661
    if (xdev->dest == (Pixmap) 0) {
662
	xdev->dest = (xdev->bpixmap != (Pixmap) 0 ?
663
		  xdev->bpixmap : (Pixmap) xdev->win);
664
    }
665
    if (xdev->dest != (Pixmap) 0) {
666
	XSetForeground(xdev->dpy, xdev->gc, xdev->background);
667
	XFillRectangle(xdev->dpy, xdev->dest, xdev->gc,
668
		       0, 0, xdev->width, xdev->height);
669
    }
670
 
671
    /* Clear the background pixmap to avoid initializing with garbage. */
672
    if (xdev->bpixmap != (Pixmap) 0) {
673
	if (!xdev->ghostview)
674
	    XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
675
	XSetForeground(xdev->dpy, xdev->gc, xdev->background);
676
	XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
677
		       0, 0, xdev->width, xdev->height);
678
    }
679
    /* Initialize foreground and background colors */
680
    xdev->back_color = xdev->background;
681
    XSetBackground(xdev->dpy, xdev->gc, xdev->background);
682
    xdev->fore_color = xdev->background;
683
    XSetForeground(xdev->dpy, xdev->gc, xdev->background);
684
    xdev->colors_or = xdev->colors_and = xdev->background;
685
}
686
 
687
/* ------ Initialize font mapping ------ */
688
 
689
/* Extract the PostScript font name from the font map resource. */
690
private const char *
691
get_ps_name(const char **cpp, int *len)
692
{
693
    const char *ret;
694
 
695
    *len = 0;
696
    /* skip over whitespace and newlines */
697
    while (**cpp == ' ' || **cpp == '\t' || **cpp == '\n') {
698
	(*cpp)++;
699
    }
700
    /* return font name up to ":", whitespace, or end of string */
701
    if (**cpp == ':' || **cpp == '\0') {
702
	return NULL;
703
    }
704
    ret = *cpp;
705
    while (**cpp != ':' &&
706
	   **cpp != ' ' && **cpp != '\t' && **cpp != '\n' &&
707
	   **cpp != '\0') {
708
	(*cpp)++;
709
	(*len)++;
710
    }
711
    return ret;
712
}
713
 
714
/* Extract the X11 font name from the font map resource. */
715
private const char *
716
get_x11_name(const char **cpp, int *len)
717
{
718
    const char *ret;
719
    int dashes = 0;
720
 
721
    *len = 0;
722
    /* skip over whitespace and the colon */
723
    while (**cpp == ' ' || **cpp == '\t' ||
724
	   **cpp == ':') {
725
	(*cpp)++;
726
    }
727
    /* return font name up to end of line or string */
728
    if (**cpp == '\0' || **cpp == '\n') {
729
	return NULL;
730
    }
731
    ret = *cpp;
732
    while (dashes != 7 &&
733
	   **cpp != '\0' && **cpp != '\n') {
734
	if (**cpp == '-')
735
	    dashes++;
736
	(*cpp)++;
737
	(*len)++;
738
    }
739
    while (**cpp != '\0' && **cpp != '\n') {
740
	(*cpp)++;
741
    }
742
    if (dashes != 7)
743
	return NULL;
744
    return ret;
745
}
746
 
747
/* Scan one resource and build font map records. */
748
private void
749
scan_font_resource(const char *resource, x11fontmap **pmaps, gs_memory_t *mem)
750
{
751
    const char *ps_name;
752
    const char *x11_name;
753
    int ps_name_len;
754
    int x11_name_len;
755
    x11fontmap *font;
756
    const char *cp = resource;
757
 
758
    while ((ps_name = get_ps_name(&cp, &ps_name_len)) != 0) {
759
	x11_name = get_x11_name(&cp, &x11_name_len);
760
	if (x11_name) {
761
	    font = gs_alloc_struct(mem, x11fontmap, &st_x11fontmap,
762
				   "scan_font_resource(font)");
763
	    if (font == NULL)
764
		continue;
765
	    font->ps_name = (char *)
766
		gs_alloc_byte_array(mem, ps_name_len + 1, sizeof(char),
767
				    "scan_font_resource(ps_name)");
768
	    if (font->ps_name == NULL) {
769
		gs_free_object(mem, font, "scan_font_resource(font)");
770
		continue;
771
	    }
772
	    strncpy(font->ps_name, ps_name, ps_name_len);
773
	    font->ps_name[ps_name_len] = '\0';
774
	    font->x11_name = (char *)
775
		gs_alloc_byte_array(mem, x11_name_len, sizeof(char),
776
				    "scan_font_resource(x11_name)");
777
	    if (font->x11_name == NULL) {
778
		gs_free_object(mem, font->ps_name,
779
			       "scan_font_resource(ps_name)");
780
		gs_free_object(mem, font, "scan_font_resource(font)");
781
		continue;
782
	    }
783
	    strncpy(font->x11_name, x11_name, x11_name_len - 1);
784
	    font->x11_name[x11_name_len - 1] = '\0';
785
	    font->std.names = NULL;
786
	    font->std.count = -1;
787
	    font->iso.names = NULL;
788
	    font->iso.count = -1;
789
	    font->next = *pmaps;
790
	    *pmaps = font;
791
	}
792
    }
793
}
794
 
795
/* Scan all the font resources and set up the maps. */
796
private void
797
gdev_x_setup_fontmap(gx_device_X * xdev)
798
{
799
    if (!xdev->useXFonts)
800
	return;			/* If no external fonts, don't bother */
801
 
802
    scan_font_resource(xdev->regularFonts, &xdev->regular_fonts, xdev->memory);
803
    scan_font_resource(xdev->symbolFonts, &xdev->symbol_fonts, xdev->memory);
804
    scan_font_resource(xdev->dingbatFonts, &xdev->dingbat_fonts, xdev->memory);
805
}
806
 
807
/* Clean up the instance after making a copy. */
808
int
809
gdev_x_finish_copydevice(gx_device *dev, const gx_device *from_dev)
810
{
811
    gx_device_X *xdev = (gx_device_X *) dev;
812
 
813
    /* Mark the new instance as closed. */
814
    xdev->is_open = false;
815
 
816
    /* Prevent dangling references from the *_fonts lists. */
817
    xdev->regular_fonts = 0;
818
    xdev->symbol_fonts = 0;
819
    xdev->dingbat_fonts = 0;
820
 
821
    /* Clear all other pointers. */
822
    xdev->target = 0;
823
    xdev->buffer = 0;
824
    xdev->dpy = 0;
825
    xdev->scr = 0;
826
    xdev->vinfo = 0;
827
 
828
    /* Clear pointer-like parameters. */
829
    xdev->win = (Window)None;
830
    xdev->bpixmap = (Pixmap)0;
831
    xdev->dest = (Pixmap)0;
832
    xdev->cp.pixmap = (Pixmap)0;
833
    xdev->ht.pixmap = (Pixmap)0;
834
 
835
    /* Reset pointer-related parameters. */
836
    xdev->is_buffered = false;
837
    /* See x_set_buffer for why we do this: */
838
    set_dev_proc(xdev, fill_rectangle,
839
		 dev_proc(&gs_x11_device, fill_rectangle));
840
 
841
    return 0;
842
}
843
 
844
/* ---------------- Get/put parameters ---------------- */
845
 
846
/* Get the device parameters.  See below. */
847
int
848
gdev_x_get_params(gx_device * dev, gs_param_list * plist)
849
{
850
    gx_device_X *xdev = (gx_device_X *) dev;
851
    int code = gx_default_get_params(dev, plist);
852
    long id = (long)xdev->pwin;
853
 
854
    if (code < 0 ||
855
	(code = param_write_long(plist, "WindowID", &id)) < 0 ||
856
	(code = param_write_bool(plist, ".IsPageDevice", &xdev->IsPageDevice)) < 0 ||
857
	(code = param_write_long(plist, "MaxBitmap", &xdev->MaxBitmap)) < 0 ||
858
	(code = param_write_int(plist, "MaxTempPixmap", &xdev->MaxTempPixmap)) < 0 ||
859
	(code = param_write_int(plist, "MaxTempImage", &xdev->MaxTempImage)) < 0 ||
860
	(code = param_write_int(plist, "MaxBufferedTotal", &xdev->MaxBufferedTotal)) < 0 ||
861
	(code = param_write_int(plist, "MaxBufferedArea", &xdev->MaxBufferedArea)) < 0 ||
862
	(code = param_write_int(plist, "MaxBufferedCount", &xdev->MaxBufferedCount)) < 0
863
	)
864
	DO_NOTHING;
865
    return code;
866
}
867
 
868
/* Set the device parameters.  We reimplement this so we can resize */
869
/* the window and avoid closing and reopening the device, and to add */
870
/* .IsPageDevice. */
871
int
872
gdev_x_put_params(gx_device * dev, gs_param_list * plist)
873
{
874
    gx_device_X *xdev = (gx_device_X *) dev;
875
    /*
876
     * Provide copies of values of parameters being set:
877
     * is_open, width, height, HWResolution, IsPageDevice, Max*.
878
     */
879
    gx_device_X values;
880
 
881
    long pwin = (long)xdev->pwin;
882
    bool save_is_page = xdev->IsPageDevice;
883
    int ecode = 0, code;
884
    bool clear_window = false;
885
 
886
    values = *xdev;
887
 
888
    /* Handle extra parameters */
889
 
890
    ecode = param_put_long(plist, "WindowID", &pwin, ecode);
891
    ecode = param_put_bool(plist, ".IsPageDevice", &values.IsPageDevice, ecode);
892
    ecode = param_put_long(plist, "MaxBitmap", &values.MaxBitmap, ecode);
893
    ecode = param_put_int(plist, "MaxTempPixmap", &values.MaxTempPixmap, ecode);
894
    ecode = param_put_int(plist, "MaxTempImage", &values.MaxTempImage, ecode);
895
    ecode = param_put_int(plist, "MaxBufferedTotal", &values.MaxBufferedTotal, ecode);
896
    ecode = param_put_int(plist, "MaxBufferedArea", &values.MaxBufferedArea, ecode);
897
    ecode = param_put_int(plist, "MaxBufferedCount", &values.MaxBufferedCount, ecode);
898
 
899
    if (ecode < 0)
900
	return ecode;
901
 
902
    /* Unless we specified a new window ID, */
903
    /* prevent gx_default_put_params from closing the device. */
904
    if (pwin == (long)xdev->pwin)
905
	dev->is_open = false;
906
    xdev->IsPageDevice = values.IsPageDevice;
907
    code = gx_default_put_params(dev, plist);
908
    dev->is_open = values.is_open; /* saved value */
909
    if (code < 0) {		/* Undo setting of .IsPageDevice */
910
	xdev->IsPageDevice = save_is_page;
911
	return code;
912
    }
913
    if (pwin != (long)xdev->pwin) {
914
	if (xdev->is_open)
915
	    gs_closedevice(dev);
916
	xdev->pwin = (Window) pwin;
917
    }
918
    /* If the device is open, resize the window. */
919
    /* Don't do this if Ghostview is active. */
920
    if (xdev->is_open && !xdev->ghostview &&
921
	(dev->width != values.width || dev->height != values.height ||
922
	 dev->HWResolution[0] != values.HWResolution[0] ||
923
	 dev->HWResolution[1] != values.HWResolution[1])
924
	) {
925
	int dw = dev->width - values.width;
926
	int dh = dev->height - values.height;
927
	double qx = dev->HWResolution[0] / values.HWResolution[0];
928
	double qy = dev->HWResolution[1] / values.HWResolution[1];
929
 
930
	if (dw || dh) {
931
	    XResizeWindow(xdev->dpy, xdev->win,
932
			  dev->width, dev->height);
933
	    if (xdev->bpixmap != (Pixmap) 0) {
934
		XFreePixmap(xdev->dpy, xdev->bpixmap);
935
		xdev->bpixmap = (Pixmap) 0;
936
	    }
937
	    xdev->dest = 0;
938
	    clear_window = true;
939
	}
940
	/* Attempt to update the initial matrix in a sensible way. */
941
	/* The whole handling of the initial matrix is a hack! */
942
	if (xdev->initial_matrix.xy == 0) {
943
	    if (xdev->initial_matrix.xx < 0) {	/* 180 degree rotation */
944
		xdev->initial_matrix.tx += dw;
945
	    } else {		/* no rotation */
946
		xdev->initial_matrix.ty += dh;
947
	    }
948
	} else {
949
	    if (xdev->initial_matrix.xy < 0) {	/* 90 degree rotation */
950
		xdev->initial_matrix.tx += dh;
951
		xdev->initial_matrix.ty += dw;
952
	    } else {		/* 270 degree rotation */
953
	    }
954
	}
955
	xdev->initial_matrix.xx *= qx;
956
	xdev->initial_matrix.xy *= qx;
957
	xdev->initial_matrix.yx *= qy;
958
	xdev->initial_matrix.yy *= qy;
959
    }
960
    xdev->MaxTempPixmap = values.MaxTempPixmap;
961
    xdev->MaxTempImage = values.MaxTempImage;
962
    xdev->MaxBufferedTotal = values.MaxBufferedTotal;
963
    xdev->MaxBufferedArea = values.MaxBufferedArea;
964
    xdev->MaxBufferedCount = values.MaxBufferedCount;
965
    if (clear_window || xdev->MaxBitmap != values.MaxBitmap) {
966
	/****** DO MORE FOR RESETTING MaxBitmap ******/
967
	xdev->MaxBitmap = values.MaxBitmap;
968
	if (xdev->is_open)
969
	    gdev_x_clear_window(xdev);
970
    }
971
    return 0;
972
}
973
 
974
/* ---------------- Closing/finalization ---------------- */
975
 
976
/* Free fonts when closing the device. */
977
private void
978
free_x_fontmaps(x11fontmap **pmaps, gs_memory_t *mem)
979
{
980
    while (*pmaps) {
981
	x11fontmap *font = *pmaps;
982
 
983
	*pmaps = font->next;
984
	if (font->std.names)
985
	    XFreeFontNames(font->std.names);
986
	if (font->iso.names)
987
	    XFreeFontNames(font->iso.names);
988
	gs_free_object(mem, font->x11_name, "free_x_fontmaps(x11_name)");
989
	gs_free_object(mem, font->ps_name, "free_x_fontmaps(ps_name)");
990
	gs_free_object(mem, font, "free_x_fontmaps(font)");
991
    }
992
}
993
 
994
/* Close the device. */
995
int
996
gdev_x_close(gx_device_X *xdev)
997
{
998
    if (xdev->ghostview)
999
	gdev_x_send_event(xdev, xdev->DONE);
1000
    if (xdev->vinfo) {
1001
	XFree((char *)xdev->vinfo);
1002
	xdev->vinfo = NULL;
1003
    }
1004
    gdev_x_free_colors(xdev);
1005
    free_x_fontmaps(&xdev->dingbat_fonts, xdev->memory);
1006
    free_x_fontmaps(&xdev->symbol_fonts, xdev->memory);
1007
    free_x_fontmaps(&xdev->regular_fonts, xdev->memory);
1008
    if (xdev->cmap != DefaultColormapOfScreen(xdev->scr))
1009
	XFreeColormap(xdev->dpy, xdev->cmap);
1010
    XCloseDisplay(xdev->dpy);
1011
    return 0;
1012
}