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 file defines the initialization for any XPlotter object, including
20    both private data and public methods.  There is a one-to-one
21    correspondence between public methods and user-callable functions in the
22    C API. */
23 
24 #include "sys-defines.h"
25 #include <signal.h>		/* for kill() */
26 #include "extern.h"
27 
28 /* Sparse array of pointers to XPlotter instances, and its size.  Should be
29    initialized to a NULL pointer, and 0, respectively.
30 
31    In libplotter these are not global variables: in extern.h, they are
32    #define'd to be static data members of the XPlotter class.
33 
34    Accessed by _pl_y_initialize() and _pl_y_terminate() in this file, by
35    _pl_y_maybe_handle_x_events() in y_openpl.c, and by _pl_y_closepl() in
36    y_closepl.c. */
37 
38 XPlotter **_xplotters = NULL;
39 int _xplotters_len = 0;
40 
41 /* initial size for "_xplotters", the sparse array of XPlotter instances */
42 #define INITIAL_XPLOTTERS_LEN 4
43 
44 /* Mutex for locking _xplotters[] and _xplotters_len. */
45 #ifdef PTHREAD_SUPPORT
46 #ifdef HAVE_PTHREAD_H
47 pthread_mutex_t _xplotters_mutex = PTHREAD_MUTEX_INITIALIZER;
48 #endif
49 #endif
50 
51 #ifndef LIBPLOTTER
52 /* In libplot, this is the initialization for the function-pointer part of
53    an XPlotter struct. */
54 const Plotter _pl_y_default_plotter =
55 {
56   /* initialization (after creation) and termination (before deletion) */
57   _pl_y_initialize, _pl_y_terminate,
58   /* page manipulation */
59   _pl_y_begin_page, _pl_y_erase_page, _pl_y_end_page,
60   /* drawing state manipulation */
61   _pl_x_push_state, _pl_x_pop_state,
62   /* internal path-painting methods (endpath() is a wrapper for the first) */
63   _pl_x_paint_path, _pl_x_paint_paths, _pl_x_path_is_flushable, _pl_x_maybe_prepaint_segments,
64   /* internal methods for drawing of markers and points */
65   _pl_g_paint_marker, _pl_x_paint_point,
66   /* internal methods that plot strings in Hershey, non-Hershey fonts */
67   _pl_g_paint_text_string_with_escapes, _pl_x_paint_text_string,
68   _pl_x_get_text_width,
69   /* private low-level `retrieve font' method */
70   _pl_x_retrieve_font,
71   /* `flush output' method, called only if Plotter handles its own output */
72   _pl_x_flush_output,
73   /* internal error handlers */
74   _pl_g_warning,
75   _pl_g_error,
76 };
77 #endif /* not LIBPLOTTER */
78 
79 /* The private `initialize' method, which is invoked when a Plotter is
80    created.  It is used for such things as initializing capability flags
81    from the values of class variables, allocating storage, etc.  When this
82    is invoked, _plotter points to the Plotter that has just been
83    created. */
84 
85 void
_pl_y_initialize(S___ (Plotter * _plotter))86 _pl_y_initialize (S___(Plotter *_plotter))
87 {
88   bool open_slot = false;
89   int i, j;
90 
91 #ifndef LIBPLOTTER
92   /* in libplot, manually invoke superclass initialization method */
93   _pl_x_initialize (S___(_plotter));
94 #endif
95 
96 #ifdef PTHREAD_SUPPORT
97 #ifdef HAVE_PTHREAD_H
98   /* lock the global variables _xplotters[] and _xplotters_len */
99   pthread_mutex_lock (&_xplotters_mutex);
100 #endif
101 #endif
102 
103   /* If this is the first XPlotter to be created, initialize Xt library.
104      At least in X11R6, it's OK to initialize it more than once, but we're
105      careful. */
106   if (_xplotters_len == 0)
107     {
108       /* first initialize Xlib and Xt thread support if any */
109 #ifdef PTHREAD_SUPPORT
110 #ifdef HAVE_PTHREAD_H
111 #ifdef X_THREAD_SUPPORT
112       XInitThreads ();
113       XtToolkitThreadInitialize ();
114 #endif
115 #endif
116 #endif
117       /* initialize Xt library itself */
118       XtToolkitInitialize ();
119     }
120 
121   /* ensure XPlotter array is set up */
122   if (_xplotters_len == 0)
123     {
124       _xplotters = (XPlotter **)_pl_xmalloc (INITIAL_XPLOTTERS_LEN * sizeof(XPlotter *));
125       for (i = 0; i < INITIAL_XPLOTTERS_LEN; i++)
126 	_xplotters[i] = (XPlotter *)NULL;
127       _xplotters_len = INITIAL_XPLOTTERS_LEN;
128     }
129 
130   /* be sure there is an open slot (slot i) */
131   for (i = 0; i < _xplotters_len; i++)
132     if (_xplotters[i] == NULL)
133       {
134 	open_slot = true;
135 	break;
136       }
137   if (!open_slot)
138     /* expand array, clearing upper half */
139     {
140       i = _xplotters_len;
141       _xplotters =
142 	(XPlotter **)_pl_xrealloc (_xplotters,
143 				    2 * _xplotters_len * sizeof (XPlotter *));
144       for (j = _xplotters_len; j < 2 * _xplotters_len; j++)
145 	_xplotters[j] = (XPlotter *)NULL;
146       _xplotters_len *= 2;
147     }
148 
149   /* place just-created Plotter in open slot */
150   _xplotters[i] = _plotter;
151 
152 #ifdef PTHREAD_SUPPORT
153 #ifdef HAVE_PTHREAD_H
154   /* unlock the global variables _xplotters[] and _xplotters_len */
155   pthread_mutex_unlock (&_xplotters_mutex);
156 #endif
157 #endif
158 
159   /* override superclass initializations, as necessary */
160 
161 #ifndef LIBPLOTTER
162   /* tag field, differs in derived classes */
163   _plotter->data->type = PL_X11;
164 #endif
165 
166   /* output model */
167   _plotter->data->output_model = PL_OUTPUT_VIA_CUSTOM_ROUTINES_TO_NON_STREAM;
168 
169   /* initialize data members specific to this derived class */
170   _plotter->y_app_con = (XtAppContext)NULL;
171   _plotter->y_toplevel = (Widget)NULL;
172   _plotter->y_canvas = (Widget)NULL;
173   _plotter->y_drawable4 = (Drawable)0;
174   _plotter->y_auto_flush = true;
175   _plotter->y_vanish_on_delete = false;
176   _plotter->y_pids = (pid_t *)NULL;
177   _plotter->y_num_pids = 0;
178   _plotter->y_event_handler_count = 0;
179 
180   /* initialize certain data members from device driver parameters */
181 
182   /* determine whether to do an XFlush() after each drawing operation */
183   {
184     const char *vanish_s;
185 
186     vanish_s = (const char *)_get_plot_param (_plotter->data,
187 					      "X_AUTO_FLUSH");
188     if (strcasecmp (vanish_s, "no") == 0)
189       _plotter->y_auto_flush = false;
190     else
191       _plotter->y_auto_flush = true;
192   }
193 
194   /* determine whether windows vanish on Plotter deletion */
195   {
196     const char *vanish_s;
197 
198     vanish_s = (const char *)_get_plot_param (_plotter->data,
199 					      "VANISH_ON_DELETE");
200     if (strcasecmp (vanish_s, "yes") == 0)
201       _plotter->y_vanish_on_delete = true;
202     else
203       _plotter->y_vanish_on_delete = false;
204   }
205 
206 }
207 
208 /* The private `terminate' method, which is invoked when a Plotter is
209    deleted.  It may do such things as write to an output stream from
210    internal storage, deallocate storage, etc.  When this is invoked,
211    _plotter points to the Plotter that is about to be deleted. */
212 
213 void
_pl_y_terminate(S___ (Plotter * _plotter))214 _pl_y_terminate (S___(Plotter *_plotter))
215 {
216   int i, j;
217 
218   /* kill forked-off processes that are maintaining XPlotter's popped-up
219      windows, provided that the VANISH_ON_DELETE parameter was set to "yes"
220      at creation time */
221   if (_plotter->y_vanish_on_delete)
222     {
223       for (j = 0; j < _plotter->y_num_pids; j++)
224 	kill (_plotter->y_pids[j], SIGKILL);
225       if (_plotter->y_num_pids > 0)
226 	{
227 	  free (_plotter->y_pids);
228 	  _plotter->y_pids = (pid_t *)NULL;
229 	}
230     }
231 
232   /* remove XPlotter from sparse XPlotter array */
233 
234 #ifdef PTHREAD_SUPPORT
235 #ifdef HAVE_PTHREAD_H
236   /* lock the global variables _xplotters[] and _xplotters_len */
237   pthread_mutex_lock (&_xplotters_mutex);
238 #endif
239 #endif
240   for (i = 0; i < _xplotters_len; i++)
241     if (_xplotters[i] == _plotter)
242       {
243 	_xplotters[i] = (XPlotter *)NULL;
244 	break;
245       }
246 #ifdef PTHREAD_SUPPORT
247 #ifdef HAVE_PTHREAD_H
248   /* unlock the global variables _xplotters[] and _xplotters_len */
249   pthread_mutex_unlock (&_xplotters_mutex);
250 #endif
251 #endif
252 
253 #ifndef LIBPLOTTER
254   /* in libplot, manually invoke superclass termination method */
255   _pl_x_terminate (S___(_plotter));
256 #endif
257 }
258 
259 #ifdef LIBPLOTTER
XPlotter(FILE * infile,FILE * outfile,FILE * errfile)260 XPlotter::XPlotter (FILE *infile, FILE *outfile, FILE *errfile)
261 	:XDrawablePlotter (infile, outfile, errfile)
262 {
263   _pl_y_initialize ();
264 
265   /* add to _xplotters sparse array */
266 }
267 
XPlotter(FILE * outfile)268 XPlotter::XPlotter (FILE *outfile)
269 	:XDrawablePlotter (outfile)
270 {
271   _pl_y_initialize ();
272 
273   /* add to _xplotters sparse array */
274 }
275 
XPlotter(istream & in,ostream & out,ostream & err)276 XPlotter::XPlotter (istream& in, ostream& out, ostream& err)
277 	: XDrawablePlotter (in, out, err)
278 {
279   _pl_y_initialize ();
280 
281   /* add to _xplotters sparse array */
282 }
283 
XPlotter(ostream & out)284 XPlotter::XPlotter (ostream& out)
285 	: XDrawablePlotter (out)
286 {
287   _pl_y_initialize ();
288 
289   /* add to _xplotters sparse array */
290 }
291 
XPlotter()292 XPlotter::XPlotter ()
293 {
294   _pl_y_initialize ();
295 
296   /* add to _xplotters sparse array */
297 }
298 
XPlotter(FILE * infile,FILE * outfile,FILE * errfile,PlotterParams & parameters)299 XPlotter::XPlotter (FILE *infile, FILE *outfile, FILE *errfile, PlotterParams &parameters)
300 	:XDrawablePlotter (infile, outfile, errfile, parameters)
301 {
302   _pl_y_initialize ();
303 
304   /* add to _xplotters sparse array */
305 }
306 
XPlotter(FILE * outfile,PlotterParams & parameters)307 XPlotter::XPlotter (FILE *outfile, PlotterParams &parameters)
308 	:XDrawablePlotter (outfile, parameters)
309 {
310   _pl_y_initialize ();
311 
312   /* add to _xplotters sparse array */
313 }
314 
XPlotter(istream & in,ostream & out,ostream & err,PlotterParams & parameters)315 XPlotter::XPlotter (istream& in, ostream& out, ostream& err, PlotterParams &parameters)
316 	: XDrawablePlotter (in, out, err, parameters)
317 {
318   _pl_y_initialize ();
319 
320   /* add to _xplotters sparse array */
321 }
322 
XPlotter(ostream & out,PlotterParams & parameters)323 XPlotter::XPlotter (ostream& out, PlotterParams &parameters)
324 	: XDrawablePlotter (out, parameters)
325 {
326   _pl_y_initialize ();
327 
328   /* add to _xplotters sparse array */
329 }
330 
XPlotter(PlotterParams & parameters)331 XPlotter::XPlotter (PlotterParams &parameters)
332 	: XDrawablePlotter (parameters)
333 {
334   _pl_y_initialize ();
335 
336   /* add to _xplotters sparse array */
337 }
338 
~XPlotter()339 XPlotter::~XPlotter ()
340 {
341   /* if luser left the Plotter open, close it */
342   if (_plotter->data->open)
343     _API_closepl ();
344 
345   _pl_y_terminate ();
346 
347   /* remove from _xplotters sparse array */
348 }
349 #endif
350