File: x_openpl.c

package info (click to toggle)
plotutils 2.4.1-15
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 11,072 kB
  • ctags: 6,952
  • sloc: ansic: 76,305; cpp: 12,402; sh: 8,475; yacc: 2,604; makefile: 894; lex: 144
file content (295 lines) | stat: -rw-r--r-- 10,593 bytes parent folder | download | duplicates (3)
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;
}