1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
|
/* This implementation is for XDrawablePlotters. It supports one or two
drawables, which must be associated with the same display and have the
same dimensions (width, height, depth). A `drawable' is either a window
or a pixmap. */
/* This file also contains the internal functions _x_maybe_get_new_colormap
and _x_maybe_handle_x_events, which are no-ops. However, they are
virtual and are overridden in the derived XPlotter class, which both
attempts to switch to a private colormap when color cells run out, and
processes its own X events. */
#include "sys-defines.h"
#include "extern.h"
bool
#ifdef _HAVE_PROTOS
_x_begin_page (S___(Plotter *_plotter))
#else
_x_begin_page (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
Window root1, root2;
int x, y;
unsigned int border_width, depth1, depth2;
unsigned int width1, height1, width2, height2;
unsigned int width, height, depth;
const char *double_buffer_s;
if (_plotter->x_dpy == (Display *)NULL)
/* pathological: user didn't set XDRAWABLE_DISPLAY parameter */
{
_plotter->error (R___(_plotter) "can't open Plotter, XDRAWABLE_DISPLAY parameter is null");
return false;
}
/* find out how long polylines can get on this X display */
_plotter->x_max_polyline_len = XMaxRequestSize(_plotter->x_dpy) / 2;
/* determine dimensions of drawable(s) */
if (_plotter->x_drawable1)
XGetGeometry (_plotter->x_dpy, _plotter->x_drawable1,
&root1, &x, &y, &width1, &height1, &border_width, &depth1);
if (_plotter->x_drawable2)
XGetGeometry (_plotter->x_dpy, _plotter->x_drawable2,
&root2, &x, &y, &width2, &height2, &border_width, &depth2);
if (_plotter->x_drawable1 && _plotter->x_drawable2)
/* sanity check */
{
if (width1 != width2 || height1 != height2
|| depth1 != depth2 || root1 != root2)
{
_plotter->error(R___(_plotter) "can't open Plotter, X drawables have unequal parameters");
return false;
}
}
if (_plotter->x_drawable1)
{
width = width1;
height = height1;
depth = depth1;
}
else if (_plotter->x_drawable2)
{
width = width2;
height = height2;
depth = depth1;
}
else
/* both are NULL, and we won't really be drawing, so these are irrelevant */
{
width = 1;
height = 1;
depth = 1;
}
_plotter->data->imin = 0;
_plotter->data->imax = width - 1;
/* note flipped-y convention for this device: for j, min > max */
_plotter->data->jmin = height - 1;
_plotter->data->jmax = 0;
/* compute the NDC to device-frame affine map, set it in Plotter */
_compute_ndc_to_device_map (_plotter->data);
/* add X GC's to drawing state (which was constructed by openpl() before
begin_page() was called), so we can at least fill with solid color */
_x_add_gcs_to_first_drawing_state (S___(_plotter));
/* At this point, we don't clear the drawable(s) by filling them with the
background color, which is what we would do here for an X Plotter (see
y_openpl.c). For an X DrawablePlotter, unlike an X Plotter, initial
clearing is not appropriate. However, if we're double buffering, we
create an off-screen buffer and fill it with the color. */
if (_plotter->x_drawable1 || _plotter->x_drawable2)
{
double_buffer_s =
(const char *)_get_plot_param (_plotter->data, "USE_DOUBLE_BUFFERING");
if (strcmp (double_buffer_s, "yes") == 0
/* backward compatibility: "fast" now means the same as "yes" */
|| strcmp (double_buffer_s, "fast") == 0)
/* user requested double buffering, so do so `by hand': allocate
additional pixmap to serve as off-screen graphics buffer */
{
_plotter->x_double_buffering = DBL_BY_HAND;
_plotter->x_drawable3
= XCreatePixmap(_plotter->x_dpy,
/* this 2nd arg merely determines the screen*/
_plotter->x_drawable1 ?
_plotter->x_drawable1 : _plotter->x_drawable2,
(unsigned int)width,
(unsigned int)height,
(unsigned int)depth);
/* erase buffer by filling it with background color */
XFillRectangle (_plotter->x_dpy, _plotter->x_drawable3,
_plotter->drawstate->x_gc_bg,
/* upper left corner */
0, 0,
(unsigned int)width, (unsigned int)height);
}
}
/* Note: at this point the drawing state, which we added X GC's to, a few
lines above, won't be ready for drawing graphics, since it won't
contain an X font or meaningful line width. To retrieve an X font and
set the line width, user will need to invoke space() after openpl(). */
return true;
}
/* Flesh out an XDrawable or X Plotter's first drawing state, by adding
X11-specific elements: GC's or lists. This is invoked by the
corresponding begin_page() routines, and hence by openpl().
As supplemented, the drawing state won't be fully ready for drawing
graphics, since it won't contain a X font. However, the the API
function alabel(), before drawing a text string, invokes _set_font(),
which in turns invokes the Plotter-specific function retrieve_font().
And x_retrieve_font() does the job of retrieving an X font from the
server and placing it in the drawing state. */
void
#ifdef _HAVE_PROTOS
_x_add_gcs_to_first_drawing_state (S___(Plotter *_plotter))
#else
_x_add_gcs_to_first_drawing_state (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
Drawable drawable;
/* determine which if either drawable we'll construct the GC's for */
if (_plotter->x_drawable1)
drawable = _plotter->x_drawable1;
else if (_plotter->x_drawable2)
drawable = _plotter->x_drawable2;
else
drawable = (Drawable)NULL;
if (drawable != (Drawable)NULL)
/* prepare GC's for new drawing state, by copying attributes we use */
{
unsigned long gcmask_fg, gcmask_fill, gcmask_bg;
gcmask_fg =
/* constant attributes (never altered) */
GCPlaneMask | GCFunction
/* drawing attributes set by _x_set_attributes() */
/* NOTE: we also use GCDashOffset and GCDashList, but Xlib does not
support retrieving the dash list from a GC, so we'll copy the
dashing style in another (painful) way */
| GCLineStyle | GCLineWidth | GCJoinStyle | GCCapStyle
/* other GC elements set by the X Drawable driver */
| GCForeground | GCFont;
gcmask_fill =
/* constant attributes (never altered) */
GCPlaneMask | GCFunction | GCArcMode
/* filling attributes set by _x_set_attributes() */
| GCFillRule
/* other GC elements set by the X Drawable driver */
| GCForeground;
gcmask_bg =
/* constant attributes (never altered) */
GCPlaneMask | GCFunction
/* other GC elements set by the X Drawable driver */
| GCForeground;
/* build new GC's from scratch */
{
XGCValues gcv_fg, gcv_fill, gcv_bg;
/* Initialize GC used for drawing. (Always initialize the line
style to LineSolid, irrespective of what the default drawing
state contains; it would be silly for the default drawing state
to include a non-solid value for the line style.) */
gcv_fg.plane_mask = AllPlanes;
gcv_fg.function = GXcopy;
gcv_fg.line_width = _default_drawstate.x_gc_line_width;
gcv_fg.line_style = LineSolid;
gcv_fg.join_style = _default_drawstate.x_gc_join_style;
gcv_fg.cap_style = _default_drawstate.x_gc_cap_style;
gcmask_fg &= ~(GCFont); /* initialized much later; see below */
gcmask_fg &= ~(GCForeground); /* color is initialized separately */
/* initialize GC used for filling */
gcv_fill.plane_mask = AllPlanes;
gcv_fill.function = GXcopy;
gcv_fill.arc_mode = ArcChord; /* libplot convention */
gcv_fill.fill_rule = _default_drawstate.x_gc_fill_rule;
gcmask_fill &= ~(GCForeground); /* color is initialized separately */
/* initialize GC used for erasing */
gcv_bg.plane_mask = AllPlanes;
gcv_bg.function = GXcopy;
gcmask_bg &= ~(GCForeground); /* color is initialized separately */
/* create the 3 GC's */
_plotter->drawstate->x_gc_fg =
XCreateGC (_plotter->x_dpy, drawable, gcmask_fg, &gcv_fg);
_plotter->drawstate->x_gc_fill =
XCreateGC (_plotter->x_dpy, drawable, gcmask_fill, &gcv_fill);
_plotter->drawstate->x_gc_bg =
XCreateGC (_plotter->x_dpy, drawable, gcmask_bg, &gcv_bg);
/* set X-specific elements in the drawing state, specifying
(non-opaquely) what the 3 GC's contain */
_plotter->drawstate->x_gc_line_width = gcv_fg.line_width;
_plotter->drawstate->x_gc_line_style = gcv_fg.line_style;
_plotter->drawstate->x_gc_join_style = gcv_fg.join_style;
_plotter->drawstate->x_gc_cap_style = gcv_fg.cap_style;
_plotter->drawstate->x_gc_dash_list = (char *)NULL;
_plotter->drawstate->x_gc_dash_list_len = 0;
_plotter->drawstate->x_gc_dash_offset = 0;
_plotter->drawstate->x_gc_fill_rule = gcv_fill.fill_rule;
/* do the separate initialization of color (i.e. GCForeground
element) in each GC */
_x_set_pen_color (S___(_plotter));
_x_set_fill_color (S___(_plotter));
_x_set_bg_color (S___(_plotter));
/* At this point, all 3 GC's are functional, except the GC used
for drawing lacks a GCFont element.
We do not retrieve a font from the X server here; not even a
default font. fsetmatrix() or space(), when invoked (which we
require after each invocation of openpl()), will select a
default size for the font. A font will be retrieved from the X
server only when fontname/fontsize/textangle is invoked to
select a different font, or when alabel/labelwidth is invoked
(see g_alabel.c).
The invocation of fsetmatrix() or space() will also set the line
width in the drawing state. Any changed attributes, such as
line width, will be written to the GC's just before drawing; see
g_attribs.c. */
}
}
}
/* This is the XDrawablePlotter-specific version of the
_maybe_get_new_colormap() method, which is invoked when a Plotter's
original colormap fills up. It's a no-op; in XPlotters, it's overridden
by a version that actually does something. */
void
#ifdef _HAVE_PROTOS
_x_maybe_get_new_colormap (S___(Plotter *_plotter))
#else
_x_maybe_get_new_colormap (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
return;
}
/* This is the XDrawablePlotter-specific version of the
_maybe_handle_x_events() method, which is invoked after most drawing
operations. It's a no-ope; in XPlotters, it's overridden by a version
that actually does something. */
void
#ifdef _HAVE_PROTOS
_x_maybe_handle_x_events(S___(Plotter *_plotter))
#else
_x_maybe_handle_x_events(S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
return;
}
|