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