2 /* Copyright (c) 1995, 1996, 1998, 1999, 2000, 2001, 2004, 2005 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions for displaying Mup/Ghostscript output under X windows. */
12 #include <X11/Xresource.h>
14 /* size for XLookupString buffer */
17 /* X window icon to use when window is icon-ized.
18 * Shows musical notes. This was generated using the bitmap tool */
19 #define Disp_icon_width 32
20 #define Disp_icon_height 32
21 static unsigned char Disp_icon_bits
[] = {
22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00,
23 0x00, 0xc0, 0x0b, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf8, 0x08, 0x00,
24 0x00, 0x1e, 0x08, 0x00, 0x00, 0x0e, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00,
25 0xff, 0xff, 0xff, 0xff, 0x00, 0x02, 0x08, 0x14, 0x00, 0x02, 0x08, 0x22,
26 0x00, 0x02, 0x08, 0x23, 0x00, 0x02, 0x08, 0x15, 0xff, 0xff, 0xff, 0xff,
27 0x00, 0x02, 0x08, 0x01, 0x00, 0x02, 0x08, 0x01, 0x00, 0x82, 0x0f, 0x01,
28 0x00, 0xc2, 0x0f, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x82, 0x07, 0x01,
29 0x00, 0x02, 0x00, 0x01, 0xe0, 0x03, 0x02, 0x01, 0xf0, 0x03, 0x01, 0x01,
30 0xff, 0xff, 0xff, 0xff, 0xe0, 0x81, 0x00, 0x01, 0x00, 0x40, 0x00, 0x01,
31 0x80, 0x31, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
34 #define MINHEIGHT (400) /* allow this short a window in X window mode */
35 #define MAXHEIGHT LINES_PER_PAGE /* tallest window we allow */
40 /* bitmap of whether control key is pressed */
44 extern unsigned char Waitmsg_bitmap
[]; /* message to tell user to wait */
45 extern int Waitmsg_width
, Waitmsg_height
;
47 /* define X window screen and display things */
48 static Display
*Display_p
;
50 static XImage
*Image_p
;
51 static XFontStruct
*Font_info_p
;
52 static GC gc
; /* X graphics context */
54 static unsigned int Width
, Height
;
55 static XSizeHints Size_hints
; /* tell window manager what size we want */
56 static unsigned long Foreground
; /* color */
57 static unsigned long Background
; /* color */
58 static char Mupdisp
[] = "mupdisp";
60 /* X resource manager things */
61 static XrmOptionDescRec Option_table
[] = {
62 { "-geometry", ".geometry", XrmoptionSepArg
, (caddr_t
) 0 },
63 { "-background","*background", XrmoptionSepArg
, (caddr_t
) 0 },
64 { "-bg", "*background", XrmoptionSepArg
, (caddr_t
) 0 },
65 { "-foreground","*foreground", XrmoptionSepArg
, (caddr_t
) 0 },
66 { "-fg", "*foreground", XrmoptionSepArg
, (caddr_t
) 0 },
68 static int Opt_table_size
= sizeof(Option_table
) / sizeof (XrmOptionDescRec
);
69 static char Xoptions_usage
[] =
71 Also the following X options:\n\
72 -bg color set background color\n\
73 -fg color set foreground color\n\
74 -geometry XxY+N+M set window size and location\n";
75 XrmDatabase Resource_db
;
79 static char * get_cmd_resource
P((char *resource_name
));
80 static unsigned long get_color
P((char *resource_name
,
81 unsigned long default_value
));
82 static int color_ok
P((char *resource_name
, char *value
, XColor
*color_p
));
83 static void create_image
P((int wid
, int height
));
84 static void get_GC
P((Window win
));
85 static void load_font
P((void));
86 static void TooSmall
P((Window win
));
89 /* parse any X-specific aguments */
95 XrmParseCommand( &Resource_db
, Option_table
, Opt_table_size
,
96 Mupdisp
, &Argc
, Argv
);
97 /* tell Mup about these additional options */
98 putenv(Xoptions_usage
);
102 /* setup for X-window operation. Basically copy things from the X manual,
103 * and customize as appropriate. */
111 unsigned int border_width
= 4;
112 unsigned int display_width
, display_height
;
113 char *window_name
= Mupdisp
;
114 char *icon_name
= Mupdisp
;
116 char *display_name
= NULL
;
119 unsigned int dummy_width
; /* we don't allow Width to change */
120 XWindowAttributes attributes
;
121 int got_geometry
= 0;
124 /* If mupdisp is setuid to root so that libsvga can work on
125 * console devices, Ghostscript can fail under X.
126 * So relinquish our superuser-ism.
128 if (getuid() != geteuid()) {
133 if ( (Display_p
= XOpenDisplay(display_name
)) == NULL
) {
134 fprintf(stderr
, "%s: can't connect to X server %s\n", Argv
[0],
135 XDisplayName(display_name
));
139 Xscreen
= DefaultScreen(Display_p
);
141 display_width
= DisplayWidth(Display_p
, Xscreen
);
142 display_height
= DisplayHeight(Display_p
, Xscreen
);
144 /* this is our ideal size. Window manager may have other ideas */
145 Width
= BITS_PER_LINE
;
146 /* Use a height a little smaller than the screen height (to allow
147 * for window borders), or at a minimum, what's in Conf_info_p */
148 if (display_height
- 50 > Conf_info_p
->vlines
) {
149 Height
= display_height
- 50;
152 Height
= Conf_info_p
->vlines
;
155 /* If user specified colors, get those, otherwise use black on white */
156 Background
= get_color("background", WhitePixel(Display_p
, Xscreen
));
157 Foreground
= get_color("foreground", BlackPixel(Display_p
, Xscreen
));
159 /* Now see if user specified geometry, either from command line,
160 * or failing that, from default database. */
161 if ((value
= get_cmd_resource("geometry")) != (char *) 0) {
162 XParseGeometry(value
, &x
, &y
, &dummy_width
, &Height
);
165 else if ((value
= XGetDefault(Display_p
, Mupdisp
, "geometry")) != 0) {
166 XParseGeometry(value
, &x
, &y
, &dummy_width
, &Height
);
169 if (Height
< MINHEIGHT
) {
172 if (Height
> MAXHEIGHT
) {
177 /* create window and icon */
178 Win
= XCreateSimpleWindow(Display_p
, RootWindow(Display_p
, Xscreen
),
179 x
, y
, Width
, Height
, border_width
,
180 Foreground
, Background
);
182 icon_pixmap
= XCreateBitmapFromData(Display_p
, Win
,
183 (char *) Disp_icon_bits
, Disp_icon_width
,
186 /* we want the width to be exactly the width of a page. The height
187 * can vary because we scroll in that direction */
189 Size_hints
.flags
= PSize
| PMinSize
| PMaxSize
| PPosition
;
194 Size_hints
.flags
= PSize
| PMinSize
| PMaxSize
;
196 Size_hints
.width
= Width
;
197 Size_hints
.height
= Height
;
198 Size_hints
.min_width
= Width
;
199 Size_hints
.max_width
= Width
;
200 Size_hints
.min_height
= MINHEIGHT
;
201 Size_hints
.max_height
= (display_height
< MAXHEIGHT
202 ? display_height
: MAXHEIGHT
);
204 XSetStandardProperties(Display_p
, Win
, window_name
, icon_name
,
205 icon_pixmap
, Argv
, Argc
, &Size_hints
);
207 XSelectInput(Display_p
, Win
, ExposureMask
| KeyPressMask
|
208 KeyReleaseMask
| ButtonPressMask
| StructureNotifyMask
);
212 XMapWindow(Display_p
, Win
);
214 /* determine what height we actually got */
215 if (XGetWindowAttributes(Display_p
, Win
, &attributes
) != 0) {
216 Conf_info_p
->vlines
= Height
= attributes
.height
;
219 create_image(Width
, Height
);
221 /* it seems we need to wait for an exposure event,(or maybe it's
222 * really MapNotify) before proceeding, or else the "wait" message
223 * doesn't get displayed, so wait for it */
224 XWindowEvent(Display_p
, Win
, ExposureMask
, &event
);
228 /* create XImage for the display. If one already existed, free it first (which
229 * would happen if window was re-sized */
232 create_image(wid
, height
)
241 /* if already have one, free that and redo if different size */
242 if (Image_p
!= (XImage
*) 0) {
243 if (Image_p
->width
== wid
&& Image_p
->height
== height
) {
244 /* already have one of correct size */
248 XDestroyImage(Image_p
);
252 /* create buffer for display image */
253 if ((databuff
= (char *) malloc(BYTES_PER_LINE
* height
)) == (char *) 0) {
254 Exit_errmsg
= "Could not allocate memory\n";
255 ( *(Conf_info_p
->cleanup
) ) (1);
258 Image_p
= XCreateImage(Display_p
, DefaultVisual(Display_p
, Xscreen
),
259 1, XYBitmap
, 0, databuff
, wid
, height
,
261 Image_p
->bitmap_unit
= 8;
262 Image_p
->bitmap_bit_order
= MSBFirst
;
266 /* Look up the color resource named. If found, return its value,
267 * otherwise return the default value. */
270 get_color(resource_name
, default_value
)
273 unsigned long default_value
;
279 /* First try looking up in command line resource database. */
280 if ((value
= get_cmd_resource(resource_name
)) != (char *) 0) {
281 if (color_ok(resource_name
, value
, &color
)) {
286 /* failing that, try looking in the default database */
287 if ((value
= XGetDefault(Display_p
, Mupdisp
, resource_name
)) != 0) {
288 if (color_ok(resource_name
, value
, &color
)) {
293 return(default_value
);
297 /* look up a value from the command line database. Return it if found, else 0 */
299 get_cmd_resource(resource_name
)
307 char class_name
[100];
311 /* create the resource and class names. Class name has initial caps */
312 sprintf(res_name
, "%s.%s", Mupdisp
, resource_name
);
313 sprintf(class_name
, "%s.%s", Mupdisp
, resource_name
);
314 class_name
[0] = toupper(class_name
[0]);
315 offset
= strlen(Mupdisp
) + 1;
316 class_name
[offset
] = toupper(class_name
[offset
]);
318 /* look it up in command line resource database. */
319 if (XrmGetResource(Resource_db
, res_name
,
320 class_name
, str_type
, &rm_value
) == True
) {
321 return ((char *) rm_value
.addr
);
326 /* Parse a color name and allocate it. If all goes well, fill in the
327 * XColor and return 1. If something goes wrong, return 0. */
330 color_ok(resource_name
, value
, color_p
)
337 if (XParseColor(Display_p
,
338 DefaultColormapOfScreen(
339 DefaultScreenOfDisplay(Display_p
)),
340 value
, color_p
) != 0) {
341 if (XAllocColor(Display_p
,
342 DefaultColormapOfScreen(
343 DefaultScreenOfDisplay(Display_p
)),
349 fprintf(stderr
, "invalid %s color: %s\n",
350 resource_name
, value
);
356 /* get input in X windows mode. Handle all the events, including mouse,
357 * resizing and exposure */
363 XEvent report
; /* what X event happened */
364 char inpbuff
[IBUFSIZ
];
366 XComposeStatus compose
;
367 int window_size
= OK
;
368 static int control
= 0; /* non-zero if control key is pressed */
373 /* get an event and take appropriate action */
374 XNextEvent(Display_p
, &report
);
376 switch(report
.type
) {
380 while(XCheckTypedEvent(Display_p
, Expose
, &report
))
382 if (window_size
== SMALL
) {
390 case ConfigureNotify
:
391 /* set up image of proper size */
392 Width
= report
.xconfigure
.width
;
393 Height
= report
.xconfigure
.height
;
394 if ((Width
< Size_hints
.min_width
) ||
395 (Height
< Size_hints
.min_height
)) {
401 create_image(Width
, Height
);
402 Conf_info_p
->vlines
= Height
;
406 /* mouse. left is forward, right is backward scroll */
407 if (report
.xbutton
.button
== 1) {
410 else if (report
.xbutton
.button
== 3) {
416 /* keyboard input. Do appropriate command */
417 XLookupString(&(report
.xkey
), inpbuff
, IBUFSIZ
, &keysym
,
419 /* the linux version of isascii claims
420 * that isascii(0xff0d) is true! So I added the
421 * extra check for < 256 (which isascii should already
423 if (keysym
< 256 && isascii(keysym
)) {
425 do_cmd(keysym
& 0x1f);
431 else if (keysym
== XK_Return
) {
434 else if (keysym
== XK_BackSpace
) {
437 else if (keysym
== XK_Up
) {
438 /* use up key as synonym for scrolling back */
441 else if (keysym
== XK_Down
) {
442 /* use down key as synonym for scrolling forward */
445 else if (keysym
== XK_Prior
) {
446 /* use page up key as synonym for previous page */
449 else if (keysym
== XK_Next
) {
450 /* use page down key as synonym for next page */
453 else if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
459 /* just check for control key release */
460 XLookupString(&(report
.xkey
), inpbuff
, IBUFSIZ
, &keysym
,
462 if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
476 /* create graphics context. Basically copy the example in the X book */
484 unsigned long valuemask
= 0;
486 unsigned int line_width
= 6;
487 int line_style
= LineOnOffDash
;
488 int cap_style
= CapRound
;
489 int join_style
= JoinRound
;
491 static char dash_list
[] = { 12, 24 };
494 gc
= XCreateGC(Display_p
, Win
, valuemask
, &values
);
495 XSetFont(Display_p
, gc
, Font_info_p
->fid
);
496 XSetForeground(Display_p
, gc
, Foreground
);
497 XSetBackground(Display_p
, gc
, Background
);
498 XSetLineAttributes(Display_p
, gc
, line_width
, line_style
, cap_style
,
500 XSetDashes(Display_p
, gc
, dash_offset
, dash_list
, list_length
);
504 /* load a font. Copy example in X book */
510 char *fontname
= "9x15";
512 if ((Font_info_p
= XLoadQueryFont(Display_p
, fontname
)) == NULL
) {
513 fprintf(stderr
, "can't open 9x15 font\n");
525 char *string1
= "Too small";
527 XDrawString(Display_p
, win
, gc
, 2, Font_info_p
->max_bounds
.ascent
+ 2,
528 string1
, strlen(string1
));
529 Exit_errmsg
= "Window too small\n";
530 ( *(Conf_info_p
->cleanup
) ) (1);
534 /* X cleanup function */
537 xterm_cleanup(status
)
542 /* free all X resources */
543 XUnloadFont(Display_p
, Font_info_p
->fid
);
544 XFreeGC(Display_p
, gc
);
545 XCloseDisplay(Display_p
);
547 /* call non-terminal-type specific cleanup */
548 generalcleanup(status
);
552 /* draw screen in X mode */
555 xterm_draw(line
, small
)
557 int line
; /* start drawing at this raster line */
558 int small
; /* if YES, use small, full-page mode */
562 long offset
; /* offset into file where page begins */
563 int fd
; /* file descriptor of bitmap file */
566 /* make sure we have a valid page */
567 if (Currpage_p
== (struct Pginfo
*) 0) {
568 ( *(Conf_info_p
->error
) ) ("page # out of range");
572 /* find data in bitmap file */
573 offset
= Currpage_p
->seqnum
* BYTES_PER_PAGE
;
574 fd
= gen1file(small
);
575 lseek(fd
, offset
+ line
* BYTES_PER_LINE
, SEEK_SET
);
577 /* copy into memory and display it */
578 for (i
= 0; i
< Conf_info_p
->vlines
; i
++) {
579 read(fd
, Image_p
->data
+ i
* BYTES_PER_LINE
, BYTES_PER_LINE
);
581 XPutImage(Display_p
, Win
, gc
, Image_p
, 0, 0, 0, 0, Width
, Height
);
587 /* Error handler. For now just beep. Maybe eventually pop up an error message */
599 /* draw a raster bitmap, centered on the window */
602 xterm_raster(bitmap
, width
, height
)
604 unsigned char *bitmap
; /* what to display */
605 int width
, height
; /* of bitmap, width is in bytes */
609 int x
, y
; /* upper left corner of where to put bitmap, x in bytes */
614 /* figure out how to center on screen */
615 x
= (BYTES_PER_LINE
- width
) / 2;
616 y
= (Conf_info_p
->vlines
- height
) / 2;
618 /* get space to image, copy, inverting to white on black. Display,
619 * then release the storage */
620 if ((bmap
= (char *) malloc(width
*height
)) == (char *) 0) {
621 Exit_errmsg
= "Could not allocate memory\n";
622 ( *(Conf_info_p
->cleanup
) ) (1);
624 for (b
= width
* height
- 1; b
>= 0; b
--) {
625 bmap
[b
] = bitmap
[b
] ^ 0xff;
627 bm_image
= XCreateImage(Display_p
, DefaultVisual(Display_p
, Xscreen
),
628 1, XYBitmap
, 0, bmap
, width
* 8, height
,
630 bm_image
->bitmap_unit
= 8;
631 bm_image
->bitmap_bit_order
= MSBFirst
;
632 XPutImage(Display_p
, Win
, gc
, bm_image
, 0, 0, x
* 8, y
, width
* 8, height
);
633 XDestroyImage(bm_image
);
639 /* some compilers complain about files that are effectively empty,
640 * so put in something even when entire file is effectively ifdef-ed out */