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
|
/* This version is for XPlotters, and should be exactly the same as
x_erase.c (the version for XDrawablePlotters) except XPlotter-specific
lines are NOT commented out. (Search for #if 1...#endif.) */
#include "sys-defines.h"
#include "extern.h"
/* If we aren't double buffering, this is the number of
most-recently-allocated color cells that we _don't_ deallocate when we
do an erase(). This is a heuristic. This quantity must be >= 0. */
#define NUM_KEPT_COLORS 256
/* If we're doing double buffering, when we do an erase() we of course
don't deallocate the color cells that were used in the current frame.
We also don't deallocate the cells used in the previous NUM_KEPT_FRAMES
frames. This is a heuristic. This quantity must be >= 0. */
#define NUM_KEPT_FRAMES 16
bool
#ifdef _HAVE_PROTOS
_y_erase_page (S___(Plotter *_plotter))
#else
_y_erase_page (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
bool head_found;
int window_width, window_height;
int i, current_frame_number, current_page_number;
plColorRecord *cptr, **link = NULL;
plDrawState *stateptr;
/* set the foreground color in the GC we use for erasing,
to be the background color in the drawing state */
_x_set_bg_color (S___(_plotter));
/* compute rectangle size; note flipped-y convention */
window_width = (_plotter->data->imax - _plotter->data->imin) + 1;
window_height = (_plotter->data->jmin - _plotter->data->jmax) + 1;
if (_plotter->x_double_buffering != DBL_NONE)
{
/* Following two sorts of server-supported double buffering
(DBL_DBE, DBL_MBX) are possible only for X Plotters, not
X Drawable Plotters. `By hand' double buffering is possible
for both. */
#if 1
#ifdef HAVE_X11_EXTENSIONS_XDBE_H
#ifdef HAVE_DBE_SUPPORT
if (_plotter->x_double_buffering == DBL_DBE)
/* we're using the X double buffering extension */
{
XdbeSwapInfo info;
/* Copy current frame of buffered graphics to window. Implement
this by swapping the front and back buffers for widget's
window. Former front buffer will become graphics buffer.
Currently, the buffers are `x_drawable2' (front) and `x_drawable3'
(back, into which we draw). */
info.swap_window = _plotter->x_drawable2;
info.swap_action = XdbeUndefined;
XdbeSwapBuffers (_plotter->x_dpy, &info, 1);
}
else
#endif /* HAVE_DBE_SUPPORT */
#endif /* HAVE_X11_EXTENSIONS_XDBE_H */
#ifdef HAVE_X11_EXTENSIONS_MULTIBUF_H
#ifdef HAVE_MBX_SUPPORT
if (_plotter->x_double_buffering == DBL_MBX)
/* we're using the X multibuffering extension */
{
Multibuffer multibuf;
/* Copy current frame of buffered graphics to window. Implement
this by making multibuffer into which we've been drawing the
current multibuffer. */
XmbufDisplayBuffers (_plotter->x_dpy, 1, &(_plotter->x_drawable3), 0, 0);
/* swap the two multibuffers, making the other one the off-screen
graphics buffer into which we draw (`x_drawable3') */
multibuf = _plotter->x_drawable3;
_plotter->x_drawable3 = _plotter->y_drawable4;
_plotter->y_drawable4 = multibuf;
}
else
#endif /* HAVE_MBX_SUPPORT */
#endif /* HAVE_X11_EXTENSIONS_MULTIBUF_H */
#endif /* 1 */
/* we must be doing double buffering `by hand', rather than using
an X protocol extension */
if (_plotter->x_double_buffering == DBL_BY_HAND)
{
/* copy current frame of buffered graphics to drawable(s) */
if (_plotter->x_drawable1)
XCopyArea (_plotter->x_dpy,
_plotter->x_drawable3, _plotter->x_drawable1,
_plotter->drawstate->x_gc_bg,
0, 0,
(unsigned int)window_width,
(unsigned int)window_height,
0, 0);
if (_plotter->x_drawable2)
XCopyArea (_plotter->x_dpy,
_plotter->x_drawable3, _plotter->x_drawable2,
_plotter->drawstate->x_gc_bg,
0, 0,
(unsigned int)window_width,
(unsigned int)window_height,
0, 0);
}
/* irrespective of which of the three sorts of double buffering is
being performed, clear the (new) graphics 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)window_width,
(unsigned int)window_height);
}
else
/* not double buffering at all */
{
/* erase drawable(s) by filling with background color */
if (_plotter->x_drawable1)
XFillRectangle (_plotter->x_dpy, _plotter->x_drawable1,
_plotter->drawstate->x_gc_bg,
/* upper left corner */
0, 0,
(unsigned int)window_width, (unsigned int)window_height);
if (_plotter->x_drawable2)
XFillRectangle (_plotter->x_dpy, _plotter->x_drawable2,
_plotter->drawstate->x_gc_bg,
/* upper left corner */
0, 0,
(unsigned int)window_width, (unsigned int)window_height);
}
#if 1
/* If an X Plotter, update background color of y_canvas widget,
irrespective of whether or not we're double buffering. This fixes
things so that if the window is resized to a larger size, the new
portions of the window will be filled with the correct color. */
{
Arg wargs[1]; /* werewolves */
#ifdef USE_MOTIF
XtSetArg (wargs[0], XmNbackground, _plotter->drawstate->x_gc_bgcolor);
#else
XtSetArg (wargs[0], XtNbackground, _plotter->drawstate->x_gc_bgcolor);
#endif
XtSetValues (_plotter->y_toplevel, wargs, (Cardinal)1);
XtSetValues (_plotter->y_canvas, wargs, (Cardinal)1);
}
#endif /* 1 */
/* Flush the color cell cache, to the extent we can. But heuristically,
keep in the cache a certain number of cells that aren't strictly
needed, but which may be needed in the following frames. There are
two cases.
1. If we're not double buffering, preserve some maximum number
(NUM_KEPT_COLORS) of the most recently allocated cells.
Implementing the cache as a list, though suboptimal from the
point of view of speed, makes it easy to implement this heuristic.
2. If we're double buffering, preserve all cells that were used
in the present frame (which was just transferred to the
drawable(s), e.g., to an on-screen window). This is mandatory.
But also use a heuristic: preserve all cells used in the
preceding NUM_KEPT_FRAMES frames.
In both cases, if a cached cell is to be preserved, it must contain a
genuine pixel value (the `allocated' flag must be set).
We also insist that for a cell to be preserved, it have a `page number
stamp' equal to the current page number. That's because XDrawable
Plotters, unlike X Plotters, don't free the color cell cache in
end_page(), i.e., when closepl() is called. That's because X Drawable
Plotters are `persistent' in the sense the graphics remain visible
until the next reopening, and beyond. So the cache may include cells
left over from previous pages, which get freed only here, when erase()
is called. */
cptr = _plotter->x_colorlist;
_plotter->x_colorlist = NULL;
i = 0;
head_found = false;
current_frame_number = _plotter->data->frame_number;
current_page_number = _plotter->data->page_number;
while (cptr)
{
plColorRecord *cptrnext;
cptrnext = cptr->next;
if (cptr->allocated)
{
if ((_plotter->x_double_buffering == DBL_NONE
&& cptr->page_number == current_page_number
&& i < NUM_KEPT_COLORS)
||
(_plotter->x_double_buffering != DBL_NONE
&& cptr->page_number == current_page_number
&& cptr->frame_number >= current_frame_number - NUM_KEPT_FRAMES))
/* cached cell contains a genuine pixel value, and it meets our
criteria, so preserve it */
{
if (head_found)
*link = cptr;
else
{
_plotter->x_colorlist = cptr;
head_found = true;
}
cptr->next = NULL;
link = &(cptr->next);
i++;
}
else
/* cached cell contains a genuine pixel value, but it doesn't
meet our criteria, so deallocate it */
{
XFreeColors (_plotter->x_dpy, _plotter->x_cmap,
&(cptr->rgb.pixel), 1, (unsigned long)0);
free (cptr);
}
}
else
/* cached cell doesn't include a genuine pixel value, so free it */
free (cptr);
cptr = cptrnext;
}
/* flag status of all colors in GC's in the drawing state stack as false
(on account of flushing, may need to be searched for or reallocated) */
for (stateptr = _plotter->drawstate; stateptr; stateptr = stateptr->previous)
{
stateptr->x_gc_fgcolor_status = false;
stateptr->x_gc_fillcolor_status = false;
stateptr->x_gc_bgcolor_status = false;
}
/* maybe flush X output buffer and handle X events (a no-op for
XDrawablePlotters, which is overridden for XPlotters) */
_maybe_handle_x_events (S___(_plotter));
return true;
}
|