1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This version is for XPlotters, and should be exactly the same as
20 x_erase.c (the version for XDrawablePlotters) except XPlotter-specific
21 lines are NOT commented out. (Search for #if 1...#endif.) */
22
23 #include "sys-defines.h"
24 #include "extern.h"
25
26 /* If we aren't double buffering, this is the number of
27 most-recently-allocated color cells that we _don't_ deallocate when we
28 do an erase(). This is a heuristic. This quantity must be >= 0. */
29 #define NUM_KEPT_COLORS 256
30
31 /* If we're doing double buffering, when we do an erase() we of course
32 don't deallocate the color cells that were used in the current frame.
33 We also don't deallocate the cells used in the previous NUM_KEPT_FRAMES
34 frames. This is a heuristic. This quantity must be >= 0. */
35 #define NUM_KEPT_FRAMES 16
36
37 bool
_pl_y_erase_page(S___ (Plotter * _plotter))38 _pl_y_erase_page (S___(Plotter *_plotter))
39 {
40 bool head_found;
41 int window_width, window_height;
42 int i, current_frame_number, current_page_number;
43 plColorRecord *cptr, **link = NULL;
44 plDrawState *stateptr;
45
46 /* set the foreground color in the GC we use for erasing,
47 to be the background color in the drawing state */
48 _pl_x_set_bg_color (S___(_plotter));
49
50 /* compute rectangle size; note flipped-y convention */
51 window_width = (_plotter->data->imax - _plotter->data->imin) + 1;
52 window_height = (_plotter->data->jmin - _plotter->data->jmax) + 1;
53
54 if (_plotter->x_double_buffering != X_DBL_BUF_NONE)
55 {
56 /* Following two sorts of server-supported double buffering
57 (X_DBL_BUF_DBE, X_DBL_BUF_MBX) are possible only for X Plotters, not
58 X Drawable Plotters. `By hand' double buffering is possible
59 for both. */
60
61 #if 1
62 #ifdef HAVE_X11_EXTENSIONS_XDBE_H
63 #ifdef HAVE_DBE_SUPPORT
64 if (_plotter->x_double_buffering == X_DBL_BUF_DBE)
65 /* we're using the X double buffering extension */
66 {
67 XdbeSwapInfo info;
68
69 /* Copy current frame of buffered graphics to window. Implement
70 this by swapping the front and back buffers for widget's
71 window. Former front buffer will become graphics buffer.
72 Currently, the buffers are `x_drawable2' (front) and `x_drawable3'
73 (back, into which we draw). */
74 info.swap_window = _plotter->x_drawable2;
75 info.swap_action = XdbeUndefined;
76 XdbeSwapBuffers (_plotter->x_dpy, &info, 1);
77 }
78 else
79 #endif /* HAVE_DBE_SUPPORT */
80 #endif /* HAVE_X11_EXTENSIONS_XDBE_H */
81
82 #ifdef HAVE_X11_EXTENSIONS_MULTIBUF_H
83 #ifdef HAVE_MBX_SUPPORT
84 if (_plotter->x_double_buffering == X_DBL_BUF_MBX)
85 /* we're using the X multibuffering extension */
86 {
87 Multibuffer multibuf;
88
89 /* Copy current frame of buffered graphics to window. Implement
90 this by making multibuffer into which we've been drawing the
91 current multibuffer. */
92 XmbufDisplayBuffers (_plotter->x_dpy, 1, &(_plotter->x_drawable3), 0, 0);
93
94 /* swap the two multibuffers, making the other one the off-screen
95 graphics buffer into which we draw (`x_drawable3') */
96 multibuf = _plotter->x_drawable3;
97 _plotter->x_drawable3 = _plotter->y_drawable4;
98 _plotter->y_drawable4 = multibuf;
99 }
100 else
101 #endif /* HAVE_MBX_SUPPORT */
102 #endif /* HAVE_X11_EXTENSIONS_MULTIBUF_H */
103 #endif /* 1 */
104
105 /* we must be doing double buffering `by hand', rather than using
106 an X protocol extension */
107 if (_plotter->x_double_buffering == X_DBL_BUF_BY_HAND)
108 {
109 /* copy current frame of buffered graphics to drawable(s) */
110 if (_plotter->x_drawable1)
111 XCopyArea (_plotter->x_dpy,
112 _plotter->x_drawable3, _plotter->x_drawable1,
113 _plotter->drawstate->x_gc_bg,
114 0, 0,
115 (unsigned int)window_width,
116 (unsigned int)window_height,
117 0, 0);
118 if (_plotter->x_drawable2)
119 XCopyArea (_plotter->x_dpy,
120 _plotter->x_drawable3, _plotter->x_drawable2,
121 _plotter->drawstate->x_gc_bg,
122 0, 0,
123 (unsigned int)window_width,
124 (unsigned int)window_height,
125 0, 0);
126 }
127
128 /* irrespective of which of the three sorts of double buffering is
129 being performed, clear the (new) graphics buffer, by filling it
130 with background color */
131 XFillRectangle (_plotter->x_dpy, _plotter->x_drawable3,
132 _plotter->drawstate->x_gc_bg,
133 /* upper left corner */
134 0, 0,
135 (unsigned int)window_width,
136 (unsigned int)window_height);
137 }
138 else
139 /* not double buffering at all */
140 {
141 /* erase drawable(s) by filling with background color */
142 if (_plotter->x_drawable1)
143 XFillRectangle (_plotter->x_dpy, _plotter->x_drawable1,
144 _plotter->drawstate->x_gc_bg,
145 /* upper left corner */
146 0, 0,
147 (unsigned int)window_width, (unsigned int)window_height);
148 if (_plotter->x_drawable2)
149 XFillRectangle (_plotter->x_dpy, _plotter->x_drawable2,
150 _plotter->drawstate->x_gc_bg,
151 /* upper left corner */
152 0, 0,
153 (unsigned int)window_width, (unsigned int)window_height);
154 }
155
156 #if 1
157 /* If an X Plotter, update background color of y_canvas widget,
158 irrespective of whether or not we're double buffering. This fixes
159 things so that if the window is resized to a larger size, the new
160 portions of the window will be filled with the correct color. */
161 {
162 Arg wargs[1]; /* werewolves */
163
164 #ifdef USE_MOTIF
165 XtSetArg (wargs[0], XmNbackground, _plotter->drawstate->x_gc_bgcolor);
166 #else
167 XtSetArg (wargs[0], XtNbackground, _plotter->drawstate->x_gc_bgcolor);
168 #endif
169 XtSetValues (_plotter->y_toplevel, wargs, (Cardinal)1);
170 XtSetValues (_plotter->y_canvas, wargs, (Cardinal)1);
171 }
172 #endif /* 1 */
173
174 /* Flush the color cell cache, to the extent we can. But heuristically,
175 keep in the cache a certain number of cells that aren't strictly
176 needed, but which may be needed in the following frames. There are
177 two cases.
178
179 1. If we're not double buffering, preserve some maximum number
180 (NUM_KEPT_COLORS) of the most recently allocated cells.
181 Implementing the cache as a list, though suboptimal from the
182 point of view of speed, makes it easy to implement this heuristic.
183 2. If we're double buffering, preserve all cells that were used
184 in the present frame (which was just transferred to the
185 drawable(s), e.g., to an on-screen window). This is mandatory.
186 But also use a heuristic: preserve all cells used in the
187 preceding NUM_KEPT_FRAMES frames.
188
189 In both cases, if a cached cell is to be preserved, it must contain a
190 genuine pixel value (the `allocated' flag must be set).
191
192 We also insist that for a cell to be preserved, it have a `page number
193 stamp' equal to the current page number. That's because XDrawable
194 Plotters, unlike X Plotters, don't free the color cell cache in
195 end_page(), i.e., when closepl() is called. That's because X Drawable
196 Plotters are `persistent' in the sense the graphics remain visible
197 until the next reopening, and beyond. So the cache may include cells
198 left over from previous pages, which get freed only here, when erase()
199 is called. */
200
201 cptr = _plotter->x_colorlist;
202 _plotter->x_colorlist = NULL;
203 i = 0;
204 head_found = false;
205 current_frame_number = _plotter->data->frame_number;
206 current_page_number = _plotter->data->page_number;
207 while (cptr)
208 {
209 plColorRecord *cptrnext;
210
211 cptrnext = cptr->next;
212 if (cptr->allocated)
213 {
214 if ((_plotter->x_double_buffering == X_DBL_BUF_NONE
215 && cptr->page_number == current_page_number
216 && i < NUM_KEPT_COLORS)
217 ||
218 (_plotter->x_double_buffering != X_DBL_BUF_NONE
219 && cptr->page_number == current_page_number
220 && cptr->frame_number >= current_frame_number - NUM_KEPT_FRAMES))
221 /* cached cell contains a genuine pixel value, and it meets our
222 criteria, so preserve it */
223 {
224 if (head_found)
225 *link = cptr;
226 else
227 {
228 _plotter->x_colorlist = cptr;
229 head_found = true;
230 }
231
232 cptr->next = NULL;
233 link = &(cptr->next);
234 i++;
235 }
236 else
237 /* cached cell contains a genuine pixel value, but it doesn't
238 meet our criteria, so deallocate it */
239 {
240 XFreeColors (_plotter->x_dpy, _plotter->x_cmap,
241 &(cptr->rgb.pixel), 1, (unsigned long)0);
242 free (cptr);
243 }
244 }
245 else
246 /* cached cell doesn't include a genuine pixel value, so free it */
247 free (cptr);
248
249 cptr = cptrnext;
250 }
251
252 /* flag status of all colors in GC's in the drawing state stack as false
253 (on account of flushing, may need to be searched for or reallocated) */
254 for (stateptr = _plotter->drawstate; stateptr; stateptr = stateptr->previous)
255 {
256 stateptr->x_gc_fgcolor_status = false;
257 stateptr->x_gc_fillcolor_status = false;
258 stateptr->x_gc_bgcolor_status = false;
259 }
260
261 /* maybe flush X output buffer and handle X events (a no-op for
262 XDrawablePlotters, which is overridden for XPlotters) */
263 _maybe_handle_x_events (S___(_plotter));
264
265 return true;
266 }
267