481 lines
13 KiB
C
481 lines
13 KiB
C
|
|
/*
|
|||
|
|
* Generic Output Driver for X
|
|||
|
|
* X version 11
|
|||
|
|
*
|
|||
|
|
* This is the primary output driver used by the new X graph
|
|||
|
|
* to display output to the X server. It has been factored
|
|||
|
|
* out of the original xgraph to allow mulitple hardcopy
|
|||
|
|
* output devices to share xgraph's capabilities. Note:
|
|||
|
|
* xgraph is still heavily X oriented. This is not intended
|
|||
|
|
* for porting to other window systems.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "copyright.h"
|
|||
|
|
#include "xgout.h"
|
|||
|
|
#include "params.h"
|
|||
|
|
|
|||
|
|
#define PADDING 2
|
|||
|
|
#define SPACE 10
|
|||
|
|
#define TICKLENGTH 5
|
|||
|
|
#define MAXSEGS 1000
|
|||
|
|
|
|||
|
|
struct x_state {
|
|||
|
|
Window win; /* Primary window */
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void text_X();
|
|||
|
|
void seg_X();
|
|||
|
|
void dot_X();
|
|||
|
|
|
|||
|
|
|
|||
|
|
typedef struct attr_set {
|
|||
|
|
char lineStyle[MAXLS];
|
|||
|
|
int lineStyleLen;
|
|||
|
|
Pixel pixelValue;
|
|||
|
|
Pixmap markStyle;
|
|||
|
|
} AttrSet;
|
|||
|
|
|
|||
|
|
static AttrSet AllAttrs[MAXATTR];
|
|||
|
|
|
|||
|
|
static Pixmap dotMap = (Pixmap) 0;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Marker bitmaps
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "bitmaps/dot.11"
|
|||
|
|
|
|||
|
|
#include "bitmaps/mark1.11"
|
|||
|
|
#include "bitmaps/mark2.11"
|
|||
|
|
#include "bitmaps/mark3.11"
|
|||
|
|
#include "bitmaps/mark4.11"
|
|||
|
|
#include "bitmaps/mark5.11"
|
|||
|
|
#include "bitmaps/mark6.11"
|
|||
|
|
#include "bitmaps/mark7.11"
|
|||
|
|
#include "bitmaps/mark8.11"
|
|||
|
|
|
|||
|
|
/* Sizes exported for marker drawing */
|
|||
|
|
static unsigned int dot_w = dot_width;
|
|||
|
|
static unsigned int dot_h = dot_height;
|
|||
|
|
static unsigned int mark_w = mark1_width;
|
|||
|
|
static unsigned int mark_h = mark1_height;
|
|||
|
|
static int mark_cx = mark1_x_hot;
|
|||
|
|
static int mark_cy = mark1_y_hot;
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
set_X(new_win, out_info)
|
|||
|
|
Window new_win; /* Newly created window */
|
|||
|
|
xgOut *out_info; /* Information to set */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Sets some of the common parameters for the X output device.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
struct x_state *new_state;
|
|||
|
|
XFontStruct *font;
|
|||
|
|
|
|||
|
|
out_info->dev_flags = ((depth > 3) ? D_COLOR : 0);
|
|||
|
|
out_info->area_w = out_info->area_h = 0; /* Set later */
|
|||
|
|
out_info->bdr_pad = PADDING;
|
|||
|
|
out_info->axis_pad = SPACE;
|
|||
|
|
out_info->legend_pad = 0;
|
|||
|
|
out_info->tick_len = TICKLENGTH;
|
|||
|
|
|
|||
|
|
font = PM_FONT("LabelFont");
|
|||
|
|
#ifdef OLD
|
|||
|
|
out_info->axis_width =
|
|||
|
|
font->max_bounds.rbearing - font->max_bounds.lbearing;
|
|||
|
|
#endif
|
|||
|
|
out_info->axis_width = XTextWidth(font, "8", 1);
|
|||
|
|
out_info->axis_height =
|
|||
|
|
font->max_bounds.ascent + font->max_bounds.descent;
|
|||
|
|
|
|||
|
|
font = PM_FONT("TitleFont");
|
|||
|
|
#ifdef OLD
|
|||
|
|
out_info->title_width =
|
|||
|
|
font->max_bounds.rbearing - font->max_bounds.lbearing;
|
|||
|
|
#endif
|
|||
|
|
out_info->title_width = XTextWidth(font, "8", 1);
|
|||
|
|
out_info->title_height =
|
|||
|
|
font->max_bounds.ascent + font->max_bounds.descent;
|
|||
|
|
out_info->max_segs = MAXSEGS;
|
|||
|
|
|
|||
|
|
out_info->xg_text = text_X;
|
|||
|
|
out_info->xg_seg = seg_X;
|
|||
|
|
out_info->xg_dot = dot_X;
|
|||
|
|
out_info->xg_end = (void (*) ()) 0;
|
|||
|
|
new_state = (struct x_state *) Malloc(sizeof(struct x_state));
|
|||
|
|
new_state->win = new_win;
|
|||
|
|
out_info->user_state = (char *) new_state;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
static void
|
|||
|
|
init_once()
|
|||
|
|
/*
|
|||
|
|
* Initializes AllAttrs.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
Window temp_win;
|
|||
|
|
XSetWindowAttributes wattr;
|
|||
|
|
char name[1024];
|
|||
|
|
int idx;
|
|||
|
|
params style_val;
|
|||
|
|
|
|||
|
|
/* Get attributes out parameters database */
|
|||
|
|
for (idx = 0; idx < MAXATTR; idx++) {
|
|||
|
|
(void) sprintf(name, "%d.Style", idx);
|
|||
|
|
(void) param_get(name, &style_val);
|
|||
|
|
AllAttrs[idx].lineStyleLen = style_val.stylev.len;
|
|||
|
|
(void) strncpy(AllAttrs[idx].lineStyle, style_val.stylev.dash_list,
|
|||
|
|
style_val.stylev.len);
|
|||
|
|
(void) sprintf(name, "%d.Color", idx);
|
|||
|
|
AllAttrs[idx].pixelValue = PM_PIXEL(name);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Create a temporary window for representing depth */
|
|||
|
|
temp_win = XCreateWindow(disp, RootWindow(disp, screen),
|
|||
|
|
0, 0, 10, 10, 0, depth, InputOutput,
|
|||
|
|
vis, (unsigned long) 0, &wattr);
|
|||
|
|
|
|||
|
|
/* Store bitmaps for dots and markers */
|
|||
|
|
dotMap = XCreateBitmapFromData(disp, temp_win, dot_bits, dot_w, dot_h);
|
|||
|
|
|
|||
|
|
AllAttrs[0].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark1_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[1].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark2_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[2].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark3_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[3].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark4_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[4].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark5_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[5].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark6_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[6].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark7_bits, mark_w, mark_h);
|
|||
|
|
AllAttrs[7].markStyle = XCreateBitmapFromData(disp, temp_win,
|
|||
|
|
mark8_bits, mark_w, mark_h);
|
|||
|
|
XDestroyWindow(disp, temp_win);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*ARGSUSED*/
|
|||
|
|
void
|
|||
|
|
init_X(user_state)
|
|||
|
|
char *user_state;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Initializes for an X drawing sequence. Sets up drawing attributes
|
|||
|
|
* by reading values from the parameter database.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
static int initialized = 0;
|
|||
|
|
|
|||
|
|
if (!initialized) {
|
|||
|
|
init_once();
|
|||
|
|
initialized = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static GC
|
|||
|
|
textGC(t_win, t_font)
|
|||
|
|
Window t_win; /* Window for making GC */
|
|||
|
|
XFontStruct *t_font; /* Text font */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Sets the fields above in a global graphics context. If
|
|||
|
|
* the graphics context does not exist, it is created.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
static GC text_gc = (GC) 0;
|
|||
|
|
XGCValues gcvals;
|
|||
|
|
unsigned long gcmask;
|
|||
|
|
|
|||
|
|
gcvals.font = t_font->fid;
|
|||
|
|
gcmask = GCFont;
|
|||
|
|
if (text_gc == (GC) 0) {
|
|||
|
|
gcvals.foreground = PM_PIXEL("Foreground");
|
|||
|
|
gcmask |= GCForeground;
|
|||
|
|
text_gc = XCreateGC(disp, t_win, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
XChangeGC(disp, text_gc, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
return text_gc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static GC
|
|||
|
|
segGC(l_win, l_fg, l_style, l_width, l_chars, l_len)
|
|||
|
|
Window l_win; /* Window for making GC */
|
|||
|
|
Pixel l_fg; /* Foreground color */
|
|||
|
|
int l_style; /* Line style */
|
|||
|
|
int l_width; /* Line width */
|
|||
|
|
char *l_chars; /* Character spec */
|
|||
|
|
int l_len; /* Length of spec */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Sets the fields above in a global graphics context. If the
|
|||
|
|
* graphics context does not exist, it is created.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
static GC segment_gc = (GC) 0;
|
|||
|
|
XGCValues gcvals;
|
|||
|
|
unsigned long gcmask;
|
|||
|
|
|
|||
|
|
gcvals.foreground = l_fg;
|
|||
|
|
gcvals.line_style = l_style;
|
|||
|
|
gcvals.line_width = l_width;
|
|||
|
|
gcmask = GCForeground | GCLineStyle | GCLineWidth;
|
|||
|
|
if (segment_gc == (GC) 0) {
|
|||
|
|
segment_gc = XCreateGC(disp, l_win, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
XChangeGC(disp, segment_gc, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
if (l_len > 0) {
|
|||
|
|
XSetDashes(disp, segment_gc, 0, l_chars, l_len);
|
|||
|
|
}
|
|||
|
|
return segment_gc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static GC
|
|||
|
|
dotGC(d_win, d_fg, d_clipmask, d_xorg, d_yorg)
|
|||
|
|
Window d_win; /* Window for making GC */
|
|||
|
|
Pixel d_fg; /* Foreground color */
|
|||
|
|
Pixmap d_clipmask; /* Clipmask */
|
|||
|
|
int d_xorg,
|
|||
|
|
d_yorg; /* Clipmask origin */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Sets the fields above in a global graphics context. If the
|
|||
|
|
* graphics context does not exist, it is created.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
static GC dot_gc = (GC) 0;
|
|||
|
|
XGCValues gcvals;
|
|||
|
|
unsigned long gcmask;
|
|||
|
|
|
|||
|
|
gcvals.foreground = d_fg;
|
|||
|
|
gcvals.clip_mask = d_clipmask;
|
|||
|
|
gcvals.clip_x_origin = d_xorg;
|
|||
|
|
gcvals.clip_y_origin = d_yorg;
|
|||
|
|
gcmask = GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin;
|
|||
|
|
if (dot_gc == (GC) 0) {
|
|||
|
|
dot_gc = XCreateGC(disp, d_win, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
XChangeGC(disp, dot_gc, gcmask, &gcvals);
|
|||
|
|
}
|
|||
|
|
return dot_gc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
text_X(user_state, x, y, text, just, style)
|
|||
|
|
char *user_state; /* Value set in xg_init */
|
|||
|
|
int x,
|
|||
|
|
y; /* Text position (pixels) */
|
|||
|
|
char *text; /* Null terminated text */
|
|||
|
|
int just; /* Justification (above) */
|
|||
|
|
int style; /* Text style (above) */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* This routine should draw text at the indicated position using
|
|||
|
|
* the indicated justification and style. The justification refers
|
|||
|
|
* to the location of the point in reference to the text. For example,
|
|||
|
|
* if just is T_LOWERLEFT, (x,y) should be located at the lower left
|
|||
|
|
* edge of the text string.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
struct x_state *st = (struct x_state *) user_state;
|
|||
|
|
XCharStruct bb;
|
|||
|
|
int rx = 0,
|
|||
|
|
ry = 0,
|
|||
|
|
len,
|
|||
|
|
height,
|
|||
|
|
width,
|
|||
|
|
dir;
|
|||
|
|
int ascent,
|
|||
|
|
descent;
|
|||
|
|
XFontStruct *font;
|
|||
|
|
|
|||
|
|
len = strlen(text);
|
|||
|
|
font = ((style == T_TITLE) ? PM_FONT("TitleFont") : PM_FONT("LabelFont"));
|
|||
|
|
XTextExtents(font, text, len, &dir, &ascent, &descent, &bb);
|
|||
|
|
width = bb.rbearing - bb.lbearing;
|
|||
|
|
height = bb.ascent + bb.descent;
|
|||
|
|
|
|||
|
|
switch (just) {
|
|||
|
|
case T_CENTER:
|
|||
|
|
rx = x - (width / 2);
|
|||
|
|
ry = y - (height / 2);
|
|||
|
|
break;
|
|||
|
|
case T_LEFT:
|
|||
|
|
rx = x;
|
|||
|
|
ry = y - (height / 2);
|
|||
|
|
break;
|
|||
|
|
case T_UPPERLEFT:
|
|||
|
|
rx = x;
|
|||
|
|
ry = y;
|
|||
|
|
break;
|
|||
|
|
case T_TOP:
|
|||
|
|
rx = x - (width / 2);
|
|||
|
|
ry = y;
|
|||
|
|
break;
|
|||
|
|
case T_UPPERRIGHT:
|
|||
|
|
rx = x - width;
|
|||
|
|
ry = y;
|
|||
|
|
break;
|
|||
|
|
case T_RIGHT:
|
|||
|
|
rx = x - width;
|
|||
|
|
ry = y - (height / 2);
|
|||
|
|
break;
|
|||
|
|
case T_LOWERRIGHT:
|
|||
|
|
rx = x - width;
|
|||
|
|
ry = y - height;
|
|||
|
|
break;
|
|||
|
|
case T_BOTTOM:
|
|||
|
|
rx = x - (width / 2);
|
|||
|
|
ry = y - height;
|
|||
|
|
break;
|
|||
|
|
case T_LOWERLEFT:
|
|||
|
|
rx = x;
|
|||
|
|
ry = y - height;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
XDrawString(disp, st->win,
|
|||
|
|
textGC(st->win, font),
|
|||
|
|
rx, ry + bb.ascent, text, len);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
seg_X(user_state, ns, segs, width, style, lappr, color)
|
|||
|
|
char *user_state; /* Value set in xg_init */
|
|||
|
|
int ns; /* Number of segments */
|
|||
|
|
XSegment *segs; /* X array of segments */
|
|||
|
|
int width; /* Width of lines */
|
|||
|
|
int style; /* See above */
|
|||
|
|
int lappr; /* Line appearence */
|
|||
|
|
int color; /* Line color (if any) */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* This routine draws a number of line segments at the points
|
|||
|
|
* given in `seglist'. Note that contiguous segments need not share
|
|||
|
|
* endpoints but often do. All segments should be `width' devcoords wide
|
|||
|
|
* and drawn in style `style'. If `style' is L_VAR, the parameters
|
|||
|
|
* `color' and `lappr' should be used to draw the line. Both
|
|||
|
|
* parameters vary from 0 to 7. If the device is capable of
|
|||
|
|
* color, `color' varies faster than `style'. If the device
|
|||
|
|
* has no color, `style' will vary faster than `color' and
|
|||
|
|
* `color' can be safely ignored. However, if the
|
|||
|
|
* the device has more than 8 line appearences, the two can
|
|||
|
|
* be combined to specify 64 line style variations.
|
|||
|
|
* Xgraph promises not to send more than the `max_segs' in the
|
|||
|
|
* xgOut structure passed back from xg_init().
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
struct x_state *st = (struct x_state *) user_state;
|
|||
|
|
param_style ps;
|
|||
|
|
GC gc;
|
|||
|
|
|
|||
|
|
if (style == L_AXIS) {
|
|||
|
|
ps = PM_STYLE("GridStyle");
|
|||
|
|
if (ps.len < 2) {
|
|||
|
|
gc = segGC(st->win, PM_PIXEL("Foreground"),
|
|||
|
|
LineSolid, PM_INT("GridSize"), (char *) 0, 0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
gc = segGC(st->win, PM_PIXEL("Foreground"),
|
|||
|
|
LineOnOffDash, PM_INT("GridSize"),
|
|||
|
|
ps.dash_list, ps.len);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (style == L_ZERO) {
|
|||
|
|
/* Set the color and line style */
|
|||
|
|
ps = PM_STYLE("ZeroStyle");
|
|||
|
|
if (ps.len < 2) {
|
|||
|
|
gc = segGC(st->win, PM_PIXEL("ZeroColor"),
|
|||
|
|
LineSolid, PM_INT("ZeroWidth"), (char *) 0, 0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
gc = segGC(st->win, PM_PIXEL("ZeroColor"),
|
|||
|
|
LineOnOffDash, PM_INT("ZeroWidth"),
|
|||
|
|
ps.dash_list, ps.len);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
/* Color and line style vary */
|
|||
|
|
if (lappr == 0) {
|
|||
|
|
gc = segGC(st->win, AllAttrs[color].pixelValue, LineSolid,
|
|||
|
|
width, (char *) 0, 0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
gc = segGC(st->win, AllAttrs[color].pixelValue, LineOnOffDash,
|
|||
|
|
width, AllAttrs[lappr].lineStyle, AllAttrs[lappr].lineStyleLen);
|
|||
|
|
}
|
|||
|
|
/* PW */
|
|||
|
|
if (lappr == 16) {
|
|||
|
|
gc = segGC(st->win, PM_PIXEL("BackGround"), LineSolid,
|
|||
|
|
width, (char *) 0, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
XDrawSegments(disp, st->win, gc, segs, ns);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#define LAST_CHECK
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
dot_X(user_state, x, y, style, type, color)
|
|||
|
|
char *user_state; /* Value set in xg_init */
|
|||
|
|
int x,
|
|||
|
|
y; /* Location in pixel units */
|
|||
|
|
int style; /* Dot style */
|
|||
|
|
int type; /* Type of marker */
|
|||
|
|
int color; /* Marker color (if any) */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* This routine should draw a marker at location `x,y'. If the
|
|||
|
|
* style is P_PIXEL, the dot should be a single pixel. If
|
|||
|
|
* the style is P_DOT, the dot should be a reasonably large
|
|||
|
|
* dot. If the style is P_MARK, it should be a distinguished
|
|||
|
|
* mark which is specified by `type' (0-7). If the output
|
|||
|
|
* device is capable of color, the marker should be drawn in
|
|||
|
|
* `color' (0-7) which corresponds with the color for xg_line.
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
struct x_state *st = (struct x_state *) user_state;
|
|||
|
|
|
|||
|
|
switch (style) {
|
|||
|
|
case P_PIXEL:
|
|||
|
|
XDrawPoint(disp, st->win,
|
|||
|
|
dotGC(st->win, AllAttrs[color].pixelValue, (Pixmap) 0, 0, 0),
|
|||
|
|
x, y);
|
|||
|
|
break;
|
|||
|
|
case P_DOT:
|
|||
|
|
XFillRectangle(disp, st->win,
|
|||
|
|
dotGC(st->win, AllAttrs[color].pixelValue, dotMap,
|
|||
|
|
(int) (x - (dot_w >> 1)),
|
|||
|
|
(int) (y - (dot_h >> 1))),
|
|||
|
|
(int) (x - (dot_w >> 1)), (int) (y - (dot_h >> 1)),
|
|||
|
|
dot_w, dot_h);
|
|||
|
|
break;
|
|||
|
|
case P_MARK:
|
|||
|
|
XFillRectangle(disp, st->win,
|
|||
|
|
dotGC(st->win, AllAttrs[color].pixelValue,
|
|||
|
|
AllAttrs[type].markStyle,
|
|||
|
|
(int) (x - mark_cx),
|
|||
|
|
(int) (y - mark_cy)),
|
|||
|
|
(int) (x - mark_cx), (int) (y - mark_cy),
|
|||
|
|
mark_w, mark_h);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|