The R Project SVN R

Rev

Rev 27662 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 27662 Rev 27686
1
/*
1
/*
2
 *  R : A Computer Langage for Statistical Data Analysis
2
 *  R : A Computer Langage for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
4
 *  Copyright (C) 1998--2003  Guido Masarotto and Brian Ripley
4
 *  Copyright (C) 1998--2003  Guido Masarotto and Brian Ripley
5
 *
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
9
 *  (at your option) any later version.
10
 *
10
 *
11
 *  This program is distributed in the hope that it will be useful,
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
14
 *  GNU General Public License for more details.
15
 *
15
 *
16
 *  You should have received a copy of the GNU General Public License
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
19
 */
20
 
20
 
21
/*--- Device Driver for Windows; this file started from
21
/*--- Device Driver for Windows; this file started from
22
 *  ../unix/X11/devX11.c --
22
 *  ../unix/X11/devX11.c --
23
 */
23
 */
24
 
24
 
25
#ifdef HAVE_CONFIG_H
25
#ifdef HAVE_CONFIG_H
26
#include <config.h>
26
#include <config.h>
27
#endif
27
#endif
28
 
28
 
29
#include <Defn.h>
29
#include <Defn.h>
30
#include <Graphics.h>
30
#include <Graphics.h>
31
#include <Rdevices.h>
31
#include <Rdevices.h>
32
#include <stdio.h>
32
#include <stdio.h>
33
#include "opt.h"
33
#include "opt.h"
34
#include "graphapp/ga.h"
34
#include "graphapp/ga.h"
35
#include "graphapp/stdimg.h"
35
#include "graphapp/stdimg.h"
36
#include "console.h"
36
#include "console.h"
37
#include "rui.h"
37
#include "rui.h"
38
#include "devga.h"		/* 'Public' routines from here */
38
#include "devga.h"		/* 'Public' routines from here */
39
#include "windows.h"
39
#include "windows.h"
40
 
40
 
41
extern console RConsole;
41
extern console RConsole;
42
extern Rboolean AllDevicesKilled;
42
extern Rboolean AllDevicesKilled;
43
 
43
 
44
int graphicsx = -25, graphicsy = 0;
44
int graphicsx = -25, graphicsy = 0;
45
 
45
 
46
/* a colour used to represent the background on png if transparent
46
/* a colour used to represent the background on png if transparent
47
   NB: used as RGB and BGR
47
   NB: used as RGB and BGR
48
*/
48
*/
49
#define PNG_TRANS 0xd6d3d6
49
#define PNG_TRANS 0xd6d3d6
50
 
50
 
51
/* these really are globals: per machine, not per window */
51
/* these really are globals: per machine, not per window */
52
static double user_xpinch = 0.0, user_ypinch = 0.0;
52
static double user_xpinch = 0.0, user_ypinch = 0.0;
53
 
53
 
54
void GAsetunits(double xpinch, double ypinch)
54
void GAsetunits(double xpinch, double ypinch)
55
{
55
{
56
    user_xpinch = xpinch;
56
    user_xpinch = xpinch;
57
    user_ypinch = ypinch;
57
    user_ypinch = ypinch;
58
}
58
}
59
 
59
 
60
static rgb GArgb(int color, double gamma)
60
static rgb GArgb(int color, double gamma)
61
{
61
{
62
    int r, g, b;
62
    int r, g, b;
63
    if (gamma != 1) {
63
    if (gamma != 1) {
64
	r = (int) (255 * pow(R_RED(color) / 255.0, gamma));
64
	r = (int) (255 * pow(R_RED(color) / 255.0, gamma));
65
	g = (int) (255 * pow(R_GREEN(color) / 255.0, gamma));
65
	g = (int) (255 * pow(R_GREEN(color) / 255.0, gamma));
66
	b = (int) (255 * pow(R_BLUE(color) / 255.0, gamma));
66
	b = (int) (255 * pow(R_BLUE(color) / 255.0, gamma));
67
    } else {
67
    } else {
68
	r = R_RED(color);
68
	r = R_RED(color);
69
	g = R_GREEN(color);
69
	g = R_GREEN(color);
70
	b = R_BLUE(color);
70
	b = R_BLUE(color);
71
    }
71
    }
72
    return rgb(r, g, b);
72
    return rgb(r, g, b);
73
}
73
}
74
 
74
 
75
 
75
 
76
 
76
 
77
	/********************************************************/
77
	/********************************************************/
78
	/* This device driver has been documented so that it be	*/
78
	/* This device driver has been documented so that it be	*/
79
	/* used as a template for new drivers 			*/
79
	/* used as a template for new drivers 			*/
80
	/********************************************************/
80
	/********************************************************/
81
 
81
 
82
#define MM_PER_INCH	25.4	/* mm -> inch conversion */
82
#define MM_PER_INCH	25.4	/* mm -> inch conversion */
83
 
83
 
84
#define TRACEDEVGA(a)
84
#define TRACEDEVGA(a)
85
#define CLIP if (xd->clip.width>0) gsetcliprect(_d,xd->clip)
85
#define CLIP if (xd->clip.width>0) gsetcliprect(_d,xd->clip)
86
 
86
 
87
static drawing _d;
87
static drawing _d;
88
 
88
 
89
#define DRAW(a) {if(xd->kind != SCREEN) {_d=xd->gawin; CLIP; a;} else {_d=xd->bm; CLIP; a; if(!xd->buffered) {_d=xd->gawin; CLIP; a;} _d=xd->bm; CLIP; a;}}
89
#define DRAW(a) {if(xd->kind != SCREEN) {_d=xd->gawin; CLIP; a;} else {_d=xd->bm; CLIP; a; if(!xd->buffered) {_d=xd->gawin; CLIP; a;} _d=xd->bm; CLIP; a;}}
90
 
90
 
91
#define SHOW  if(xd->kind==SCREEN) {gbitblt(xd->gawin,xd->bm,pt(0,0),getrect(xd->bm));GALastUpdate=GetTickCount();}
91
#define SHOW  if(xd->kind==SCREEN) {gbitblt(xd->gawin,xd->bm,pt(0,0),getrect(xd->bm));GALastUpdate=GetTickCount();}
92
#define SH if(xd->kind==SCREEN && xd->buffered) GA_Timer(xd)
92
#define SH if(xd->kind==SCREEN && xd->buffered) GA_Timer(xd)
93
 
93
 
94
 
94
 
95
#define SF 20  /* scrollbar resolution */
95
#define SF 20  /* scrollbar resolution */
96
 
96
 
97
        /********************************************************/
97
        /********************************************************/
98
	/* Each driver can have its own device-specic graphical */
98
	/* Each driver can have its own device-specic graphical */
99
	/* parameters and resources.  these should be wrapped	*/
99
	/* parameters and resources.  these should be wrapped	*/
100
	/* in a structure (like the gadesc structure below)    */
100
	/* in a structure (like the gadesc structure below)    */
101
	/* and attached to the overall device description via 	*/
101
	/* and attached to the overall device description via 	*/
102
	/* the dd->deviceSpecific pointer			*/
102
	/* the dd->deviceSpecific pointer			*/
103
	/* NOTE that there are generic graphical parameters	*/
103
	/* NOTE that there are generic graphical parameters	*/
104
	/* which must be set by the device driver, but are	*/
104
	/* which must be set by the device driver, but are	*/
105
	/* common to all device types (see Graphics.h)		*/
105
	/* common to all device types (see Graphics.h)		*/
106
	/* so go in the GPar structure rather than this device- */
106
	/* so go in the GPar structure rather than this device- */
107
	/* specific structure					*/
107
	/* specific structure					*/
108
	/********************************************************/
108
	/********************************************************/
109
 
109
 
110
enum DeviceKinds {SCREEN=0, PRINTER, METAFILE, PNG, JPEG, BMP};
110
enum DeviceKinds {SCREEN=0, PRINTER, METAFILE, PNG, JPEG, BMP};
111
 
111
 
112
typedef struct {
112
typedef struct {
113
    /* R Graphics Parameters */
113
    /* R Graphics Parameters */
114
    /* local device copy so that we can detect */
114
    /* local device copy so that we can detect */
115
    /* when parameter changes */
115
    /* when parameter changes */
116
    int   col;			   /* Color */
116
    int   col;			   /* Color */
117
    int   bg;			   /* Background */
117
    int   bg;			   /* Background */
118
    int   fontface;		   /* Typeface */
118
    int   fontface;		   /* Typeface */
119
    int   fontsize, basefontsize;  /* Size in points */
119
    int   fontsize, basefontsize;  /* Size in points */
120
    double fontangle;
120
    double fontangle;
121
 
121
 
122
    /* devga Driver Specific */
122
    /* devga Driver Specific */
123
    /* parameters with copy per devga device */
123
    /* parameters with copy per devga device */
124
 
124
 
125
    enum DeviceKinds kind;
125
    enum DeviceKinds kind;
126
    int   windowWidth;		/* Window width (pixels) */
126
    int   windowWidth;		/* Window width (pixels) */
127
    int   windowHeight;		/* Window height (pixels) */
127
    int   windowHeight;		/* Window height (pixels) */
128
    int   showWidth;		/* device width (pixels) */
128
    int   showWidth;		/* device width (pixels) */
129
    int   showHeight;		/* device height (pixels) */
129
    int   showHeight;		/* device height (pixels) */
130
    int   origWidth, origHeight, xshift, yshift;
130
    int   origWidth, origHeight, xshift, yshift;
131
    Rboolean resize;		/* Window resized */
131
    Rboolean resize;		/* Window resized */
132
    window gawin;		/* Graphics window */
132
    window gawin;		/* Graphics window */
133
  /*FIXME: we should have union for this stuff and
133
  /*FIXME: we should have union for this stuff and
134
    maybe change gawin to canvas*/
134
    maybe change gawin to canvas*/
135
  /* SCREEN section*/
135
  /* SCREEN section*/
136
    popup locpopup, grpopup;
136
    popup locpopup, grpopup;
137
    button  stoploc;
137
    button  stoploc;
138
    menubar mbar, mbarloc;
138
    menubar mbar, mbarloc;
139
    menu  msubsave;
139
    menu  msubsave;
140
    menuitem mpng, mbmp, mjpeg50, mjpeg75, mjpeg100;
140
    menuitem mpng, mbmp, mjpeg50, mjpeg75, mjpeg100;
141
    menuitem mps, mpdf, mwm, mclpbm, mclpwm, mprint, mclose;
141
    menuitem mps, mpdf, mwm, mclpbm, mclpwm, mprint, mclose;
142
    menuitem mrec, madd, mreplace, mprev, mnext, mclear, msvar, mgvar;
142
    menuitem mrec, madd, mreplace, mprev, mnext, mclear, msvar, mgvar;
143
    menuitem mR, mfit, mfix;
143
    menuitem mR, mfit, mfix, grmenustayontop;
144
    Rboolean recording, replaying, needsave;
144
    Rboolean recording, replaying, needsave;
145
    bitmap bm;
145
    bitmap bm;
146
  /* PNG and JPEG section */
146
  /* PNG and JPEG section */
147
    FILE *fp;
147
    FILE *fp;
148
    char filename[512];
148
    char filename[512];
149
    int quality;
149
    int quality;
150
    int npage;
150
    int npage;
151
    double w, h;
151
    double w, h;
152
  /* Used to rescale font size so that bitmap devices have 72dpi */
152
  /* Used to rescale font size so that bitmap devices have 72dpi */
153
    int truedpi, wanteddpi;
153
    int truedpi, wanteddpi;
154
    rgb   fgcolor;		/* Foreground color */
154
    rgb   fgcolor;		/* Foreground color */
155
    rgb   bgcolor;		/* Background color */
155
    rgb   bgcolor;		/* Background color */
156
    rgb   canvascolor;		/* Canvas color */
156
    rgb   canvascolor;		/* Canvas color */
157
    rgb   outcolor;		/* Outside canvas color */
157
    rgb   outcolor;		/* Outside canvas color */
158
    rect  clip;			/* The clipping rectangle */
158
    rect  clip;			/* The clipping rectangle */
159
    Rboolean usefixed;
159
    Rboolean usefixed;
160
    font  fixedfont;
160
    font  fixedfont;
161
    font  font;
161
    font  font;
162
    Rboolean locator;
162
    Rboolean locator;
163
    int clicked; /* {0,1,2} */
163
    int clicked; /* {0,1,2} */
164
    int	px, py, lty, lwd;
164
    int	px, py, lty, lwd;
165
    int resizing; /* {1,2,3} */
165
    int resizing; /* {1,2,3} */
166
    double rescale_factor;
166
    double rescale_factor;
167
    int fast; /* Use fast fixed-width lines? */
167
    int fast; /* Use fast fixed-width lines? */
168
    unsigned int pngtrans; /* what PNG_TRANS get mapped to */
168
    unsigned int pngtrans; /* what PNG_TRANS get mapped to */
169
    Rboolean buffered;
169
    Rboolean buffered;
170
    int timeafter, timesince;
170
    int timeafter, timesince;
171
    SEXP psenv;
171
    SEXP psenv;
172
} gadesc;
172
} gadesc;
173
 
173
 
174
rect getregion(gadesc *xd)
174
rect getregion(gadesc *xd)
175
{
175
{
176
    rect r = getrect(xd->bm);
176
    rect r = getrect(xd->bm);
177
    r.x += max(0, xd->xshift);
177
    r.x += max(0, xd->xshift);
178
    r.y += max(0, xd->yshift);
178
    r.y += max(0, xd->yshift);
179
    r.width = min(r.width, xd->showWidth);
179
    r.width = min(r.width, xd->showWidth);
180
    r.height = min(r.height, xd->showHeight);
180
    r.height = min(r.height, xd->showHeight);
181
    return r;
181
    return r;
182
}
182
}
183
 
183
 
184
/* Update the screen 100ms after last plotting call or 500ms after last
184
/* Update the screen 100ms after last plotting call or 500ms after last
185
   update */
185
   update */
186
 
186
 
187
static UINT TimerNo = 0;
187
static UINT TimerNo = 0;
188
static gadesc *GA_xd;
188
static gadesc *GA_xd;
189
static DWORD GALastUpdate = 0;
189
static DWORD GALastUpdate = 0;
190
 
190
 
191
static VOID CALLBACK
191
static VOID CALLBACK
192
GA_timer_proc(HWND hwnd, UINT message, UINT tid, DWORD time)
192
GA_timer_proc(HWND hwnd, UINT message, UINT tid, DWORD time)
193
{
193
{
194
    if ((message != WM_TIMER) || tid != TimerNo || !GA_xd) return;
194
    if ((message != WM_TIMER) || tid != TimerNo || !GA_xd) return;
195
    gbitblt(GA_xd->gawin, GA_xd->bm, pt(0,0), getrect(GA_xd->bm));
195
    gbitblt(GA_xd->gawin, GA_xd->bm, pt(0,0), getrect(GA_xd->bm));
196
    GALastUpdate = time;
196
    GALastUpdate = time;
197
}
197
}
198
 
198
 
199
static void GA_Timer(gadesc *xd)
199
static void GA_Timer(gadesc *xd)
200
{
200
{
201
    DWORD now = GetTickCount();
201
    DWORD now = GetTickCount();
202
    if(TimerNo != 0) KillTimer(0, TimerNo);
202
    if(TimerNo != 0) KillTimer(0, TimerNo);
203
    if(now > GALastUpdate + xd->timesince) {
203
    if(now > GALastUpdate + xd->timesince) {
204
	gbitblt(xd->gawin, xd->bm, pt(0,0), getrect(xd->bm));
204
	gbitblt(xd->gawin, xd->bm, pt(0,0), getrect(xd->bm));
205
	GALastUpdate = now;
205
	GALastUpdate = now;
206
    } else {
206
    } else {
207
	GA_xd = xd;
207
	GA_xd = xd;
208
	TimerNo = SetTimer(0, 0, (UINT) xd->timeafter, GA_timer_proc);
208
	TimerNo = SetTimer(0, 0, (UINT) xd->timeafter, GA_timer_proc);
209
    }
209
    }
210
}
210
}
211
 
211
 
212
	/********************************************************/
212
	/********************************************************/
213
	/* There are a number of actions that every device 	*/
213
	/* There are a number of actions that every device 	*/
214
	/* driver is expected to perform (even if, in some	*/
214
	/* driver is expected to perform (even if, in some	*/
215
	/* cases it does nothing - just so long as it doesn't 	*/
215
	/* cases it does nothing - just so long as it doesn't 	*/
216
	/* crash !).  this is how the graphics engine interacts */
216
	/* crash !).  this is how the graphics engine interacts */
217
	/* with each device. Each action will be documented 	*/
217
	/* with each device. Each action will be documented 	*/
218
	/* individually. 					*/
218
	/* individually. 					*/
219
	/* hooks for these actions must be set up when the 	*/
219
	/* hooks for these actions must be set up when the 	*/
220
	/* device is first created				*/
220
	/* device is first created				*/
221
	/********************************************************/
221
	/********************************************************/
222
 
222
 
223
	/* Device Driver Actions */
223
	/* Device Driver Actions */
224
 
224
 
225
static void GA_Activate(NewDevDesc *dd);
225
static void GA_Activate(NewDevDesc *dd);
226
static void GA_Circle(double x, double y, double r,
226
static void GA_Circle(double x, double y, double r,
227
		      R_GE_gcontext *gc,
227
		      R_GE_gcontext *gc,
228
		      NewDevDesc *dd);
228
		      NewDevDesc *dd);
229
static void GA_Clip(double x0, double x1, double y0, double y1,
229
static void GA_Clip(double x0, double x1, double y0, double y1,
230
		     NewDevDesc *dd);
230
		     NewDevDesc *dd);
231
static void GA_Close(NewDevDesc *dd);
231
static void GA_Close(NewDevDesc *dd);
232
static void GA_Deactivate(NewDevDesc *dd);
232
static void GA_Deactivate(NewDevDesc *dd);
233
static void GA_Hold(NewDevDesc *dd);
233
static void GA_Hold(NewDevDesc *dd);
234
static Rboolean GA_Locator(double *x, double *y, NewDevDesc *dd);
234
static Rboolean GA_Locator(double *x, double *y, NewDevDesc *dd);
235
static void GA_Line(double x1, double y1, double x2, double y2,
235
static void GA_Line(double x1, double y1, double x2, double y2,
236
		    R_GE_gcontext *gc,
236
		    R_GE_gcontext *gc,
237
		    NewDevDesc *dd);
237
		    NewDevDesc *dd);
238
static void GA_MetricInfo(int c,
238
static void GA_MetricInfo(int c,
239
			  R_GE_gcontext *gc,
239
			  R_GE_gcontext *gc,
240
			  double* ascent, double* descent,
240
			  double* ascent, double* descent,
241
			  double* width, NewDevDesc *dd);
241
			  double* width, NewDevDesc *dd);
242
static void GA_Mode(int mode, NewDevDesc *dd);
242
static void GA_Mode(int mode, NewDevDesc *dd);
243
static void GA_NewPage(R_GE_gcontext *gc,
243
static void GA_NewPage(R_GE_gcontext *gc,
244
		       NewDevDesc *dd);
244
		       NewDevDesc *dd);
245
static void GA_Polygon(int n, double *x, double *y,
245
static void GA_Polygon(int n, double *x, double *y,
246
		       R_GE_gcontext *gc,
246
		       R_GE_gcontext *gc,
247
		       NewDevDesc *dd);
247
		       NewDevDesc *dd);
248
static void GA_Polyline(int n, double *x, double *y,
248
static void GA_Polyline(int n, double *x, double *y,
249
			R_GE_gcontext *gc,
249
			R_GE_gcontext *gc,
250
			NewDevDesc *dd);
250
			NewDevDesc *dd);
251
static void GA_Rect(double x0, double y0, double x1, double y1,
251
static void GA_Rect(double x0, double y0, double x1, double y1,
252
		    R_GE_gcontext *gc,
252
		    R_GE_gcontext *gc,
253
		    NewDevDesc *dd);
253
		    NewDevDesc *dd);
254
static void GA_Size(double *left, double *right,
254
static void GA_Size(double *left, double *right,
255
		    double *bottom, double *top,
255
		    double *bottom, double *top,
256
		    NewDevDesc *dd);
256
		    NewDevDesc *dd);
257
static void GA_Resize(NewDevDesc *dd);
257
static void GA_Resize(NewDevDesc *dd);
258
static double GA_StrWidth(char *str,
258
static double GA_StrWidth(char *str,
259
			  R_GE_gcontext *gc,
259
			  R_GE_gcontext *gc,
260
			  NewDevDesc *dd);
260
			  NewDevDesc *dd);
261
static void GA_Text(double x, double y, char *str,
261
static void GA_Text(double x, double y, char *str,
262
		    double rot, double hadj,
262
		    double rot, double hadj,
263
		    R_GE_gcontext *gc,
263
		    R_GE_gcontext *gc,
264
		    NewDevDesc *dd);
264
		    NewDevDesc *dd);
265
static Rboolean GA_Open(NewDevDesc*, gadesc*, char*, double, double,
265
static Rboolean GA_Open(NewDevDesc*, gadesc*, char*, double, double,
266
			Rboolean, int, int, double, int, int);
266
			Rboolean, int, int, double, int, int);
267
 
267
 
268
	/********************************************************/
268
	/********************************************************/
269
	/* end of list of required device driver actions 	*/
269
	/* end of list of required device driver actions 	*/
270
	/********************************************************/
270
	/********************************************************/
271
 
271
 
272
	/* Support Routines */
272
	/* Support Routines */
273
 
273
 
274
static double pixelHeight(drawing  d);
274
static double pixelHeight(drawing  d);
275
static double pixelWidth(drawing d);
275
static double pixelWidth(drawing d);
276
static void SetColor(int, double, NewDevDesc *);
276
static void SetColor(int, double, NewDevDesc *);
277
static void SetFont(int, int, double, NewDevDesc *);
277
static void SetFont(int, int, double, NewDevDesc *);
278
static void SetLinetype(int, double, NewDevDesc *);
278
static void SetLinetype(int, double, NewDevDesc *);
279
static int Load_Rbitmap_Dll();
279
static int Load_Rbitmap_Dll();
280
void UnLoad_Rbitmap_Dll();
280
void UnLoad_Rbitmap_Dll();
281
static void SaveAsPng(NewDevDesc *dd, char *fn);
281
static void SaveAsPng(NewDevDesc *dd, char *fn);
282
static void SaveAsJpeg(NewDevDesc *dd, int quality, char *fn);
282
static void SaveAsJpeg(NewDevDesc *dd, int quality, char *fn);
283
static void SaveAsBmp(NewDevDesc *dd, char *fn);
283
static void SaveAsBmp(NewDevDesc *dd, char *fn);
284
static void SaveAsBitmap(NewDevDesc *dd);
284
static void SaveAsBitmap(NewDevDesc *dd);
285
 
285
 
286
static void PrivateCopyDevice(NewDevDesc *dd, NewDevDesc *ndd, char *name)
286
static void PrivateCopyDevice(NewDevDesc *dd, NewDevDesc *ndd, char *name)
287
{
287
{
288
    GEDevDesc* gdd;
288
    GEDevDesc* gdd;
289
    int saveDev = curDevice();
289
    int saveDev = curDevice();
290
    gadesc *xd = (gadesc *) dd->deviceSpecific;
290
    gadesc *xd = (gadesc *) dd->deviceSpecific;
291
    gsetcursor(xd->gawin, WatchCursor);
291
    gsetcursor(xd->gawin, WatchCursor);
292
    gsetVar(install(".Device"),
292
    gsetVar(install(".Device"),
293
	    mkString(name), R_NilValue);
293
	    mkString(name), R_NilValue);
294
    gdd = GEcreateDevDesc(ndd);
294
    gdd = GEcreateDevDesc(ndd);
295
    addDevice((DevDesc*) gdd);
295
    addDevice((DevDesc*) gdd);
296
    GEcopyDisplayList(devNumber((DevDesc*) dd));
296
    GEcopyDisplayList(devNumber((DevDesc*) dd));
297
    KillDevice((DevDesc*) gdd);
297
    KillDevice((DevDesc*) gdd);
298
    selectDevice(saveDev);
298
    selectDevice(saveDev);
299
/*    KillDevice(GetDevice(devNumber((DevDesc*) ndd))); */
299
/*    KillDevice(GetDevice(devNumber((DevDesc*) ndd))); */
300
    gsetcursor(xd->gawin, ArrowCursor);
300
    gsetcursor(xd->gawin, ArrowCursor);
301
    show(xd->gawin);
301
    show(xd->gawin);
302
}
302
}
303
 
303
 
304
static void SaveAsWin(NewDevDesc *dd, char *display)
304
static void SaveAsWin(NewDevDesc *dd, char *display)
305
{
305
{
306
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
306
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
307
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
307
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
308
    if (!ndd) {
308
    if (!ndd) {
309
	R_ShowMessage("Not enough memory to copy graphics window");
309
	R_ShowMessage("Not enough memory to copy graphics window");
310
	return;
310
	return;
311
    }
311
    }
312
    if(!R_CheckDeviceAvailableBool()) {
312
    if(!R_CheckDeviceAvailableBool()) {
313
	free(ndd);
313
	free(ndd);
314
	R_ShowMessage("No device available to copy graphics window");
314
	R_ShowMessage("No device available to copy graphics window");
315
	return;
315
	return;
316
    }
316
    }
317
 
317
 
318
    ndd->displayList = R_NilValue;
318
    ndd->displayList = R_NilValue;
319
    if (GADeviceDriver(ndd, display,
319
    if (GADeviceDriver(ndd, display,
320
		       fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
320
		       fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
321
				       GE_INCHES, gdd),
321
				       GE_INCHES, gdd),
322
		       fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
322
		       fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
323
					GE_INCHES, gdd),
323
					GE_INCHES, gdd),
324
		       ((gadesc*) dd->deviceSpecific)->basefontsize,
324
		       ((gadesc*) dd->deviceSpecific)->basefontsize,
325
		       0, 1, White, 1, NA_INTEGER, NA_INTEGER, FALSE,
325
		       0, 1, White, 1, NA_INTEGER, NA_INTEGER, FALSE,
326
		       R_GlobalEnv))
326
		       R_GlobalEnv))
327
        PrivateCopyDevice(dd, ndd, display);
327
        PrivateCopyDevice(dd, ndd, display);
328
}
328
}
329
 
329
 
330
 
330
 
331
static void SaveAsPostscript(NewDevDesc *dd, char *fn)
331
static void SaveAsPostscript(NewDevDesc *dd, char *fn)
332
{
332
{
333
    SEXP s;
333
    SEXP s;
334
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
334
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
335
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
335
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
336
    gadesc *xd = (gadesc *) dd->deviceSpecific;
336
    gadesc *xd = (gadesc *) dd->deviceSpecific;
337
    char family[256], encoding[256], paper[256], bg[256], fg[256],
337
    char family[256], encoding[256], paper[256], bg[256], fg[256],
338
	**afmpaths = NULL;
338
	**afmpaths = NULL;
339
 
339
 
340
    if (!ndd) {
340
    if (!ndd) {
341
	R_ShowMessage("Not enough memory to copy graphics window");
341
	R_ShowMessage("Not enough memory to copy graphics window");
342
	return;
342
	return;
343
    }
343
    }
344
    if(!R_CheckDeviceAvailableBool()) {
344
    if(!R_CheckDeviceAvailableBool()) {
345
	free(ndd);
345
	free(ndd);
346
	R_ShowMessage("No device available to copy graphics window");
346
	R_ShowMessage("No device available to copy graphics window");
347
	return;
347
	return;
348
    }
348
    }
349
 
349
 
350
 
350
 
351
    ndd->displayList = R_NilValue;
351
    ndd->displayList = R_NilValue;
352
 
352
 
353
    /* Set default values... */
353
    /* Set default values... */
354
    strcpy(family, "Helvetica");
354
    strcpy(family, "Helvetica");
355
    strcpy(encoding, "ISOLatin1.enc");
355
    strcpy(encoding, "ISOLatin1.enc");
356
    strcpy(paper, "default");
356
    strcpy(paper, "default");
357
    strcpy(bg, "transparent");
357
    strcpy(bg, "transparent");
358
    strcpy(fg, "black");
358
    strcpy(fg, "black");
359
    /* and then try to get it from .PostScript.Options */
359
    /* and then try to get it from .PostScript.Options */
360
    s = findVar(install(".PostScript.Options"), xd->psenv);
360
    s = findVar(install(".PostScript.Options"), xd->psenv);
361
    if ((s != R_UnboundValue) && (s != R_NilValue)) {
361
    if ((s != R_UnboundValue) && (s != R_NilValue)) {
362
	SEXP names = getAttrib(s, R_NamesSymbol);
362
	SEXP names = getAttrib(s, R_NamesSymbol);
363
	int i,done;
363
	int i,done;
364
	for (i=0, done=0; (done<4) && (i<length(s)) ; i++) {
364
	for (i=0, done=0; (done<4) && (i<length(s)) ; i++) {
365
	    if(!strcmp("family", CHAR(STRING_ELT(names, i)))) {
365
	    if(!strcmp("family", CHAR(STRING_ELT(names, i)))) {
366
		strcpy(family, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
366
		strcpy(family, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
367
		done += 1;
367
		done += 1;
368
	    }
368
	    }
369
	    if(!strcmp("paper", CHAR(STRING_ELT(names, i)))) {
369
	    if(!strcmp("paper", CHAR(STRING_ELT(names, i)))) {
370
		strcpy(paper, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
370
		strcpy(paper, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
371
		done += 1;
371
		done += 1;
372
	    }
372
	    }
373
	    if(!strcmp("bg", CHAR(STRING_ELT(names, i)))) {
373
	    if(!strcmp("bg", CHAR(STRING_ELT(names, i)))) {
374
		strcpy(bg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
374
		strcpy(bg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
375
		done += 1;
375
		done += 1;
376
	    }
376
	    }
377
	    if(!strcmp("fg", CHAR(STRING_ELT(names, i)))) {
377
	    if(!strcmp("fg", CHAR(STRING_ELT(names, i)))) {
378
		strcpy(fg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
378
		strcpy(fg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
379
		done += 1;
379
		done += 1;
380
	    }
380
	    }
381
	}
381
	}
382
    }
382
    }
383
    if (PSDeviceDriver((DevDesc *) ndd,
383
    if (PSDeviceDriver((DevDesc *) ndd,
384
		       fn, paper, family, afmpaths, encoding, bg, fg,
384
		       fn, paper, family, afmpaths, encoding, bg, fg,
385
		       fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
385
		       fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
386
				       GE_INCHES, gdd),
386
				       GE_INCHES, gdd),
387
		       fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
387
		       fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
388
					GE_INCHES, gdd),
388
					GE_INCHES, gdd),
389
		       (double)0, ((gadesc*) dd->deviceSpecific)->basefontsize,
389
		       (double)0, ((gadesc*) dd->deviceSpecific)->basefontsize,
390
		       0, 1, 0, "", "R Graphics Output"))
390
		       0, 1, 0, "", "R Graphics Output"))
391
	/* horizontal=F, onefile=F, pagecentre=T, print.it=F */
391
	/* horizontal=F, onefile=F, pagecentre=T, print.it=F */
392
	PrivateCopyDevice(dd, ndd, "postscript");
392
	PrivateCopyDevice(dd, ndd, "postscript");
393
}
393
}
394
 
394
 
395
 
395
 
396
static void SaveAsPDF(NewDevDesc *dd, char *fn)
396
static void SaveAsPDF(NewDevDesc *dd, char *fn)
397
{
397
{
398
    SEXP s;
398
    SEXP s;
399
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
399
    NewDevDesc *ndd = (NewDevDesc *) calloc(1, sizeof(NewDevDesc));
400
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
400
    GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
401
    gadesc *xd = (gadesc *) dd->deviceSpecific;
401
    gadesc *xd = (gadesc *) dd->deviceSpecific;
402
    char family[256], encoding[256], bg[256], fg[256];
402
    char family[256], encoding[256], bg[256], fg[256];
403
 
403
 
404
    if (!ndd) {
404
    if (!ndd) {
405
	R_ShowMessage("Not enough memory to copy graphics window");
405
	R_ShowMessage("Not enough memory to copy graphics window");
406
	return;
406
	return;
407
    }
407
    }
408
    if(!R_CheckDeviceAvailableBool()) {
408
    if(!R_CheckDeviceAvailableBool()) {
409
	free(ndd);
409
	free(ndd);
410
	R_ShowMessage("No device available to copy graphics window");
410
	R_ShowMessage("No device available to copy graphics window");
411
	return;
411
	return;
412
    }
412
    }
413
 
413
 
414
    ndd->displayList = R_NilValue;
414
    ndd->displayList = R_NilValue;
415
 
415
 
416
    /* Set default values... */
416
    /* Set default values... */
417
    s = findVar(install(".PostScript.Options"), xd->psenv);
417
    s = findVar(install(".PostScript.Options"), xd->psenv);
418
    strcpy(family, "Helvetica");
418
    strcpy(family, "Helvetica");
419
    strcpy(encoding, "ISOLatin1.enc");
419
    strcpy(encoding, "ISOLatin1.enc");
420
    strcpy(bg, "transparent");
420
    strcpy(bg, "transparent");
421
    strcpy(fg, "black");
421
    strcpy(fg, "black");
422
    /* and then try to get it from .PostScript.Options */
422
    /* and then try to get it from .PostScript.Options */
423
    if ((s != R_UnboundValue) && (s != R_NilValue)) {
423
    if ((s != R_UnboundValue) && (s != R_NilValue)) {
424
	SEXP names = getAttrib(s, R_NamesSymbol);
424
	SEXP names = getAttrib(s, R_NamesSymbol);
425
	int i,done;
425
	int i,done;
426
	for (i=0, done=0; (done<4) && (i<length(s)) ; i++) {
426
	for (i=0, done=0; (done<4) && (i<length(s)) ; i++) {
427
	    if(!strcmp("family", CHAR(STRING_ELT(names, i)))) {
427
	    if(!strcmp("family", CHAR(STRING_ELT(names, i)))) {
428
		strcpy(family, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
428
		strcpy(family, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
429
		done += 1;
429
		done += 1;
430
	    }
430
	    }
431
	    if(!strcmp("bg", CHAR(STRING_ELT(names, i)))) {
431
	    if(!strcmp("bg", CHAR(STRING_ELT(names, i)))) {
432
		strcpy(bg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
432
		strcpy(bg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
433
		done += 1;
433
		done += 1;
434
	    }
434
	    }
435
	    if(!strcmp("fg", CHAR(STRING_ELT(names, i)))) {
435
	    if(!strcmp("fg", CHAR(STRING_ELT(names, i)))) {
436
		strcpy(fg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
436
		strcpy(fg, CHAR(STRING_ELT(VECTOR_ELT(s, i), 0)));
437
		done += 1;
437
		done += 1;
438
	    }
438
	    }
439
	}
439
	}
440
    }
440
    }
441
    if (PDFDeviceDriver((DevDesc *) ndd, fn, family, encoding, bg, fg,
441
    if (PDFDeviceDriver((DevDesc *) ndd, fn, family, encoding, bg, fg,
442
			fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
442
			fromDeviceWidth(toDeviceWidth(1.0, GE_NDC, gdd),
443
					GE_INCHES, gdd),
443
					GE_INCHES, gdd),
444
			fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
444
			fromDeviceHeight(toDeviceHeight(-1.0, GE_NDC, gdd),
445
					 GE_INCHES, gdd),
445
					 GE_INCHES, gdd),
446
			((gadesc*) dd->deviceSpecific)->basefontsize,
446
			((gadesc*) dd->deviceSpecific)->basefontsize,
447
			1, "R Graphics Output"))
447
			1, "R Graphics Output"))
448
	PrivateCopyDevice(dd, ndd, "PDF");
448
	PrivateCopyDevice(dd, ndd, "PDF");
449
}
449
}
450
 
450
 
451
 
451
 
452
 
452
 
453
			/* Pixel Dimensions (Inches) */
453
			/* Pixel Dimensions (Inches) */
454
static double pixelWidth(drawing obj)
454
static double pixelWidth(drawing obj)
455
{
455
{
456
    return ((double) 1) / devicepixelsx(obj);
456
    return ((double) 1) / devicepixelsx(obj);
457
}
457
}
458
 
458
 
459
static double pixelHeight(drawing obj)
459
static double pixelHeight(drawing obj)
460
{
460
{
461
    return ((double) 1) / devicepixelsy(obj);
461
    return ((double) 1) / devicepixelsy(obj);
462
}
462
}
463
 
463
 
464
			/* Font information array. */
464
			/* Font information array. */
465
			/* Point sizes: 6-24 */
465
			/* Point sizes: 6-24 */
466
			/* Faces: plain, bold, oblique, bold-oblique */
466
			/* Faces: plain, bold, oblique, bold-oblique */
467
			/* Symbol may be added later */
467
			/* Symbol may be added later */
468
 
468
 
469
#define NFONT 19
469
#define NFONT 19
470
#define MAXFONT 32
470
#define MAXFONT 32
471
static int fontnum;
471
static int fontnum;
472
static int fontinitdone = 0;/* in {0,1,2} */
472
static int fontinitdone = 0;/* in {0,1,2} */
473
static char *fontname[MAXFONT];
473
static char *fontname[MAXFONT];
474
static int fontstyle[MAXFONT];
474
static int fontstyle[MAXFONT];
475
 
475
 
476
static void RStandardFonts()
476
static void RStandardFonts()
477
{
477
{
478
    int   i;
478
    int   i;
479
 
479
 
480
    for (i = 0; i < 4; i++)
480
    for (i = 0; i < 4; i++)
481
	fontname[i] = "Times New Roman";
481
	fontname[i] = "Times New Roman";
482
    fontname[4] = "Symbol";
482
    fontname[4] = "Symbol";
483
    fontstyle[0] = fontstyle[4] = Plain;
483
    fontstyle[0] = fontstyle[4] = Plain;
484
    fontstyle[1] = Bold;
484
    fontstyle[1] = Bold;
485
    fontstyle[2] = Italic;
485
    fontstyle[2] = Italic;
486
    fontstyle[3] = BoldItalic;
486
    fontstyle[3] = BoldItalic;
487
    fontnum = 5;
487
    fontnum = 5;
488
    fontinitdone = 2;		/* =fontinit done & fontname must not be
488
    fontinitdone = 2;		/* =fontinit done & fontname must not be
489
				   free-ed */
489
				   free-ed */
490
}
490
}
491
 
491
 
492
 
492
 
493
static void RFontInit()
493
static void RFontInit()
494
{
494
{
495
    int   i, notdone;
495
    int   i, notdone;
496
    char *opt[2];
496
    char *opt[2];
497
    char  oops[256];
497
    char  oops[256];
498
 
498
 
499
    sprintf(oops, "%s/Rdevga", getenv("R_USER"));
499
    sprintf(oops, "%s/Rdevga", getenv("R_USER"));
500
    notdone = 1;
500
    notdone = 1;
501
    fontnum = 0;
501
    fontnum = 0;
502
    fontinitdone = 1;
502
    fontinitdone = 1;
503
    if (!optopenfile(oops)) {
503
    if (!optopenfile(oops)) {
504
	sprintf(oops, "%s/etc/Rdevga", getenv("R_HOME"));
504
	sprintf(oops, "%s/etc/Rdevga", getenv("R_HOME"));
505
	if (!optopenfile(oops)) {
505
	if (!optopenfile(oops)) {
506
	    RStandardFonts();
506
	    RStandardFonts();
507
	    notdone = 0;
507
	    notdone = 0;
508
	}
508
	}
509
    }
509
    }
510
    while (notdone) {
510
    while (notdone) {
511
	oops[0] = '\0';
511
	oops[0] = '\0';
512
	notdone = optread(opt, ':');
512
	notdone = optread(opt, ':');
513
	if (notdone == 1)
513
	if (notdone == 1)
514
	    sprintf(oops, "[%s] Error at line %d.", optfile(), optline());
514
	    sprintf(oops, "[%s] Error at line %d.", optfile(), optline());
515
	else if (notdone == 2) {
515
	else if (notdone == 2) {
516
	    fontname[fontnum] = strdup(opt[0]);
516
	    fontname[fontnum] = strdup(opt[0]);
517
	    if (!fontname[fontnum])
517
	    if (!fontname[fontnum])
518
		strcpy(oops, "Insufficient memory. ");
518
		strcpy(oops, "Insufficient memory. ");
519
	    else {
519
	    else {
520
		if (!strcmpi(opt[1], "plain"))
520
		if (!strcmpi(opt[1], "plain"))
521
		    fontstyle[fontnum] = Plain;
521
		    fontstyle[fontnum] = Plain;
522
		else if (!strcmpi(opt[1], "bold"))
522
		else if (!strcmpi(opt[1], "bold"))
523
		    fontstyle[fontnum] = Bold;
523
		    fontstyle[fontnum] = Bold;
524
		else if (!strcmpi(opt[1], "italic"))
524
		else if (!strcmpi(opt[1], "italic"))
525
		    fontstyle[fontnum] = Italic;
525
		    fontstyle[fontnum] = Italic;
526
		else if (!strcmpi(opt[1], "bold&italic"))
526
		else if (!strcmpi(opt[1], "bold&italic"))
527
		    fontstyle[fontnum] = BoldItalic;
527
		    fontstyle[fontnum] = BoldItalic;
528
		else
528
		else
529
		    sprintf(oops, "Unknown style at line %d. ", optline());
529
		    sprintf(oops, "Unknown style at line %d. ", optline());
530
		fontnum += 1;
530
		fontnum += 1;
531
	    }
531
	    }
532
	}
532
	}
533
	if (oops[0]) {
533
	if (oops[0]) {
534
	    optclosefile();
534
	    optclosefile();
535
	    strcat(oops, optfile());
535
	    strcat(oops, optfile());
536
	    strcat(oops, " will be ignored.");
536
	    strcat(oops, " will be ignored.");
537
	    R_ShowMessage(oops);
537
	    R_ShowMessage(oops);
538
	    for (i = 0; i < fontnum; i++) free(fontname[i]);
538
	    for (i = 0; i < fontnum; i++) free(fontname[i]);
539
	    RStandardFonts();
539
	    RStandardFonts();
540
	    notdone = 0;
540
	    notdone = 0;
541
	}
541
	}
542
	if (fontnum == MAXFONT) {
542
	if (fontnum == MAXFONT) {
543
	    optclosefile();
543
	    optclosefile();
544
	    notdone = 0;
544
	    notdone = 0;
545
	}
545
	}
546
    }
546
    }
547
}
547
}
548
 
548
 
549
 
549
 
550
 
550
 
551
static int SetBaseFont(gadesc *xd)
551
static int SetBaseFont(gadesc *xd)
552
{
552
{
553
    xd->fontface = 1;
553
    xd->fontface = 1;
554
    xd->fontsize = xd->basefontsize;
554
    xd->fontsize = xd->basefontsize;
555
    xd->fontangle = 0.0;
555
    xd->fontangle = 0.0;
556
    xd->usefixed = FALSE;
556
    xd->usefixed = FALSE;
557
    xd->font = gnewfont(xd->gawin, fontname[0], fontstyle[0],
557
    xd->font = gnewfont(xd->gawin, fontname[0], fontstyle[0],
558
			MulDiv(xd->fontsize, xd->wanteddpi, xd->truedpi), 0.0);
558
			MulDiv(xd->fontsize, xd->wanteddpi, xd->truedpi), 0.0);
559
    if (!xd->font) {
559
    if (!xd->font) {
560
	xd->usefixed= TRUE;
560
	xd->usefixed= TRUE;
561
	xd->font = xd->fixedfont = FixedFont;
561
	xd->font = xd->fixedfont = FixedFont;
562
	if (!xd->fixedfont)
562
	if (!xd->fixedfont)
563
	    return 0;
563
	    return 0;
564
    }
564
    }
565
    return 1;
565
    return 1;
566
}
566
}
567
 
567
 
568
 
568
 
569
 
569
 
570
/* Set the font size and face */
570
/* Set the font size and face */
571
/* If the font of this size and at that the specified */
571
/* If the font of this size and at that the specified */
572
/* rotation is not present it is loaded. */
572
/* rotation is not present it is loaded. */
573
/* 0 = plain text, 1 = bold */
573
/* 0 = plain text, 1 = bold */
574
/* 2 = oblique, 3 = bold-oblique */
574
/* 2 = oblique, 3 = bold-oblique */
575
 
575
 
576
#define SMALLEST 2
576
#define SMALLEST 2
577
#define LARGEST 100
577
#define LARGEST 100
578
 
578
 
579
static void SetFont(int face, int size, double rot, NewDevDesc *dd)
579
static void SetFont(int face, int size, double rot, NewDevDesc *dd)
580
{
580
{
581
    gadesc *xd = (gadesc *) dd->deviceSpecific;
581
    gadesc *xd = (gadesc *) dd->deviceSpecific;
582
 
582
 
583
    if (face < 1 || face > fontnum)
583
    if (face < 1 || face > fontnum)
584
	face = 1;
584
	face = 1;
585
    if (size < SMALLEST) size = SMALLEST;
585
    if (size < SMALLEST) size = SMALLEST;
586
    if (size > LARGEST) size = LARGEST;
586
    if (size > LARGEST) size = LARGEST;
587
    size = MulDiv(size, xd->wanteddpi, xd->truedpi);
587
    size = MulDiv(size, xd->wanteddpi, xd->truedpi);
588
    if (!xd->usefixed &&
588
    if (!xd->usefixed &&
589
	(size != xd->fontsize || face != xd->fontface ||
589
	(size != xd->fontsize || face != xd->fontface ||
590
	 rot != xd->fontangle)) {
590
	 rot != xd->fontangle)) {
591
	 del(xd->font); doevent();
591
	 del(xd->font); doevent();
592
	 xd->font = gnewfont(xd->gawin,
592
	 xd->font = gnewfont(xd->gawin,
593
			    fontname[face - 1], fontstyle[face - 1],
593
			    fontname[face - 1], fontstyle[face - 1],
594
			    size, rot);
594
			    size, rot);
595
	if (xd->font) {
595
	if (xd->font) {
596
	    xd->fontface = face;
596
	    xd->fontface = face;
597
	    xd->fontsize = size;
597
	    xd->fontsize = size;
598
	    xd->fontangle = rot;
598
	    xd->fontangle = rot;
599
	} else {
599
	} else {
600
	    SetBaseFont(xd);
600
	    SetBaseFont(xd);
601
	}
601
	}
602
    }
602
    }
603
}
603
}
604
 
604
 
605
 
605
 
606
static void SetColor(int color, double gamma, NewDevDesc *dd)
606
static void SetColor(int color, double gamma, NewDevDesc *dd)
607
{
607
{
608
    gadesc *xd = (gadesc *) dd->deviceSpecific;
608
    gadesc *xd = (gadesc *) dd->deviceSpecific;
609
 
609
 
610
    if (color != xd->col) {
610
    if (color != xd->col) {
611
	xd->col = color;
611
	xd->col = color;
612
	xd->fgcolor = GArgb(color, gamma);
612
	xd->fgcolor = GArgb(color, gamma);
613
    }
613
    }
614
}
614
}
615
 
615
 
616
 
616
 
617
/*
617
/*
618
 *	Some Notes on Line Textures
618
 *	Some Notes on Line Textures
619
 *
619
 *
620
 *	Line textures are stored as an array of 4-bit integers within
620
 *	Line textures are stored as an array of 4-bit integers within
621
 *	a single 32-bit word.  These integers contain the lengths of
621
 *	a single 32-bit word.  These integers contain the lengths of
622
 *	lines to be drawn with the pen alternately down and then up.
622
 *	lines to be drawn with the pen alternately down and then up.
623
 *	The device should try to arrange that these values are measured
623
 *	The device should try to arrange that these values are measured
624
 *	in points if possible, although pixels is ok on most displays.
624
 *	in points if possible, although pixels is ok on most displays.
625
 *
625
 *
626
 *	If newlty contains a line texture description it is decoded
626
 *	If newlty contains a line texture description it is decoded
627
 *	as follows:
627
 *	as follows:
628
 *
628
 *
629
 *		ndash = 0;
629
 *		ndash = 0;
630
 *		for(i=0 ; i<8 && newlty&15 ; i++) {
630
 *		for(i=0 ; i<8 && newlty&15 ; i++) {
631
 *			dashlist[ndash++] = newlty&15;
631
 *			dashlist[ndash++] = newlty&15;
632
 *			newlty = newlty>>4;
632
 *			newlty = newlty>>4;
633
 *		}
633
 *		}
634
 *		dashlist[0] = length of pen-down segment
634
 *		dashlist[0] = length of pen-down segment
635
 *		dashlist[1] = length of pen-up segment
635
 *		dashlist[1] = length of pen-up segment
636
 *		etc
636
 *		etc
637
 *
637
 *
638
 *	An integer containing a zero terminates the pattern.  Hence
638
 *	An integer containing a zero terminates the pattern.  Hence
639
 *	ndash in this code fragment gives the length of the texture
639
 *	ndash in this code fragment gives the length of the texture
640
 *	description.  If a description contains an odd number of
640
 *	description.  If a description contains an odd number of
641
 *	elements it is replicated to create a pattern with an
641
 *	elements it is replicated to create a pattern with an
642
 *	even number of elements.  (If this is a pain, do something
642
 *	even number of elements.  (If this is a pain, do something
643
 *	different its not crucial).
643
 *	different its not crucial).
644
 *
644
 *
645
 *	27/5/98 Paul - change to allow lty and lwd to interact:
645
 *	27/5/98 Paul - change to allow lty and lwd to interact:
646
 *	the line texture is now scaled by the line width so that,
646
 *	the line texture is now scaled by the line width so that,
647
 *	for example, a wide (lwd=2) dotted line (lty=2) has bigger
647
 *	for example, a wide (lwd=2) dotted line (lty=2) has bigger
648
 *	dots which are more widely spaced.  Previously, such a line
648
 *	dots which are more widely spaced.  Previously, such a line
649
 *	would have "dots" which were wide, but not long, nor widely
649
 *	would have "dots" which were wide, but not long, nor widely
650
 *	spaced.
650
 *	spaced.
651
 */
651
 */
652
 
652
 
653
static void SetLinetype(int newlty, double nlwd, NewDevDesc *dd)
653
static void SetLinetype(int newlty, double nlwd, NewDevDesc *dd)
654
{
654
{
655
    gadesc *xd = (gadesc *) dd->deviceSpecific;
655
    gadesc *xd = (gadesc *) dd->deviceSpecific;
656
    int   newlwd;
656
    int   newlwd;
657
 
657
 
658
    newlwd = nlwd;
658
    newlwd = nlwd;
659
    if (newlwd < 1)
659
    if (newlwd < 1)
660
	newlwd = 1;
660
	newlwd = 1;
661
    xd->lty = newlty;
661
    xd->lty = newlty;
662
    xd->lwd = newlwd;
662
    xd->lwd = newlwd;
663
}
663
}
664
 
664
 
665
 
665
 
666
 
666
 
667
/* Callback functions */
667
/* Callback functions */
668
 
668
 
669
 
669
 
670
static void HelpResize(window w, rect r)
670
static void HelpResize(window w, rect r)
671
{
671
{
672
    if (AllDevicesKilled) return;
672
    if (AllDevicesKilled) return;
673
    {
673
    {
674
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
674
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
675
	gadesc *xd = (gadesc *) dd->deviceSpecific;
675
	gadesc *xd = (gadesc *) dd->deviceSpecific;
676
 
676
 
677
	if (r.width) {
677
	if (r.width) {
678
	    if ((xd->windowWidth != r.width) ||
678
	    if ((xd->windowWidth != r.width) ||
679
		((xd->windowHeight != r.height))) {
679
		((xd->windowHeight != r.height))) {
680
		xd->windowWidth = r.width;
680
		xd->windowWidth = r.width;
681
		xd->windowHeight = r.height;
681
		xd->windowHeight = r.height;
682
		xd->resize = TRUE;
682
		xd->resize = TRUE;
683
	    }
683
	    }
684
	}
684
	}
685
    }
685
    }
686
}
686
}
687
 
687
 
688
static void HelpClose(window w)
688
static void HelpClose(window w)
689
{
689
{
690
    if (AllDevicesKilled) return;
690
    if (AllDevicesKilled) return;
691
    {
691
    {
692
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
692
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
693
	KillDevice(GetDevice(devNumber((DevDesc*) dd)));
693
	KillDevice(GetDevice(devNumber((DevDesc*) dd)));
694
    }
694
    }
695
}
695
}
696
 
696
 
697
static void HelpExpose(window w, rect r)
697
static void HelpExpose(window w, rect r)
698
{
698
{
699
    if (AllDevicesKilled) return;
699
    if (AllDevicesKilled) return;
700
    {
700
    {
701
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
701
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
702
	GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
702
	GEDevDesc* gdd = (GEDevDesc*) GetDevice(devNumber((DevDesc*) dd));
703
	gadesc *xd = (gadesc *) dd->deviceSpecific;
703
	gadesc *xd = (gadesc *) dd->deviceSpecific;
704
 
704
 
705
	if (xd->resize) {
705
	if (xd->resize) {
706
	    GA_Resize(dd);
706
	    GA_Resize(dd);
707
	    xd->replaying = TRUE;
707
	    xd->replaying = TRUE;
708
	    GEplayDisplayList(gdd);
708
	    GEplayDisplayList(gdd);
709
	    xd->replaying = FALSE;
709
	    xd->replaying = FALSE;
710
	    R_ProcessEvents();
710
	    R_ProcessEvents();
711
	} else
711
	} else
712
	    SHOW;
712
	    SHOW;
713
    }
713
    }
714
}
714
}
715
 
715
 
716
static void HelpMouseClick(window w, int button, point pt)
716
static void HelpMouseClick(window w, int button, point pt)
717
{
717
{
718
    if (AllDevicesKilled) return;
718
    if (AllDevicesKilled) return;
719
    {
719
    {
720
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
720
	NewDevDesc *dd = (NewDevDesc *) getdata(w);
721
	gadesc *xd = (gadesc *) dd->deviceSpecific;
721
	gadesc *xd = (gadesc *) dd->deviceSpecific;
722
 
722
 
723
	if (!xd->locator)
723
	if (!xd->locator)
724
	    return;
724
	    return;
725
	if (button & LeftButton) {
725
	if (button & LeftButton) {
726
	    int useBeep = asLogical(GetOption(install("locatorBell"),
726
	    int useBeep = asLogical(GetOption(install("locatorBell"),
727
					      R_NilValue));
727
					      R_NilValue));
728
	    if(useBeep) gabeep();
728
	    if(useBeep) gabeep();
729
	    xd->clicked = 1;
729
	    xd->clicked = 1;
730
	    xd->px = pt.x;
730
	    xd->px = pt.x;
731
	    xd->py = pt.y;
731
	    xd->py = pt.y;
732
	} else
732
	} else
733
	    xd->clicked = 2;
733
	    xd->clicked = 2;
734
    }
734
    }
735
}
735
}
736
 
736
 
737
static void menustop(control m)
737
static void menustop(control m)
738
{
738
{
739
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
739
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
740
    gadesc *xd = (gadesc *) dd->deviceSpecific;
740
    gadesc *xd = (gadesc *) dd->deviceSpecific;
741
    if (!xd->locator)
741
    if (!xd->locator)
742
	return;
742
	return;
743
    xd->clicked = 2;
743
    xd->clicked = 2;
744
}
744
}
745
 
745
 
746
void  fixslash(char *);
746
void  fixslash(char *);
747
 
747
 
748
static void menufilebitmap(control m)
748
static void menufilebitmap(control m)
749
{
749
{
750
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
750
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
751
    gadesc *xd = (gadesc *) dd->deviceSpecific;
751
    gadesc *xd = (gadesc *) dd->deviceSpecific;
752
    char *fn;
752
    char *fn;
753
    if (m==xd->mpng) {
753
    if (m==xd->mpng) {
754
      setuserfilter("Png files (*.png)\0*.png\0\0");
754
      setuserfilter("Png files (*.png)\0*.png\0\0");
755
      fn = askfilesave("Portable network graphics file", "");
755
      fn = askfilesave("Portable network graphics file", "");
756
    } else if (m==xd->mbmp) {
756
    } else if (m==xd->mbmp) {
757
      setuserfilter("Windows bitmap files (*.bmp)\0*.bmp\0\0");
757
      setuserfilter("Windows bitmap files (*.bmp)\0*.bmp\0\0");
758
      fn = askfilesave("Windows bitmap file", "");
758
      fn = askfilesave("Windows bitmap file", "");
759
    } else {
759
    } else {
760
      setuserfilter("Jpeg files (*.jpeg,*jpg)\0*.jpeg;*.jpg\0\0");
760
      setuserfilter("Jpeg files (*.jpeg,*jpg)\0*.jpeg;*.jpg\0\0");
761
      fn = askfilesave("Jpeg file", "");
761
      fn = askfilesave("Jpeg file", "");
762
    }
762
    }
763
    if (!fn) return;
763
    if (!fn) return;
764
    fixslash(fn);
764
    fixslash(fn);
765
    gsetcursor(xd->gawin, WatchCursor);
765
    gsetcursor(xd->gawin, WatchCursor);
766
    show(xd->gawin);
766
    show(xd->gawin);
767
    if (m==xd->mpng) SaveAsPng(dd, fn);
767
    if (m==xd->mpng) SaveAsPng(dd, fn);
768
    else if (m==xd->mbmp) SaveAsBmp(dd, fn);
768
    else if (m==xd->mbmp) SaveAsBmp(dd, fn);
769
    else if (m==xd->mjpeg50) SaveAsJpeg(dd, 50, fn);
769
    else if (m==xd->mjpeg50) SaveAsJpeg(dd, 50, fn);
770
    else if (m==xd->mjpeg75) SaveAsJpeg(dd, 75, fn);
770
    else if (m==xd->mjpeg75) SaveAsJpeg(dd, 75, fn);
771
    else SaveAsJpeg(dd, 100, fn);
771
    else SaveAsJpeg(dd, 100, fn);
772
    gsetcursor(xd->gawin, ArrowCursor);
772
    gsetcursor(xd->gawin, ArrowCursor);
773
    show(xd->gawin);
773
    show(xd->gawin);
774
}
774
}
775
 
775
 
776
 
776
 
777
static void menups(control m)
777
static void menups(control m)
778
{
778
{
779
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
779
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
780
    char  *fn;
780
    char  *fn;
781
 
781
 
782
    setuserfilter("Postscript files (*.ps)\0*.ps\0All files (*.*)\0*.*\0\0");
782
    setuserfilter("Postscript files (*.ps)\0*.ps\0All files (*.*)\0*.*\0\0");
783
    fn = askfilesave("Postscript file", "");
783
    fn = askfilesave("Postscript file", "");
784
    if (!fn) return;
784
    if (!fn) return;
785
    fixslash(fn);
785
    fixslash(fn);
786
    SaveAsPostscript(dd, fn);
786
    SaveAsPostscript(dd, fn);
787
}
787
}
788
 
788
 
789
 
789
 
790
static void menupdf(control m)
790
static void menupdf(control m)
791
{
791
{
792
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
792
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
793
    char  *fn;
793
    char  *fn;
794
 
794
 
795
    setuserfilter("PDF files (*.pdf)\0*.pdf\0All files (*.*)\0*.*\0\0");
795
    setuserfilter("PDF files (*.pdf)\0*.pdf\0All files (*.*)\0*.*\0\0");
796
    fn = askfilesave("PDF file", "");
796
    fn = askfilesave("PDF file", "");
797
    if (!fn) return;
797
    if (!fn) return;
798
    fixslash(fn);
798
    fixslash(fn);
799
    SaveAsPDF(dd, fn);
799
    SaveAsPDF(dd, fn);
800
}
800
}
801
 
801
 
802
 
802
 
803
static void menuwm(control m)
803
static void menuwm(control m)
804
{
804
{
805
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
805
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
806
    char  display[550], *fn;
806
    char  display[550], *fn;
807
 
807
 
808
    setuserfilter("Enhanced metafiles (*.emf)\0*.emf\0All files (*.*)\0*.*\0\0");
808
    setuserfilter("Enhanced metafiles (*.emf)\0*.emf\0All files (*.*)\0*.*\0\0");
809
    fn = askfilesave("Enhanced metafiles", "");
809
    fn = askfilesave("Enhanced metafiles", "");
810
    if (!fn) return;
810
    if (!fn) return;
811
    fixslash(fn);
811
    fixslash(fn);
812
    if(strlen(fn) > 512) {
812
    if(strlen(fn) > 512) {
813
	askok("file path selected is too long: only 512 bytes are allowed");
813
	askok("file path selected is too long: only 512 bytes are allowed");
814
	return;
814
	return;
815
    }
815
    }
816
    sprintf(display, "win.metafile:%s", fn);
816
    sprintf(display, "win.metafile:%s", fn);
817
    SaveAsWin(dd, display);
817
    SaveAsWin(dd, display);
818
}
818
}
819
 
819
 
820
 
820
 
821
static void menuclpwm(control m)
821
static void menuclpwm(control m)
822
{
822
{
823
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
823
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
824
    SaveAsWin(dd, "win.metafile");
824
    SaveAsWin(dd, "win.metafile");
825
}
825
}
826
 
826
 
827
static void menuclpbm(control m)
827
static void menuclpbm(control m)
828
{
828
{
829
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
829
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
830
    gadesc *xd = (gadesc *) dd->deviceSpecific;
830
    gadesc *xd = (gadesc *) dd->deviceSpecific;
831
 
831
 
832
    show(xd->gawin);
832
    show(xd->gawin);
833
    gsetcursor(xd->gawin, WatchCursor);
833
    gsetcursor(xd->gawin, WatchCursor);
834
    copytoclipboard(xd->bm);
834
    copytoclipboard(xd->bm);
835
    gsetcursor(xd->gawin, ArrowCursor);
835
    gsetcursor(xd->gawin, ArrowCursor);
836
}
836
}
837
 
837
 
838
static void menustayontop(control m)
838
static void menustayontop(control m)
839
{
839
{
840
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
840
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
841
    gadesc *xd = (gadesc *) dd->deviceSpecific;
841
    gadesc *xd = (gadesc *) dd->deviceSpecific;
842
 
842
 
843
    if (ischecked(m)) {
-
 
844
	uncheck(m);
-
 
845
	BringToTop(xd->gawin, 0);
843
    BringToTop(xd->gawin, 2);
846
    } else {
-
 
847
	check(m);
-
 
848
	BringToTop(xd->gawin, 1);
-
 
849
    }
-
 
850
}
844
}
851
 
845
 
852
static void menuprint(control m)
846
static void menuprint(control m)
853
{
847
{
854
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
848
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
855
    SaveAsWin(dd, "win.print:");
849
    SaveAsWin(dd, "win.print:");
856
}
850
}
857
 
851
 
858
 
-
 
859
 
-
 
860
static void menuclose(control m)
852
static void menuclose(control m)
861
{
853
{
862
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
854
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
863
    gadesc *xd = (gadesc *) dd->deviceSpecific;
855
    gadesc *xd = (gadesc *) dd->deviceSpecific;
864
 
856
 
865
    HelpClose(xd->gawin);
857
    HelpClose(xd->gawin);
866
}
858
}
867
 
859
 
-
 
860
static void grpopupact(control m)
-
 
861
{
-
 
862
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
-
 
863
    gadesc *xd = (gadesc *) dd->deviceSpecific;
-
 
864
 
-
 
865
    if (ismdi())
-
 
866
    	disable(xd->grmenustayontop);
-
 
867
    else {
-
 
868
    	if (isTopmost(xd->gawin))
-
 
869
     	    check(xd->grmenustayontop);
-
 
870
    	else
-
 
871
    	    uncheck(xd->grmenustayontop);
-
 
872
    }
-
 
873
}
-
 
874
 
868
/* plot history */
875
/* plot history */
869
 
876
 
870
 
877
 
871
#ifdef PLOTHISTORY
878
#ifdef PLOTHISTORY
872
 
879
 
873
/* extern SEXP savedSnapshot;*/
880
/* extern SEXP savedSnapshot;*/
874
 
881
 
875
/* NB: this puts .SavedPlots in .GlobalEnv */
882
/* NB: this puts .SavedPlots in .GlobalEnv */
876
#define GROWTH 4
883
#define GROWTH 4
877
#define GETDL SEXP vDL=findVar(install(".SavedPlots"), R_GlobalEnv)
884
#define GETDL SEXP vDL=findVar(install(".SavedPlots"), R_GlobalEnv)
878
#define SETDL defineVar(install(".SavedPlots"), vDL, R_GlobalEnv)
885
#define SETDL defineVar(install(".SavedPlots"), vDL, R_GlobalEnv)
879
/* altered in 1.4.0, as incompatible format */
886
/* altered in 1.4.0, as incompatible format */
880
#define PLOTHISTORYMAGIC 31416
887
#define PLOTHISTORYMAGIC 31416
881
#define pMAGIC      (INTEGER(VECTOR_ELT(vDL, 0))[0])
888
#define pMAGIC      (INTEGER(VECTOR_ELT(vDL, 0))[0])
882
#define pNUMPLOTS   (INTEGER(VECTOR_ELT(vDL, 1))[0])
889
#define pNUMPLOTS   (INTEGER(VECTOR_ELT(vDL, 1))[0])
883
#define pMAXPLOTS   (INTEGER(VECTOR_ELT(vDL, 2))[0])
890
#define pMAXPLOTS   (INTEGER(VECTOR_ELT(vDL, 2))[0])
884
#define pCURRENTPOS (INTEGER(VECTOR_ELT(vDL, 3))[0])
891
#define pCURRENTPOS (INTEGER(VECTOR_ELT(vDL, 3))[0])
885
#define pHISTORY    (VECTOR_ELT(vDL, 4))
892
#define pHISTORY    (VECTOR_ELT(vDL, 4))
886
#define SET_pHISTORY(v)    (SET_VECTOR_ELT(vDL, 4, v))
893
#define SET_pHISTORY(v)    (SET_VECTOR_ELT(vDL, 4, v))
887
#define pCURRENT    (VECTOR_ELT(pHISTORY, pCURRENTPOS))
894
#define pCURRENT    (VECTOR_ELT(pHISTORY, pCURRENTPOS))
888
#define pCURRENTdl  (VECTOR_ELT(pCURRENT, 0))
895
#define pCURRENTdl  (VECTOR_ELT(pCURRENT, 0))
889
#define pCURRENTgp  (INTEGER(VECTOR_ELT(pCURRENT, 1)))
896
#define pCURRENTgp  (INTEGER(VECTOR_ELT(pCURRENT, 1)))
890
#define pCURRENTsnapshot (VECTOR_ELT(pCURRENT, 0))
897
#define pCURRENTsnapshot (VECTOR_ELT(pCURRENT, 0))
891
#define pCHECK      if ((TYPEOF(vDL)!=VECSXP)||\
898
#define pCHECK      if ((TYPEOF(vDL)!=VECSXP)||\
892
                       (TYPEOF(VECTOR_ELT(vDL, 0))!=INTSXP) ||\
899
                       (TYPEOF(VECTOR_ELT(vDL, 0))!=INTSXP) ||\
893
                       (LENGTH(VECTOR_ELT(vDL, 0))!=1) ||\
900
                       (LENGTH(VECTOR_ELT(vDL, 0))!=1) ||\
894
                       (pMAGIC != PLOTHISTORYMAGIC)) {\
901
                       (pMAGIC != PLOTHISTORYMAGIC)) {\
895
                       R_ShowMessage("Plot history seems corrupted");\
902
                       R_ShowMessage("Plot history seems corrupted");\
896
                       return;}
903
                       return;}
897
#define pMOVE(a) {pCURRENTPOS+=a;\
904
#define pMOVE(a) {pCURRENTPOS+=a;\
898
                  if(pCURRENTPOS<0) pCURRENTPOS=0;\
905
                  if(pCURRENTPOS<0) pCURRENTPOS=0;\
899
                  if(pCURRENTPOS>pNUMPLOTS-1) pCURRENTPOS=pNUMPLOTS-1;\
906
                  if(pCURRENTPOS>pNUMPLOTS-1) pCURRENTPOS=pNUMPLOTS-1;\
900
                  Replay(dd,vDL);SETDL;}
907
                  Replay(dd,vDL);SETDL;}
901
#define pEXIST ((vDL!=R_UnboundValue) && (vDL!=R_NilValue))
908
#define pEXIST ((vDL!=R_UnboundValue) && (vDL!=R_NilValue))
902
#define pMUSTEXIST if(!pEXIST){R_ShowMessage("No plot history!");return;}
909
#define pMUSTEXIST if(!pEXIST){R_ShowMessage("No plot history!");return;}
903
 
910
 
904
 
911
 
905
 
912
 
906
 
913
 
907
static SEXP NewPlotHistory(int n)
914
static SEXP NewPlotHistory(int n)
908
{
915
{
909
    SEXP  vDL, class;
916
    SEXP  vDL, class;
910
    int   i;
917
    int   i;
911
 
918
 
912
    PROTECT(vDL = allocVector(VECSXP, 5));
919
    PROTECT(vDL = allocVector(VECSXP, 5));
913
    for (i = 0; i < 4; i++)
920
    for (i = 0; i < 4; i++)
914
	PROTECT(SET_VECTOR_ELT(vDL, i, allocVector(INTSXP, 1)));
921
	PROTECT(SET_VECTOR_ELT(vDL, i, allocVector(INTSXP, 1)));
915
    PROTECT(SET_pHISTORY (allocVector(VECSXP, n)));
922
    PROTECT(SET_pHISTORY (allocVector(VECSXP, n)));
916
    pMAGIC = PLOTHISTORYMAGIC;
923
    pMAGIC = PLOTHISTORYMAGIC;
917
    pNUMPLOTS = 0;
924
    pNUMPLOTS = 0;
918
    pMAXPLOTS = n;
925
    pMAXPLOTS = n;
919
    pCURRENTPOS = -1;
926
    pCURRENTPOS = -1;
920
    for (i = 0; i < n; i++)
927
    for (i = 0; i < n; i++)
921
	SET_VECTOR_ELT(pHISTORY, i, R_NilValue);
928
	SET_VECTOR_ELT(pHISTORY, i, R_NilValue);
922
    PROTECT(class = allocVector(STRSXP, 1));
929
    PROTECT(class = allocVector(STRSXP, 1));
923
    SET_STRING_ELT(class, 0, mkChar("SavedPlots"));
930
    SET_STRING_ELT(class, 0, mkChar("SavedPlots"));
924
    classgets(vDL, class);
931
    classgets(vDL, class);
925
    SETDL;
932
    SETDL;
926
    UNPROTECT(7);
933
    UNPROTECT(7);
927
    return vDL;
934
    return vDL;
928
}
935
}
929
 
936
 
930
static SEXP GrowthPlotHistory(SEXP vDL)
937
static SEXP GrowthPlotHistory(SEXP vDL)
931
{
938
{
932
    SEXP  vOLD;
939
    SEXP  vOLD;
933
    int   i, oldNPlots, oldCurrent;
940
    int   i, oldNPlots, oldCurrent;
934
 
941
 
935
    PROTECT(vOLD = pHISTORY);
942
    PROTECT(vOLD = pHISTORY);
936
    oldNPlots = pNUMPLOTS;
943
    oldNPlots = pNUMPLOTS;
937
    oldCurrent = pCURRENTPOS;
944
    oldCurrent = pCURRENTPOS;
938
    PROTECT(vDL = NewPlotHistory(pMAXPLOTS + GROWTH));
945
    PROTECT(vDL = NewPlotHistory(pMAXPLOTS + GROWTH));
939
    for (i = 0; i < oldNPlots; i++)
946
    for (i = 0; i < oldNPlots; i++)
940
	SET_VECTOR_ELT(pHISTORY, i, VECTOR_ELT(vOLD, i));
947
	SET_VECTOR_ELT(pHISTORY, i, VECTOR_ELT(vOLD, i));
941
    pNUMPLOTS = oldNPlots;
948
    pNUMPLOTS = oldNPlots;
942
    pCURRENTPOS = oldCurrent;
949
    pCURRENTPOS = oldCurrent;
943
    SETDL;
950
    SETDL;
944
    UNPROTECT(2);
951
    UNPROTECT(2);
945
    return vDL;
952
    return vDL;
946
}
953
}
947
 
954
 
948
static void AddtoPlotHistory(SEXP snapshot, int replace)
955
static void AddtoPlotHistory(SEXP snapshot, int replace)
949
{
956
{
950
    int   where;
957
    int   where;
951
    SEXP  class;
958
    SEXP  class;
952
 
959
 
953
    GETDL;
960
    GETDL;
954
/*    if (dl == R_NilValue) {
961
/*    if (dl == R_NilValue) {
955
	R_ShowMessage("Display list is void!");
962
	R_ShowMessage("Display list is void!");
956
	return;
963
	return;
957
	} */
964
	} */
958
    if (!pEXIST)
965
    if (!pEXIST)
959
	vDL = NewPlotHistory(GROWTH);
966
	vDL = NewPlotHistory(GROWTH);
960
    else if (!replace && (pNUMPLOTS == pMAXPLOTS))
967
    else if (!replace && (pNUMPLOTS == pMAXPLOTS))
961
	vDL = GrowthPlotHistory(vDL);
968
	vDL = GrowthPlotHistory(vDL);
962
    PROTECT(vDL);
969
    PROTECT(vDL);
963
    pCHECK;
970
    pCHECK;
964
    if (replace)
971
    if (replace)
965
	where = pCURRENTPOS;
972
	where = pCURRENTPOS;
966
    else
973
    else
967
	where = pNUMPLOTS;
974
	where = pNUMPLOTS;
968
    PROTECT(snapshot);
975
    PROTECT(snapshot);
969
    PROTECT(class = allocVector(STRSXP, 1));
976
    PROTECT(class = allocVector(STRSXP, 1));
970
    SET_STRING_ELT(class, 0, mkChar("recordedplot"));
977
    SET_STRING_ELT(class, 0, mkChar("recordedplot"));
971
    classgets(snapshot, class);
978
    classgets(snapshot, class);
972
    SET_VECTOR_ELT(pHISTORY, where, snapshot);
979
    SET_VECTOR_ELT(pHISTORY, where, snapshot);
973
    pCURRENTPOS = where;
980
    pCURRENTPOS = where;
974
    if (!replace) pNUMPLOTS += 1;
981
    if (!replace) pNUMPLOTS += 1;
975
    SETDL;
982
    SETDL;
976
    UNPROTECT(3);
983
    UNPROTECT(3);
977
}
984
}
978
 
985
 
979
 
986
 
980
static void Replay(NewDevDesc *dd, SEXP vDL)
987
static void Replay(NewDevDesc *dd, SEXP vDL)
981
{
988
{
982
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
989
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
983
    gadesc *xd = (gadesc *) dd->deviceSpecific;
990
    gadesc *xd = (gadesc *) dd->deviceSpecific;
984
 
991
 
985
    xd->replaying = TRUE;
992
    xd->replaying = TRUE;
986
    gsetcursor(xd->gawin, WatchCursor);
993
    gsetcursor(xd->gawin, WatchCursor);
987
    GEplaySnapshot(pCURRENT, gdd);
994
    GEplaySnapshot(pCURRENT, gdd);
988
    xd->replaying = FALSE;
995
    xd->replaying = FALSE;
989
    gsetcursor(xd->gawin, ArrowCursor);
996
    gsetcursor(xd->gawin, ArrowCursor);
990
}
997
}
991
 
998
 
992
static void menurec(control m)
999
static void menurec(control m)
993
{
1000
{
994
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1001
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
995
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1002
    gadesc *xd = (gadesc *) dd->deviceSpecific;
996
 
1003
 
997
    if (xd->recording) {
1004
    if (xd->recording) {
998
	xd->recording = FALSE;
1005
	xd->recording = FALSE;
999
	uncheck(m);
1006
	uncheck(m);
1000
    } else {
1007
    } else {
1001
	xd->recording = TRUE;
1008
	xd->recording = TRUE;
1002
	check(m);
1009
	check(m);
1003
    }
1010
    }
1004
}
1011
}
1005
 
1012
 
1006
 
1013
 
1007
static void menuadd(control m)
1014
static void menuadd(control m)
1008
{
1015
{
1009
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1016
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1010
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1017
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1011
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1018
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1012
 
1019
 
1013
    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1020
    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1014
    xd->needsave = FALSE;
1021
    xd->needsave = FALSE;
1015
}
1022
}
1016
 
1023
 
1017
static void menureplace(control m)
1024
static void menureplace(control m)
1018
{
1025
{
1019
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1026
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1020
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1027
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1021
 
1028
 
1022
    GETDL;
1029
    GETDL;
1023
    pMUSTEXIST;
1030
    pMUSTEXIST;
1024
    pCHECK;
1031
    pCHECK;
1025
    if (pCURRENTPOS < 0) {
1032
    if (pCURRENTPOS < 0) {
1026
	R_ShowMessage("No plot to replace!");
1033
	R_ShowMessage("No plot to replace!");
1027
	return;
1034
	return;
1028
    }
1035
    }
1029
    AddtoPlotHistory(GEcreateSnapshot(gdd), 1);
1036
    AddtoPlotHistory(GEcreateSnapshot(gdd), 1);
1030
}
1037
}
1031
 
1038
 
1032
static void menunext(control m)
1039
static void menunext(control m)
1033
{
1040
{
1034
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1041
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1035
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1042
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1036
 
1043
 
1037
    GETDL;
1044
    GETDL;
1038
    if (xd->needsave) return;
1045
    if (xd->needsave) return;
1039
    pMUSTEXIST;
1046
    pMUSTEXIST;
1040
    pCHECK;
1047
    pCHECK;
1041
    if (pCURRENTPOS != (pNUMPLOTS - 1)) pMOVE(1);
1048
    if (pCURRENTPOS != (pNUMPLOTS - 1)) pMOVE(1);
1042
}
1049
}
1043
 
1050
 
1044
static void menuprev(control m)
1051
static void menuprev(control m)
1045
{
1052
{
1046
    NewDevDesc *dd = (NewDevDesc*) getdata(m);
1053
    NewDevDesc *dd = (NewDevDesc*) getdata(m);
1047
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1054
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1048
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1055
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1049
 
1056
 
1050
    GETDL;
1057
    GETDL;
1051
    pMUSTEXIST;
1058
    pMUSTEXIST;
1052
    pCHECK;
1059
    pCHECK;
1053
    if (pNUMPLOTS) {
1060
    if (pNUMPLOTS) {
1054
	if (xd->recording && xd->needsave && (dd->displayList != R_NilValue)) {
1061
	if (xd->recording && xd->needsave && (dd->displayList != R_NilValue)) {
1055
	    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1062
	    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1056
	    xd->needsave = FALSE;
1063
	    xd->needsave = FALSE;
1057
	}
1064
	}
1058
	pMOVE((xd->needsave) ? 0 : -1);
1065
	pMOVE((xd->needsave) ? 0 : -1);
1059
    }
1066
    }
1060
}
1067
}
1061
 
1068
 
1062
static void menuclear(control m)
1069
static void menuclear(control m)
1063
{
1070
{
1064
    defineVar(install(".SavedPlots"), R_NilValue, R_GlobalEnv);
1071
    defineVar(install(".SavedPlots"), R_NilValue, R_GlobalEnv);
1065
}
1072
}
1066
 
1073
 
1067
static void menugvar(control m)
1074
static void menugvar(control m)
1068
{
1075
{
1069
    SEXP  vDL;
1076
    SEXP  vDL;
1070
    char *v = askstring("Variable name", "");
1077
    char *v = askstring("Variable name", "");
1071
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1078
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1072
 
1079
 
1073
    if (!v)
1080
    if (!v)
1074
	return;
1081
	return;
1075
    vDL = findVar(install(v), R_GlobalEnv);
1082
    vDL = findVar(install(v), R_GlobalEnv);
1076
    if (!pEXIST || !pNUMPLOTS) {
1083
    if (!pEXIST || !pNUMPLOTS) {
1077
	R_ShowMessage("Variable doesn't exist or doesn't contain any plots!");
1084
	R_ShowMessage("Variable doesn't exist or doesn't contain any plots!");
1078
	return;
1085
	return;
1079
    }
1086
    }
1080
    pCHECK;
1087
    pCHECK;
1081
    pCURRENTPOS = 0;
1088
    pCURRENTPOS = 0;
1082
    Replay(dd, vDL);
1089
    Replay(dd, vDL);
1083
    SETDL;
1090
    SETDL;
1084
}
1091
}
1085
 
1092
 
1086
static void menusvar(control m)
1093
static void menusvar(control m)
1087
{
1094
{
1088
    char *v;
1095
    char *v;
1089
 
1096
 
1090
    GETDL;
1097
    GETDL;
1091
    pMUSTEXIST;
1098
    pMUSTEXIST;
1092
    pCHECK;
1099
    pCHECK;
1093
    v = askstring("Name of variable to save to", "");
1100
    v = askstring("Name of variable to save to", "");
1094
    if (!v)
1101
    if (!v)
1095
	return;
1102
	return;
1096
    defineVar(install(v), vDL, R_GlobalEnv);
1103
    defineVar(install(v), vDL, R_GlobalEnv);
1097
}
1104
}
1098
#endif
1105
#endif
1099
 
1106
 
1100
static void menuconsole(control m)
1107
static void menuconsole(control m)
1101
{
1108
{
1102
   show(RConsole);
1109
   show(RConsole);
1103
}
1110
}
1104
 
1111
 
1105
static void menuR(control m)
1112
static void menuR(control m)
1106
{
1113
{
1107
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1114
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1108
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1115
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1109
    check(xd->mR);
1116
    check(xd->mR);
1110
    uncheck(xd->mfix);
1117
    uncheck(xd->mfix);
1111
    uncheck(xd->mfit);
1118
    uncheck(xd->mfit);
1112
    xd->resizing = 1;
1119
    xd->resizing = 1;
1113
    xd->resize = TRUE;
1120
    xd->resize = TRUE;
1114
    HelpExpose(m, getrect(xd->gawin));
1121
    HelpExpose(m, getrect(xd->gawin));
1115
}
1122
}
1116
 
1123
 
1117
static void menufit(control m)
1124
static void menufit(control m)
1118
{
1125
{
1119
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1126
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1120
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1127
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1121
 
1128
 
1122
    uncheck(xd->mR);
1129
    uncheck(xd->mR);
1123
    check(xd->mfit);
1130
    check(xd->mfit);
1124
    uncheck(xd->mfix);
1131
    uncheck(xd->mfix);
1125
    xd->resizing = 2;
1132
    xd->resizing = 2;
1126
    xd->resize = TRUE;
1133
    xd->resize = TRUE;
1127
    HelpExpose(m, getrect(xd->gawin));
1134
    HelpExpose(m, getrect(xd->gawin));
1128
}
1135
}
1129
 
1136
 
1130
static void menufix(control m)
1137
static void menufix(control m)
1131
{
1138
{
1132
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1139
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1133
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1140
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1134
 
1141
 
1135
    uncheck(xd->mR);
1142
    uncheck(xd->mR);
1136
    uncheck(xd->mfit);
1143
    uncheck(xd->mfit);
1137
    check(xd->mfix);
1144
    check(xd->mfix);
1138
    xd->resizing = 3;
1145
    xd->resizing = 3;
1139
    xd->resize = TRUE;
1146
    xd->resize = TRUE;
1140
    HelpExpose(m, getrect(xd->gawin));
1147
    HelpExpose(m, getrect(xd->gawin));
1141
}
1148
}
1142
 
1149
 
1143
static void CHelpKeyIn(control w, int key)
1150
static void CHelpKeyIn(control w, int key)
1144
{
1151
{
1145
#ifdef PLOTHISTORY
1152
#ifdef PLOTHISTORY
1146
    NewDevDesc *dd = (NewDevDesc *) getdata(w);
1153
    NewDevDesc *dd = (NewDevDesc *) getdata(w);
1147
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1154
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1148
 
1155
 
1149
    if (xd->replaying) return;
1156
    if (xd->replaying) return;
1150
    switch (key) {
1157
    switch (key) {
1151
      case INS:
1158
      case INS:
1152
	menuadd(xd->madd);
1159
	menuadd(xd->madd);
1153
	break;
1160
	break;
1154
      case PGUP:
1161
      case PGUP:
1155
	menuprev(xd->mprev);
1162
	menuprev(xd->mprev);
1156
	break;
1163
	break;
1157
      case PGDN:
1164
      case PGDN:
1158
	menunext(xd->mnext);
1165
	menunext(xd->mnext);
1159
	break;
1166
	break;
1160
    }
1167
    }
1161
#endif
1168
#endif
1162
}
1169
}
1163
 
1170
 
1164
static void NHelpKeyIn(control w,int key)
1171
static void NHelpKeyIn(control w,int key)
1165
{
1172
{
1166
    NewDevDesc *dd = (NewDevDesc *) getdata(w);
1173
    NewDevDesc *dd = (NewDevDesc *) getdata(w);
1167
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1174
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1168
 
1175
 
1169
    if (xd->replaying) return;
1176
    if (xd->replaying) return;
1170
    if (ggetkeystate() != CtrlKey)
1177
    if (ggetkeystate() != CtrlKey)
1171
	return;
1178
	return;
1172
    key = 'A' + key - 1;
1179
    key = 'A' + key - 1;
1173
    if (key == 'C')
1180
    if (key == 'C')
1174
	menuclpbm(xd->mclpbm);
1181
	menuclpbm(xd->mclpbm);
1175
    if (dd->displayList == R_NilValue)
1182
    if (dd->displayList == R_NilValue)
1176
	return;
1183
	return;
1177
    if (key == 'W')
1184
    if (key == 'W')
1178
	menuclpwm(xd->mclpwm);
1185
	menuclpwm(xd->mclpwm);
1179
    if (key == 'P')
1186
    if (key == 'P')
1180
	menuprint(xd->mprint);
1187
	menuprint(xd->mprint);
1181
}
1188
}
1182
 
1189
 
1183
static void mbarf(control m)
1190
static void mbarf(control m)
1184
{
1191
{
1185
#ifdef PLOTHISTORY
1192
#ifdef PLOTHISTORY
1186
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1193
    NewDevDesc *dd = (NewDevDesc *) getdata(m);
1187
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1194
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1188
 
1195
 
1189
    GETDL;
1196
    GETDL;
1190
    if (pEXIST && !xd->replaying) {
1197
    if (pEXIST && !xd->replaying) {
1191
	enable(xd->mnext);
1198
	enable(xd->mnext);
1192
	enable(xd->mprev);
1199
	enable(xd->mprev);
1193
	if ((pCURRENTPOS >= 0) && (dd->displayList != R_NilValue))
1200
	if ((pCURRENTPOS >= 0) && (dd->displayList != R_NilValue))
1194
	    enable(xd->mreplace);
1201
	    enable(xd->mreplace);
1195
	else
1202
	else
1196
	    disable(xd->mreplace);
1203
	    disable(xd->mreplace);
1197
	enable(xd->msvar);
1204
	enable(xd->msvar);
1198
	enable(xd->mclear);
1205
	enable(xd->mclear);
1199
    } else {
1206
    } else {
1200
	disable(xd->mnext);
1207
	disable(xd->mnext);
1201
	disable(xd->mprev);
1208
	disable(xd->mprev);
1202
	disable(xd->mreplace);
1209
	disable(xd->mreplace);
1203
	disable(xd->msvar);
1210
	disable(xd->msvar);
1204
	disable(xd->mclear);
1211
	disable(xd->mclear);
1205
    }
1212
    }
1206
    if (!xd->replaying)
1213
    if (!xd->replaying)
1207
	enable(xd->mgvar);
1214
	enable(xd->mgvar);
1208
    else
1215
    else
1209
	disable(xd->mgvar);
1216
	disable(xd->mgvar);
1210
    if ((dd->displayList != R_NilValue) && !xd->replaying) {
1217
    if ((dd->displayList != R_NilValue) && !xd->replaying) {
1211
	enable(xd->madd);
1218
	enable(xd->madd);
1212
	enable(xd->mprint);
1219
	enable(xd->mprint);
1213
	enable(xd->mpng);
1220
	enable(xd->mpng);
1214
	enable(xd->mbmp);
1221
	enable(xd->mbmp);
1215
	enable(xd->mjpeg50);
1222
	enable(xd->mjpeg50);
1216
	enable(xd->mjpeg75);
1223
	enable(xd->mjpeg75);
1217
	enable(xd->mjpeg100);
1224
	enable(xd->mjpeg100);
1218
	enable(xd->mwm);
1225
	enable(xd->mwm);
1219
	enable(xd->mps);
1226
	enable(xd->mps);
1220
	enable(xd->mpdf);
1227
	enable(xd->mpdf);
1221
	enable(xd->mclpwm);
1228
	enable(xd->mclpwm);
1222
	enable(xd->mclpbm);
1229
	enable(xd->mclpbm);
1223
    } else {
1230
    } else {
1224
	disable(xd->madd);
1231
	disable(xd->madd);
1225
	disable(xd->mprint);
1232
	disable(xd->mprint);
1226
	disable(xd->msubsave);
1233
	disable(xd->msubsave);
1227
	disable(xd->mpng);
1234
	disable(xd->mpng);
1228
	disable(xd->mbmp);
1235
	disable(xd->mbmp);
1229
	disable(xd->mjpeg50);
1236
	disable(xd->mjpeg50);
1230
	disable(xd->mjpeg75);
1237
	disable(xd->mjpeg75);
1231
	disable(xd->mjpeg100);
1238
	disable(xd->mjpeg100);
1232
	disable(xd->mwm);
1239
	disable(xd->mwm);
1233
	disable(xd->mps);
1240
	disable(xd->mps);
1234
	disable(xd->mpdf);
1241
	disable(xd->mpdf);
1235
	disable(xd->mclpwm);
1242
	disable(xd->mclpwm);
1236
	disable(xd->mclpbm);
1243
	disable(xd->mclpbm);
1237
    }
1244
    }
1238
    draw(xd->mbar);
1245
    draw(xd->mbar);
1239
#endif
1246
#endif
1240
}
1247
}
1241
 
1248
 
1242
 
1249
 
1243
        /********************************************************/
1250
        /********************************************************/
1244
	/* device_Open is not usually called directly by the 	*/
1251
	/* device_Open is not usually called directly by the 	*/
1245
	/* graphics engine;  it is usually only called from 	*/
1252
	/* graphics engine;  it is usually only called from 	*/
1246
	/* the device-driver entry point.			*/
1253
	/* the device-driver entry point.			*/
1247
	/* this function should set up all of the device-	*/
1254
	/* this function should set up all of the device-	*/
1248
	/* specific resources for a new device			*/
1255
	/* specific resources for a new device			*/
1249
	/* this function is given a new	structure for device-	*/
1256
	/* this function is given a new	structure for device-	*/
1250
	/* specific information AND it must FREE the structure 	*/
1257
	/* specific information AND it must FREE the structure 	*/
1251
	/* if anything goes seriously wrong			*/
1258
	/* if anything goes seriously wrong			*/
1252
	/* NOTE that it is perfectly acceptable for this 	*/
1259
	/* NOTE that it is perfectly acceptable for this 	*/
1253
	/* function to set generic graphics parameters too	*/
1260
	/* function to set generic graphics parameters too	*/
1254
	/* (i.e., override the generic parameter settings	*/
1261
	/* (i.e., override the generic parameter settings	*/
1255
	/* which GInit sets up) all at the author's own risk	*/
1262
	/* which GInit sets up) all at the author's own risk	*/
1256
	/* of course :)						*/
1263
	/* of course :)						*/
1257
	/********************************************************/
1264
	/********************************************************/
1258
 
1265
 
1259
#define MCHECK(m) {if(!(m)) {del(xd->gawin); return 0;}}
1266
#define MCHECK(m) {if(!(m)) {del(xd->gawin); return 0;}}
1260
 
1267
 
1261
static void devga_sbf(control c, int pos)
1268
static void devga_sbf(control c, int pos)
1262
{
1269
{
1263
    NewDevDesc *dd = (NewDevDesc *) getdata(c);
1270
    NewDevDesc *dd = (NewDevDesc *) getdata(c);
1264
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1271
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1265
    if (pos < 0) {
1272
    if (pos < 0) {
1266
	pos = -pos-1;
1273
	pos = -pos-1;
1267
	pos = min(pos*SF, (xd->origWidth - xd->windowWidth + SF-1));
1274
	pos = min(pos*SF, (xd->origWidth - xd->windowWidth + SF-1));
1268
	xd->xshift = -pos;
1275
	xd->xshift = -pos;
1269
    } else {
1276
    } else {
1270
	pos = min(pos*SF, (xd->origHeight - xd->windowHeight + SF-1));
1277
	pos = min(pos*SF, (xd->origHeight - xd->windowHeight + SF-1));
1271
	xd->yshift = -pos;
1278
	xd->yshift = -pos;
1272
    }
1279
    }
1273
    xd->resize = 1;
1280
    xd->resize = 1;
1274
    HelpExpose(c, getrect(xd->gawin));
1281
    HelpExpose(c, getrect(xd->gawin));
1275
}
1282
}
1276
 
1283
 
1277
 
1284
 
1278
static int
1285
static int
1279
setupScreenDevice(NewDevDesc *dd, gadesc *xd, double w, double h,
1286
setupScreenDevice(NewDevDesc *dd, gadesc *xd, double w, double h,
1280
		  Rboolean recording, int resize, int xpos, int ypos)
1287
		  Rboolean recording, int resize, int xpos, int ypos)
1281
{
1288
{
1282
    menu  m;
1289
    menu  m;
1283
    int   iw, ih;
1290
    int   iw, ih;
1284
    int   cw, ch;
1291
    int   cw, ch;
1285
    double dw, dw0, dh, d;
1292
    double dw, dw0, dh, d;
1286
 
1293
 
1287
    xd->kind = SCREEN;
1294
    xd->kind = SCREEN;
1288
    if (R_finite(user_xpinch) && user_xpinch > 0.0)
1295
    if (R_finite(user_xpinch) && user_xpinch > 0.0)
1289
	dw = dw0 = (int) (w * user_xpinch);
1296
	dw = dw0 = (int) (w * user_xpinch);
1290
    else
1297
    else
1291
	dw = dw0 = (int) (w / pixelWidth(NULL));
1298
	dw = dw0 = (int) (w / pixelWidth(NULL));
1292
    if (R_finite(user_ypinch) && user_ypinch > 0.0)
1299
    if (R_finite(user_ypinch) && user_ypinch > 0.0)
1293
	dh = (int) (w * user_ypinch);
1300
	dh = (int) (w * user_ypinch);
1294
    else
1301
    else
1295
	dh = (int) (h / pixelHeight(NULL));
1302
	dh = (int) (h / pixelHeight(NULL));
1296
 
1303
 
1297
    if (ismdi()) {
1304
    if (ismdi()) {
1298
	cw = RgetMDIwidth();
1305
	cw = RgetMDIwidth();
1299
	ch = RgetMDIheight();
1306
	ch = RgetMDIheight();
1300
    } else {
1307
    } else {
1301
	cw = devicewidth(NULL);
1308
	cw = devicewidth(NULL);
1302
	ch = deviceheight(NULL);
1309
	ch = deviceheight(NULL);
1303
    }
1310
    }
1304
 
1311
 
1305
    if (resize != 3) {
1312
    if (resize != 3) {
1306
	if ((dw / cw) > 0.85) {
1313
	if ((dw / cw) > 0.85) {
1307
	    d = dh / dw;
1314
	    d = dh / dw;
1308
	    dw = 0.85 * cw;
1315
	    dw = 0.85 * cw;
1309
	    dh = d * dw;
1316
	    dh = d * dw;
1310
	}
1317
	}
1311
	if ((dh / ch) > 0.85) {
1318
	if ((dh / ch) > 0.85) {
1312
	    d = dw / dh;
1319
	    d = dw / dh;
1313
	    dh = 0.85 * ch;
1320
	    dh = 0.85 * ch;
1314
	    dw = d * dh;
1321
	    dw = d * dh;
1315
	}
1322
	}
1316
    } else {
1323
    } else {
1317
	dw = min(dw, 0.85*cw);
1324
	dw = min(dw, 0.85*cw);
1318
	dh = min(dh, 0.85*ch);
1325
	dh = min(dh, 0.85*ch);
1319
    }
1326
    }
1320
    iw = dw + 0.5;
1327
    iw = dw + 0.5;
1321
    ih = dh + 0.5;
1328
    ih = dh + 0.5;
1322
    if (resize == 2) xd->rescale_factor = dw/dw0;
1329
    if (resize == 2) xd->rescale_factor = dw/dw0;
1323
    {
1330
    {
1324
	int grx, gry;
1331
	int grx, gry;
1325
	grx = (xpos == NA_INTEGER) ? graphicsx : xpos;
1332
	grx = (xpos == NA_INTEGER) ? graphicsx : xpos;
1326
	gry = (ypos == NA_INTEGER) ? graphicsy : ypos;
1333
	gry = (ypos == NA_INTEGER) ? graphicsy : ypos;
1327
	if (grx < 0) grx = cw - iw + grx;
1334
	if (grx < 0) grx = cw - iw + grx;
1328
	if (gry < 0) gry = ch - ih + gry;
1335
	if (gry < 0) gry = ch - ih + gry;
1329
	if (!(xd->gawin = newwindow("R Graphics",
1336
	if (!(xd->gawin = newwindow("R Graphics",
1330
				    rect(grx, gry, iw, ih),
1337
				    rect(grx, gry, iw, ih),
1331
				    Document | StandardWindow | Menubar |
1338
				    Document | StandardWindow | Menubar |
1332
				    VScrollbar | HScrollbar)))
1339
				    VScrollbar | HScrollbar)))
1333
	    return 0;
1340
	    return 0;
1334
    }
1341
    }
1335
    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1342
    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1336
    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1343
    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1337
 
1344
 
1338
    addto(xd->gawin);
1345
    addto(xd->gawin);
1339
    gsetcursor(xd->gawin, ArrowCursor);
1346
    gsetcursor(xd->gawin, ArrowCursor);
1340
    if (ismdi() && (RguiMDI & RW_TOOLBAR)) {
1347
    if (ismdi() && (RguiMDI & RW_TOOLBAR)) {
1341
	int btsize = 24;
1348
	int btsize = 24;
1342
	rect r = rect(2, 2, btsize, btsize);
1349
	rect r = rect(2, 2, btsize, btsize);
1343
	control bt, tb;
1350
	control bt, tb;
1344
 
1351
 
1345
	MCHECK(tb = newtoolbar(btsize + 4));
1352
	MCHECK(tb = newtoolbar(btsize + 4));
1346
	gsetcursor(tb, ArrowCursor);
1353
	gsetcursor(tb, ArrowCursor);
1347
	addto(tb);
1354
	addto(tb);
1348
 
1355
 
1349
	MCHECK(bt = newtoolbutton(cam_image, r, menuclpwm));
1356
	MCHECK(bt = newtoolbutton(cam_image, r, menuclpwm));
1350
	MCHECK(addtooltip(bt, "Copy to the clipboard as a metafile"));
1357
	MCHECK(addtooltip(bt, "Copy to the clipboard as a metafile"));
1351
	gsetcursor(bt, ArrowCursor);
1358
	gsetcursor(bt, ArrowCursor);
1352
	setdata(bt, (void *) dd);
1359
	setdata(bt, (void *) dd);
1353
	r.x += (btsize + 6);
1360
	r.x += (btsize + 6);
1354
 
1361
 
1355
	MCHECK(bt = newtoolbutton(print_image, r, menuprint));
1362
	MCHECK(bt = newtoolbutton(print_image, r, menuprint));
1356
	MCHECK(addtooltip(bt, "Print"));
1363
	MCHECK(addtooltip(bt, "Print"));
1357
	gsetcursor(bt, ArrowCursor);
1364
	gsetcursor(bt, ArrowCursor);
1358
	setdata(bt, (void *) dd);
1365
	setdata(bt, (void *) dd);
1359
	r.x += (btsize + 6);
1366
	r.x += (btsize + 6);
1360
 
1367
 
1361
	MCHECK(bt = newtoolbutton(console_image, r, menuconsole));
1368
	MCHECK(bt = newtoolbutton(console_image, r, menuconsole));
1362
	MCHECK(addtooltip(bt, "Return focus to console"));
1369
	MCHECK(addtooltip(bt, "Return focus to console"));
1363
	gsetcursor(bt, ArrowCursor);
1370
	gsetcursor(bt, ArrowCursor);
1364
	setdata(bt, (void *) dd);
1371
	setdata(bt, (void *) dd);
1365
	r.x += (btsize + 6);
1372
	r.x += (btsize + 6);
1366
 
1373
 
1367
	MCHECK(xd->stoploc = newtoolbutton(stop_image, r, menustop));
1374
	MCHECK(xd->stoploc = newtoolbutton(stop_image, r, menustop));
1368
	MCHECK(addtooltip(xd->stoploc, "Stop locator"));
1375
	MCHECK(addtooltip(xd->stoploc, "Stop locator"));
1369
	gsetcursor(bt, ArrowCursor);
1376
	gsetcursor(bt, ArrowCursor);
1370
	setdata(xd->stoploc,(void *) dd);
1377
	setdata(xd->stoploc,(void *) dd);
1371
	hide(xd->stoploc);
1378
	hide(xd->stoploc);
1372
    } else
1379
    } else
1373
	xd->stoploc = NULL;
1380
	xd->stoploc = NULL;
1374
 
1381
 
1375
    /* First we prepare 'locator' menubar and popup */
1382
    /* First we prepare 'locator' menubar and popup */
1376
    addto(xd->gawin);
1383
    addto(xd->gawin);
1377
    MCHECK(xd->mbarloc = newmenubar(NULL));
1384
    MCHECK(xd->mbarloc = newmenubar(NULL));
1378
    MCHECK(newmenu("Stop"));
1385
    MCHECK(newmenu("Stop"));
1379
    MCHECK(m = newmenuitem("Stop locator", 0, menustop));
1386
    MCHECK(m = newmenuitem("Stop locator", 0, menustop));
1380
    setdata(m, (void *) dd);
1387
    setdata(m, (void *) dd);
1381
    MCHECK(xd->locpopup = newpopup(NULL));
1388
    MCHECK(xd->locpopup = newpopup(NULL));
1382
    MCHECK(m = newmenuitem("Stop", 0, menustop));
1389
    MCHECK(m = newmenuitem("Stop", 0, menustop));
1383
    setdata(m, (void *) dd);
1390
    setdata(m, (void *) dd);
1384
    MCHECK(newmenuitem("Continue", 0, NULL));
1391
    MCHECK(newmenuitem("Continue", 0, NULL));
1385
 
1392
 
1386
    /* Normal menubar */
1393
    /* Normal menubar */
1387
    MCHECK(xd->mbar = newmenubar(mbarf));
1394
    MCHECK(xd->mbar = newmenubar(mbarf));
1388
    MCHECK(m = newmenu("File"));
1395
    MCHECK(m = newmenu("File"));
1389
    MCHECK(xd->msubsave = newsubmenu(m, "Save as"));
1396
    MCHECK(xd->msubsave = newsubmenu(m, "Save as"));
1390
    MCHECK(xd->mwm = newmenuitem("Metafile...", 0, menuwm));
1397
    MCHECK(xd->mwm = newmenuitem("Metafile...", 0, menuwm));
1391
    MCHECK(xd->mps = newmenuitem("Postscript...", 0, menups));
1398
    MCHECK(xd->mps = newmenuitem("Postscript...", 0, menups));
1392
    MCHECK(xd->mpdf = newmenuitem("PDF...", 0, menupdf));
1399
    MCHECK(xd->mpdf = newmenuitem("PDF...", 0, menupdf));
1393
    MCHECK(xd->mpng = newmenuitem("Png...", 0, menufilebitmap));
1400
    MCHECK(xd->mpng = newmenuitem("Png...", 0, menufilebitmap));
1394
    MCHECK(xd->mbmp = newmenuitem("Bmp...", 0, menufilebitmap));
1401
    MCHECK(xd->mbmp = newmenuitem("Bmp...", 0, menufilebitmap));
1395
    MCHECK(newsubmenu(xd->msubsave,"Jpeg"));
1402
    MCHECK(newsubmenu(xd->msubsave,"Jpeg"));
1396
    MCHECK(xd->mjpeg50 = newmenuitem("50% quality...", 0, menufilebitmap));
1403
    MCHECK(xd->mjpeg50 = newmenuitem("50% quality...", 0, menufilebitmap));
1397
    MCHECK(xd->mjpeg75 = newmenuitem("75% quality...", 0, menufilebitmap));
1404
    MCHECK(xd->mjpeg75 = newmenuitem("75% quality...", 0, menufilebitmap));
1398
    MCHECK(xd->mjpeg100 = newmenuitem("100% quality...", 0, menufilebitmap));
1405
    MCHECK(xd->mjpeg100 = newmenuitem("100% quality...", 0, menufilebitmap));
1399
    MCHECK(newsubmenu(m, "Copy to the clipboard"));
1406
    MCHECK(newsubmenu(m, "Copy to the clipboard"));
1400
    MCHECK(xd->mclpbm = newmenuitem("as a Bitmap\tCTRL+C", 0, menuclpbm));
1407
    MCHECK(xd->mclpbm = newmenuitem("as a Bitmap\tCTRL+C", 0, menuclpbm));
1401
    MCHECK(xd->mclpwm = newmenuitem("as a Metafile\tCTRL+W", 0, menuclpwm));
1408
    MCHECK(xd->mclpwm = newmenuitem("as a Metafile\tCTRL+W", 0, menuclpwm));
1402
    addto(m);
1409
    addto(m);
1403
    MCHECK(newmenuitem("-", 0, NULL));
1410
    MCHECK(newmenuitem("-", 0, NULL));
1404
    MCHECK(xd->mprint = newmenuitem("Print...\tCTRL+P", 0, menuprint));
1411
    MCHECK(xd->mprint = newmenuitem("Print...\tCTRL+P", 0, menuprint));
1405
    MCHECK(newmenuitem("-", 0, NULL));
1412
    MCHECK(newmenuitem("-", 0, NULL));
1406
    MCHECK(xd->mclose = newmenuitem("close Device", 0, menuclose));
1413
    MCHECK(xd->mclose = newmenuitem("close Device", 0, menuclose));
1407
#ifdef PLOTHISTORY
1414
#ifdef PLOTHISTORY
1408
    MCHECK(newmenu("History"));
1415
    MCHECK(newmenu("History"));
1409
    MCHECK(xd->mrec = newmenuitem("Recording", 0, menurec));
1416
    MCHECK(xd->mrec = newmenuitem("Recording", 0, menurec));
1410
    if(recording) check(xd->mrec);
1417
    if(recording) check(xd->mrec);
1411
    MCHECK(newmenuitem("-", 0, NULL));
1418
    MCHECK(newmenuitem("-", 0, NULL));
1412
    MCHECK(xd->madd = newmenuitem("Add\tINS", 0, menuadd));
1419
    MCHECK(xd->madd = newmenuitem("Add\tINS", 0, menuadd));
1413
    MCHECK(xd->mreplace = newmenuitem("Replace", 0, menureplace));
1420
    MCHECK(xd->mreplace = newmenuitem("Replace", 0, menureplace));
1414
    MCHECK(newmenuitem("-", 0, NULL));
1421
    MCHECK(newmenuitem("-", 0, NULL));
1415
    MCHECK(xd->mprev = newmenuitem("Previous\tPgUp", 0, menuprev));
1422
    MCHECK(xd->mprev = newmenuitem("Previous\tPgUp", 0, menuprev));
1416
    MCHECK(xd->mnext = newmenuitem("Next\tPgDown", 0, menunext));
1423
    MCHECK(xd->mnext = newmenuitem("Next\tPgDown", 0, menunext));
1417
    MCHECK(newmenuitem("-", 0, NULL));
1424
    MCHECK(newmenuitem("-", 0, NULL));
1418
    MCHECK(xd->msvar = newmenuitem("Save to variable...", 0, menusvar));
1425
    MCHECK(xd->msvar = newmenuitem("Save to variable...", 0, menusvar));
1419
    MCHECK(xd->mgvar = newmenuitem("Get from variable...", 0, menugvar));
1426
    MCHECK(xd->mgvar = newmenuitem("Get from variable...", 0, menugvar));
1420
    MCHECK(newmenuitem("-", 0, NULL));
1427
    MCHECK(newmenuitem("-", 0, NULL));
1421
    MCHECK(xd->mclear = newmenuitem("Clear history", 0, menuclear));
1428
    MCHECK(xd->mclear = newmenuitem("Clear history", 0, menuclear));
1422
#endif
1429
#endif
1423
    MCHECK(newmenu("Resize"));
1430
    MCHECK(newmenu("Resize"));
1424
    MCHECK(xd->mR = newmenuitem("R mode", 0, menuR));
1431
    MCHECK(xd->mR = newmenuitem("R mode", 0, menuR));
1425
    if(resize == 1) check(xd->mR);
1432
    if(resize == 1) check(xd->mR);
1426
    MCHECK(xd->mfit = newmenuitem("Fit to window", 0, menufit));
1433
    MCHECK(xd->mfit = newmenuitem("Fit to window", 0, menufit));
1427
    if(resize == 2) check(xd->mfit);
1434
    if(resize == 2) check(xd->mfit);
1428
    MCHECK(xd->mfix = newmenuitem("Fixed size", 0, menufix));
1435
    MCHECK(xd->mfix = newmenuitem("Fixed size", 0, menufix));
1429
    if(resize == 3) check(xd->mfix);
1436
    if(resize == 3) check(xd->mfix);
1430
    newmdimenu();
1437
    newmdimenu();
1431
 
1438
 
1432
    /* Normal popup */
1439
    /* Normal popup */
1433
    MCHECK(xd->grpopup = newpopup(NULL));
1440
    MCHECK(xd->grpopup = newpopup(grpopupact));
-
 
1441
    setdata(xd->grpopup, (void *) dd);
1434
    MCHECK(m = newmenuitem("Copy as metafile", 0, menuclpwm));
1442
    MCHECK(m = newmenuitem("Copy as metafile", 0, menuclpwm));
1435
    setdata(m, (void *) dd);
1443
    setdata(m, (void *) dd);
1436
    MCHECK(m = newmenuitem("Copy as bitmap", 0, menuclpbm));
1444
    MCHECK(m = newmenuitem("Copy as bitmap", 0, menuclpbm));
1437
    setdata(m, (void *) dd);
1445
    setdata(m, (void *) dd);
1438
    MCHECK(newmenuitem("-", 0, NULL));
1446
    MCHECK(newmenuitem("-", 0, NULL));
1439
    MCHECK(m = newmenuitem("Save as metafile...", 0, menuwm));
1447
    MCHECK(m = newmenuitem("Save as metafile...", 0, menuwm));
1440
    setdata(m, (void *) dd);
1448
    setdata(m, (void *) dd);
1441
    MCHECK(m = newmenuitem("Save as postscript...", 0, menups));
1449
    MCHECK(m = newmenuitem("Save as postscript...", 0, menups));
1442
    setdata(m, (void *) dd);
1450
    setdata(m, (void *) dd);
1443
    if (!ismdi()) {
-
 
1444
	MCHECK(newmenuitem("-", 0, NULL));
1451
    MCHECK(newmenuitem("-", 0, NULL));
1445
    	MCHECK(m = newmenuitem("Stay on top", 0, menustayontop));
1452
    MCHECK(xd->grmenustayontop = newmenuitem("Stay on top", 0, menustayontop));
1446
    	setdata(m, (void *) dd);
1453
    setdata(xd->grmenustayontop, (void *) dd);
1447
    }
-
 
1448
    MCHECK(newmenuitem("-", 0, NULL));
1454
    MCHECK(newmenuitem("-", 0, NULL));
1449
    MCHECK(m = newmenuitem("Print...", 0, menuprint));
1455
    MCHECK(m = newmenuitem("Print...", 0, menuprint));
1450
    setdata(m, (void *) dd);
1456
    setdata(m, (void *) dd);
1451
    gchangepopup(xd->gawin, xd->grpopup);
1457
    gchangepopup(xd->gawin, xd->grpopup);
1452
 
1458
 
1453
    MCHECK(xd->bm = newbitmap(getwidth(xd->gawin), getheight(xd->gawin),
1459
    MCHECK(xd->bm = newbitmap(getwidth(xd->gawin), getheight(xd->gawin),
1454
			      getdepth(xd->gawin)));
1460
			      getdepth(xd->gawin)));
1455
    gfillrect(xd->gawin, xd->outcolor, getrect(xd->gawin));
1461
    gfillrect(xd->gawin, xd->outcolor, getrect(xd->gawin));
1456
    gfillrect(xd->bm, xd->outcolor, getrect(xd->bm));
1462
    gfillrect(xd->bm, xd->outcolor, getrect(xd->bm));
1457
    addto(xd->gawin);
1463
    addto(xd->gawin);
1458
    setdata(xd->mbar, (void *) dd);
1464
    setdata(xd->mbar, (void *) dd);
1459
    setdata(xd->mpng, (void *) dd);
1465
    setdata(xd->mpng, (void *) dd);
1460
    setdata(xd->mbmp, (void *) dd);
1466
    setdata(xd->mbmp, (void *) dd);
1461
    setdata(xd->mjpeg50, (void *) dd);
1467
    setdata(xd->mjpeg50, (void *) dd);
1462
    setdata(xd->mjpeg75, (void *) dd);
1468
    setdata(xd->mjpeg75, (void *) dd);
1463
    setdata(xd->mjpeg100, (void *) dd);
1469
    setdata(xd->mjpeg100, (void *) dd);
1464
    setdata(xd->mps, (void *) dd);
1470
    setdata(xd->mps, (void *) dd);
1465
    setdata(xd->mpdf, (void *) dd);
1471
    setdata(xd->mpdf, (void *) dd);
1466
    setdata(xd->mwm, (void *) dd);
1472
    setdata(xd->mwm, (void *) dd);
1467
    setdata(xd->mclpwm, (void *) dd);
1473
    setdata(xd->mclpwm, (void *) dd);
1468
    setdata(xd->mclpbm, (void *) dd);
1474
    setdata(xd->mclpbm, (void *) dd);
1469
    setdata(xd->mprint, (void *) dd);
1475
    setdata(xd->mprint, (void *) dd);
1470
    setdata(xd->mclose, (void *) dd);
1476
    setdata(xd->mclose, (void *) dd);
1471
    setdata(xd->mrec, (void *) dd);
1477
    setdata(xd->mrec, (void *) dd);
1472
    setdata(xd->mprev, (void *) dd);
1478
    setdata(xd->mprev, (void *) dd);
1473
    setdata(xd->mnext, (void *) dd);
1479
    setdata(xd->mnext, (void *) dd);
1474
    setdata(xd->mgvar, (void *) dd);
1480
    setdata(xd->mgvar, (void *) dd);
1475
    setdata(xd->madd, (void *) dd);
1481
    setdata(xd->madd, (void *) dd);
1476
    setdata(xd->mreplace, (void *) dd);
1482
    setdata(xd->mreplace, (void *) dd);
1477
    setdata(xd->mR, (void *) dd);
1483
    setdata(xd->mR, (void *) dd);
1478
    setdata(xd->mfit, (void *) dd);
1484
    setdata(xd->mfit, (void *) dd);
1479
    setdata(xd->mfix, (void *) dd);
1485
    setdata(xd->mfix, (void *) dd);
1480
    show(xd->gawin); /* twice, for a Windows bug */
1486
    show(xd->gawin); /* twice, for a Windows bug */
1481
    show(xd->gawin);
1487
    show(xd->gawin);
1482
    BringToTop(xd->gawin, 0);
1488
    BringToTop(xd->gawin, 0);
1483
    sethit(xd->gawin, devga_sbf);
1489
    sethit(xd->gawin, devga_sbf);
1484
    setresize(xd->gawin, HelpResize);
1490
    setresize(xd->gawin, HelpResize);
1485
    setredraw(xd->gawin, HelpExpose);
1491
    setredraw(xd->gawin, HelpExpose);
1486
    setmousedown(xd->gawin, HelpMouseClick);
1492
    setmousedown(xd->gawin, HelpMouseClick);
1487
    setkeydown(xd->gawin, NHelpKeyIn);
1493
    setkeydown(xd->gawin, NHelpKeyIn);
1488
    setkeyaction(xd->gawin, CHelpKeyIn);
1494
    setkeyaction(xd->gawin, CHelpKeyIn);
1489
    setclose(xd->gawin, HelpClose);
1495
    setclose(xd->gawin, HelpClose);
1490
    xd->recording = recording;
1496
    xd->recording = recording;
1491
    xd->replaying = FALSE;
1497
    xd->replaying = FALSE;
1492
    xd->resizing = resize;
1498
    xd->resizing = resize;
1493
 
1499
 
1494
    return 1;
1500
    return 1;
1495
}
1501
}
1496
 
1502
 
1497
static Rboolean GA_Open(NewDevDesc *dd, gadesc *xd, char *dsp,
1503
static Rboolean GA_Open(NewDevDesc *dd, gadesc *xd, char *dsp,
1498
			double w, double h, Rboolean recording,
1504
			double w, double h, Rboolean recording,
1499
			int resize, int canvascolor, double gamma,
1505
			int resize, int canvascolor, double gamma,
1500
			int xpos, int ypos)
1506
			int xpos, int ypos)
1501
{
1507
{
1502
    rect  rr;
1508
    rect  rr;
1503
    char buf[600]; /* allow for pageno formats */
1509
    char buf[600]; /* allow for pageno formats */
1504
 
1510
 
1505
    if (!fontinitdone)
1511
    if (!fontinitdone)
1506
	RFontInit();
1512
	RFontInit();
1507
 
1513
 
1508
    /* Foreground and Background Colors */
1514
    /* Foreground and Background Colors */
1509
    xd->bg = dd->startfill = 0xffffffff; /* transparent */
1515
    xd->bg = dd->startfill = 0xffffffff; /* transparent */
1510
    xd->col = dd->startcol = R_RGB(0, 0, 0);
1516
    xd->col = dd->startcol = R_RGB(0, 0, 0);
1511
 
1517
 
1512
    xd->fgcolor = Black;
1518
    xd->fgcolor = Black;
1513
    xd->bgcolor = xd->canvascolor = GArgb(canvascolor, gamma);
1519
    xd->bgcolor = xd->canvascolor = GArgb(canvascolor, gamma);
1514
    xd->outcolor = myGetSysColor(COLOR_APPWORKSPACE);
1520
    xd->outcolor = myGetSysColor(COLOR_APPWORKSPACE);
1515
    xd->rescale_factor = 1.0;
1521
    xd->rescale_factor = 1.0;
1516
    xd->fast = 1;  /* Use `cosmetic pens' if available */
1522
    xd->fast = 1;  /* Use `cosmetic pens' if available */
1517
    xd->xshift = xd->yshift = 0;
1523
    xd->xshift = xd->yshift = 0;
1518
    xd->npage = 0;
1524
    xd->npage = 0;
1519
    if (!dsp[0]) {
1525
    if (!dsp[0]) {
1520
	if (!setupScreenDevice(dd, xd, w, h, recording, resize, xpos, ypos))
1526
	if (!setupScreenDevice(dd, xd, w, h, recording, resize, xpos, ypos))
1521
	    return FALSE;
1527
	    return FALSE;
1522
    } else if (!strncmp(dsp, "win.print:", 10)) {
1528
    } else if (!strncmp(dsp, "win.print:", 10)) {
1523
	xd->kind = PRINTER;
1529
	xd->kind = PRINTER;
1524
	xd->gawin = newprinter(MM_PER_INCH * w, MM_PER_INCH * h, &dsp[10]);
1530
	xd->gawin = newprinter(MM_PER_INCH * w, MM_PER_INCH * h, &dsp[10]);
1525
	if (!xd->gawin)
1531
	if (!xd->gawin)
1526
	    return FALSE;
1532
	    return FALSE;
1527
    } else if (!strncmp(dsp, "png:", 4) || !strncmp(dsp,"bmp:", 4)) {
1533
    } else if (!strncmp(dsp, "png:", 4) || !strncmp(dsp,"bmp:", 4)) {
1528
	if(R_OPAQUE(canvascolor))
1534
	if(R_OPAQUE(canvascolor))
1529
	    xd->bg = dd->startfill = GArgb(canvascolor, 1.0);
1535
	    xd->bg = dd->startfill = GArgb(canvascolor, 1.0);
1530
	else
1536
	else
1531
	    xd->bg = dd->startfill = canvascolor;
1537
	    xd->bg = dd->startfill = canvascolor;
1532
	/* was R_RGB(255, 255, 255); white */
1538
	/* was R_RGB(255, 255, 255); white */
1533
        xd->kind = (dsp[0]=='p') ? PNG : BMP;
1539
        xd->kind = (dsp[0]=='p') ? PNG : BMP;
1534
	if(strlen(dsp+4) >= 512) error("filename too long in %s() call",
1540
	if(strlen(dsp+4) >= 512) error("filename too long in %s() call",
1535
				       (dsp[0]=='p') ? "png" : "bmp");
1541
				       (dsp[0]=='p') ? "png" : "bmp");
1536
	strcpy(xd->filename, dsp+4);
1542
	strcpy(xd->filename, dsp+4);
1537
	if (!Load_Rbitmap_Dll()) {
1543
	if (!Load_Rbitmap_Dll()) {
1538
	    warning("Unable to load Rbitmap.dll");
1544
	    warning("Unable to load Rbitmap.dll");
1539
	    return FALSE;
1545
	    return FALSE;
1540
	}
1546
	}
1541
	/*
1547
	/*
1542
	  Observe that given actual graphapp implementation 256 is
1548
	  Observe that given actual graphapp implementation 256 is
1543
	  irrelevant,i.e., depth of the bitmap is the one of graphic card
1549
	  irrelevant,i.e., depth of the bitmap is the one of graphic card
1544
	  if required depth > 1
1550
	  if required depth > 1
1545
	*/
1551
	*/
1546
	if ((xd->gawin = newbitmap(w, h, 256)) == NULL) {
1552
	if ((xd->gawin = newbitmap(w, h, 256)) == NULL) {
1547
	    warning("Unable to allocate bitmap");
1553
	    warning("Unable to allocate bitmap");
1548
	    return FALSE;
1554
	    return FALSE;
1549
	}
1555
	}
1550
	snprintf(buf, 600, xd->filename, 1);
1556
	snprintf(buf, 600, xd->filename, 1);
1551
	if ((xd->fp = fopen(buf, "wb")) == NULL) {
1557
	if ((xd->fp = fopen(buf, "wb")) == NULL) {
1552
	    del(xd->gawin);
1558
	    del(xd->gawin);
1553
	    warning("Unable to open file `%s' for writing", buf);
1559
	    warning("Unable to open file `%s' for writing", buf);
1554
	    return FALSE;
1560
	    return FALSE;
1555
	}
1561
	}
1556
    } else if (!strncmp(dsp, "jpeg:", 5)) {
1562
    } else if (!strncmp(dsp, "jpeg:", 5)) {
1557
        char *p = strchr(&dsp[5], ':');
1563
        char *p = strchr(&dsp[5], ':');
1558
	xd->bg = dd->startfill = GArgb(canvascolor, 1.0);
1564
	xd->bg = dd->startfill = GArgb(canvascolor, 1.0);
1559
        xd->kind = JPEG;
1565
        xd->kind = JPEG;
1560
	if (!p) return FALSE;
1566
	if (!p) return FALSE;
1561
	if (!Load_Rbitmap_Dll()) {
1567
	if (!Load_Rbitmap_Dll()) {
1562
	    warning("Unable to load Rbitmap.dll");
1568
	    warning("Unable to load Rbitmap.dll");
1563
	    return FALSE;
1569
	    return FALSE;
1564
	}
1570
	}
1565
	*p = '\0';
1571
	*p = '\0';
1566
	xd->quality = atoi(&dsp[5]);
1572
	xd->quality = atoi(&dsp[5]);
1567
	*p = ':' ;
1573
	*p = ':' ;
1568
	if(strlen(p+1) >= 512) error("filename too long in jpeg() call");
1574
	if(strlen(p+1) >= 512) error("filename too long in jpeg() call");
1569
	strcpy(xd->filename, p+1);
1575
	strcpy(xd->filename, p+1);
1570
	if((xd->gawin = newbitmap(w, h, 256)) == NULL) {
1576
	if((xd->gawin = newbitmap(w, h, 256)) == NULL) {
1571
	    warning("Unable to allocate bitmap");
1577
	    warning("Unable to allocate bitmap");
1572
	    return FALSE;
1578
	    return FALSE;
1573
	}
1579
	}
1574
	snprintf(buf, 600, xd->filename, 1);
1580
	snprintf(buf, 600, xd->filename, 1);
1575
	if ((xd->fp = fopen(buf, "wb")) == NULL) {
1581
	if ((xd->fp = fopen(buf, "wb")) == NULL) {
1576
	    del(xd->gawin);
1582
	    del(xd->gawin);
1577
	    warning("Unable to open file `%s' for writing", buf);
1583
	    warning("Unable to open file `%s' for writing", buf);
1578
	    return FALSE;
1584
	    return FALSE;
1579
	}
1585
	}
1580
    } else {
1586
    } else {
1581
	/*
1587
	/*
1582
	 * win.metafile[:] in memory (for the clipboard)
1588
	 * win.metafile[:] in memory (for the clipboard)
1583
	 * win.metafile:filename
1589
	 * win.metafile:filename
1584
	 * anything else return FALSE
1590
	 * anything else return FALSE
1585
	 */
1591
	 */
1586
	char  *s = "win.metafile";
1592
	char  *s = "win.metafile";
1587
	int   ls = strlen(s);
1593
	int   ls = strlen(s);
1588
	int   ld = strlen(dsp);
1594
	int   ld = strlen(dsp);
1589
 
1595
 
1590
	if (ls > ld)
1596
	if (ls > ld)
1591
	    return FALSE;
1597
	    return FALSE;
1592
	if (strncmp(dsp, s, ls) || (dsp[ls] && (dsp[ls] != ':')))
1598
	if (strncmp(dsp, s, ls) || (dsp[ls] && (dsp[ls] != ':')))
1593
	    return FALSE;
1599
	    return FALSE;
1594
	if(ld > ls && strlen(&dsp[ls + 1]) >= 512)
1600
	if(ld > ls && strlen(&dsp[ls + 1]) >= 512)
1595
	    error("filename too long in win.metafile() call");
1601
	    error("filename too long in win.metafile() call");
1596
	strcpy(xd->filename, (ld > ls) ? &dsp[ls + 1] : "");
1602
	strcpy(xd->filename, (ld > ls) ? &dsp[ls + 1] : "");
1597
	snprintf(buf, 600, xd->filename, 1);
1603
	snprintf(buf, 600, xd->filename, 1);
1598
	xd->w = MM_PER_INCH * w;
1604
	xd->w = MM_PER_INCH * w;
1599
	xd->h =  MM_PER_INCH * h;
1605
	xd->h =  MM_PER_INCH * h;
1600
	xd->gawin = newmetafile(buf, MM_PER_INCH * w, MM_PER_INCH * h);
1606
	xd->gawin = newmetafile(buf, MM_PER_INCH * w, MM_PER_INCH * h);
1601
	xd->kind = METAFILE;
1607
	xd->kind = METAFILE;
1602
	xd->fast = 0; /* use scalable line widths */
1608
	xd->fast = 0; /* use scalable line widths */
1603
	if (!xd->gawin) {
1609
	if (!xd->gawin) {
1604
	    if(ld > ls)
1610
	    if(ld > ls)
1605
		warning("Unable to open metafile `%s' for writing", buf);
1611
		warning("Unable to open metafile `%s' for writing", buf);
1606
	    else
1612
	    else
1607
		warning("Unable to open clipboard to write metafile");
1613
		warning("Unable to open clipboard to write metafile");
1608
	    return FALSE;
1614
	    return FALSE;
1609
	}
1615
	}
1610
    }
1616
    }
1611
    xd->truedpi = devicepixelsy(xd->gawin);
1617
    xd->truedpi = devicepixelsy(xd->gawin);
1612
    if ((xd->kind == PNG) || (xd->kind == JPEG) || (xd->kind == BMP))
1618
    if ((xd->kind == PNG) || (xd->kind == JPEG) || (xd->kind == BMP))
1613
      xd->wanteddpi = 72 ;
1619
      xd->wanteddpi = 72 ;
1614
    else
1620
    else
1615
      xd->wanteddpi = xd->truedpi;
1621
      xd->wanteddpi = xd->truedpi;
1616
    if (!SetBaseFont(xd)) {
1622
    if (!SetBaseFont(xd)) {
1617
	warning("can't find any fonts");
1623
	warning("can't find any fonts");
1618
	del(xd->gawin);
1624
	del(xd->gawin);
1619
	if (xd->kind == SCREEN) del(xd->bm);
1625
	if (xd->kind == SCREEN) del(xd->bm);
1620
	return FALSE;
1626
	return FALSE;
1621
    }
1627
    }
1622
    rr = getrect(xd->gawin);
1628
    rr = getrect(xd->gawin);
1623
    xd->origWidth = xd->showWidth = xd->windowWidth = rr.width;
1629
    xd->origWidth = xd->showWidth = xd->windowWidth = rr.width;
1624
    xd->origHeight = xd->showHeight = xd->windowHeight = rr.height;
1630
    xd->origHeight = xd->showHeight = xd->windowHeight = rr.height;
1625
    xd->clip = rr;
1631
    xd->clip = rr;
1626
    setdata(xd->gawin, (void *) dd);
1632
    setdata(xd->gawin, (void *) dd);
1627
    xd->needsave = FALSE;
1633
    xd->needsave = FALSE;
1628
    return TRUE;
1634
    return TRUE;
1629
}
1635
}
1630
 
1636
 
1631
	/********************************************************/
1637
	/********************************************************/
1632
	/* device_StrWidth should return the width of the given */
1638
	/* device_StrWidth should return the width of the given */
1633
	/* string in DEVICE units (GStrWidth is responsible for */
1639
	/* string in DEVICE units (GStrWidth is responsible for */
1634
	/* converting from DEVICE to whatever units the user 	*/
1640
	/* converting from DEVICE to whatever units the user 	*/
1635
	/* asked for						*/
1641
	/* asked for						*/
1636
	/********************************************************/
1642
	/********************************************************/
1637
 
1643
 
1638
static double GA_StrWidth(char *str,
1644
static double GA_StrWidth(char *str,
1639
			  R_GE_gcontext *gc,
1645
			  R_GE_gcontext *gc,
1640
			  NewDevDesc *dd)
1646
			  NewDevDesc *dd)
1641
{
1647
{
1642
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1648
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1643
    double a;
1649
    double a;
1644
    int   size = gc->cex * gc->ps + 0.5;
1650
    int   size = gc->cex * gc->ps + 0.5;
1645
 
1651
 
1646
    SetFont(gc->fontface, size, 0.0, dd);
1652
    SetFont(gc->fontface, size, 0.0, dd);
1647
    a = (double) gstrwidth(xd->gawin, xd->font, str);
1653
    a = (double) gstrwidth(xd->gawin, xd->font, str);
1648
    return a;
1654
    return a;
1649
}
1655
}
1650
 
1656
 
1651
 
1657
 
1652
	/********************************************************/
1658
	/********************************************************/
1653
	/* device_MetricInfo should return height, depth, and 	*/
1659
	/* device_MetricInfo should return height, depth, and 	*/
1654
	/* width information for the given character in DEVICE	*/
1660
	/* width information for the given character in DEVICE	*/
1655
	/* units (GMetricInfo does the necessary conversions)	*/
1661
	/* units (GMetricInfo does the necessary conversions)	*/
1656
	/* This is used for formatting mathematical expressions	*/
1662
	/* This is used for formatting mathematical expressions	*/
1657
	/********************************************************/
1663
	/********************************************************/
1658
 
1664
 
1659
	/* Character Metric Information */
1665
	/* Character Metric Information */
1660
	/* Passing c == 0 gets font information */
1666
	/* Passing c == 0 gets font information */
1661
 
1667
 
1662
static void GA_MetricInfo(int c,
1668
static void GA_MetricInfo(int c,
1663
			  R_GE_gcontext *gc,
1669
			  R_GE_gcontext *gc,
1664
			  double* ascent, double* descent,
1670
			  double* ascent, double* descent,
1665
			  double* width, NewDevDesc *dd)
1671
			  double* width, NewDevDesc *dd)
1666
{
1672
{
1667
    int   a, d, w;
1673
    int   a, d, w;
1668
    int   size = gc->cex * gc->ps + 0.5;
1674
    int   size = gc->cex * gc->ps + 0.5;
1669
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1675
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1670
 
1676
 
1671
    SetFont(gc->fontface, size, 0.0, dd);
1677
    SetFont(gc->fontface, size, 0.0, dd);
1672
    gcharmetric(xd->gawin, xd->font, c, &a, &d, &w);
1678
    gcharmetric(xd->gawin, xd->font, c, &a, &d, &w);
1673
    /* Some Windows systems report that space has height and depth,
1679
    /* Some Windows systems report that space has height and depth,
1674
       so we have a kludge.  Note that 32 is space in symbol font too */
1680
       so we have a kludge.  Note that 32 is space in symbol font too */
1675
    if(c == 32) {
1681
    if(c == 32) {
1676
	*ascent  = 0.0;
1682
	*ascent  = 0.0;
1677
	*descent = 0.0;
1683
	*descent = 0.0;
1678
	*width   = (double) w;
1684
	*width   = (double) w;
1679
 
1685
 
1680
    } else {
1686
    } else {
1681
	*ascent  = (double) a;
1687
	*ascent  = (double) a;
1682
	*descent = (double) d;
1688
	*descent = (double) d;
1683
	*width   = (double) w;
1689
	*width   = (double) w;
1684
    }
1690
    }
1685
}
1691
}
1686
 
1692
 
1687
	/********************************************************/
1693
	/********************************************************/
1688
	/* device_Clip is given the left, right, bottom, and 	*/
1694
	/* device_Clip is given the left, right, bottom, and 	*/
1689
	/* top of a rectangle (in DEVICE coordinates).  it 	*/
1695
	/* top of a rectangle (in DEVICE coordinates).  it 	*/
1690
	/* should have the side-effect that subsequent output	*/
1696
	/* should have the side-effect that subsequent output	*/
1691
	/* is clipped to the given rectangle			*/
1697
	/* is clipped to the given rectangle			*/
1692
	/********************************************************/
1698
	/********************************************************/
1693
 
1699
 
1694
static void GA_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
1700
static void GA_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
1695
{
1701
{
1696
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1702
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1697
 
1703
 
1698
    xd->clip = rcanon(rpt(pt(x0, y0), pt(x1, y1)));
1704
    xd->clip = rcanon(rpt(pt(x0, y0), pt(x1, y1)));
1699
    xd->clip.width  += 1;
1705
    xd->clip.width  += 1;
1700
    xd->clip.height += 1;
1706
    xd->clip.height += 1;
1701
}
1707
}
1702
 
1708
 
1703
	/********************************************************/
1709
	/********************************************************/
1704
	/* device_Resize is called whenever the device is 	*/
1710
	/* device_Resize is called whenever the device is 	*/
1705
	/* resized.  the function must update the GPar 		*/
1711
	/* resized.  the function must update the GPar 		*/
1706
	/* parameters (left, right, bottom, and top) for the 	*/
1712
	/* parameters (left, right, bottom, and top) for the 	*/
1707
	/* new device size					*/
1713
	/* new device size					*/
1708
	/* this is not usually called directly by the graphics	*/
1714
	/* this is not usually called directly by the graphics	*/
1709
	/* engine because the detection of device resizes	*/
1715
	/* engine because the detection of device resizes	*/
1710
	/* (e.g., a window resize) are usually detected by	*/
1716
	/* (e.g., a window resize) are usually detected by	*/
1711
	/* device-specific code	(see R_ProcessEvents in ./system.c)*/
1717
	/* device-specific code	(see R_ProcessEvents in ./system.c)*/
1712
	/********************************************************/
1718
	/********************************************************/
1713
 
1719
 
1714
static void GA_Size(double *left, double *right,
1720
static void GA_Size(double *left, double *right,
1715
		     double *bottom, double *top,
1721
		     double *bottom, double *top,
1716
		     NewDevDesc *dd)
1722
		     NewDevDesc *dd)
1717
{
1723
{
1718
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1724
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1719
 
1725
 
1720
    int   iw, ih;
1726
    int   iw, ih;
1721
 
1727
 
1722
    iw = xd->windowWidth;
1728
    iw = xd->windowWidth;
1723
    ih = xd->windowHeight;
1729
    ih = xd->windowHeight;
1724
    *left = 0.0;
1730
    *left = 0.0;
1725
    *top = 0.0;
1731
    *top = 0.0;
1726
    *right = iw;
1732
    *right = iw;
1727
    *bottom = ih;
1733
    *bottom = ih;
1728
}
1734
}
1729
 
1735
 
1730
static void GA_Resize(NewDevDesc *dd)
1736
static void GA_Resize(NewDevDesc *dd)
1731
{
1737
{
1732
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1738
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1733
    SEXP scale;
1739
    SEXP scale;
1734
    PROTECT(scale = allocVector(REALSXP, 1));
1740
    PROTECT(scale = allocVector(REALSXP, 1));
1735
    if (xd->resize) {
1741
    if (xd->resize) {
1736
	int   iw, ih, iw0 = dd->right - dd->left,
1742
	int   iw, ih, iw0 = dd->right - dd->left,
1737
	    ih0 = dd->bottom - dd->top;
1743
	    ih0 = dd->bottom - dd->top;
1738
	double fw, fh, rf, shift;
1744
	double fw, fh, rf, shift;
1739
 
1745
 
1740
	iw = xd->windowWidth;
1746
	iw = xd->windowWidth;
1741
	ih = xd->windowHeight;
1747
	ih = xd->windowHeight;
1742
	if(xd->resizing == 1) {
1748
	if(xd->resizing == 1) {
1743
	    /* last mode might have been 3, so remove scrollbars */
1749
	    /* last mode might have been 3, so remove scrollbars */
1744
	    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1750
	    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1745
	    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1751
	    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1746
	    dd->left = 0.0;
1752
	    dd->left = 0.0;
1747
	    dd->top = 0.0;
1753
	    dd->top = 0.0;
1748
	    dd->right = iw;
1754
	    dd->right = iw;
1749
	    dd->bottom = ih;
1755
	    dd->bottom = ih;
1750
	    xd->showWidth = iw;
1756
	    xd->showWidth = iw;
1751
	    xd->showHeight =  ih;
1757
	    xd->showHeight =  ih;
1752
	} else if (xd->resizing == 2) {
1758
	} else if (xd->resizing == 2) {
1753
	    /* last mode might have been 3, so remove scrollbars */
1759
	    /* last mode might have been 3, so remove scrollbars */
1754
	    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1760
	    gchangescrollbar(xd->gawin, VWINSB, 0, ih/SF-1, ih/SF, 0);
1755
	    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1761
	    gchangescrollbar(xd->gawin, HWINSB, 0, iw/SF-1, iw/SF, 0);
1756
	    fw = (iw + 0.5)/(iw0 + 0.5);
1762
	    fw = (iw + 0.5)/(iw0 + 0.5);
1757
	    fh = (ih + 0.5)/(ih0 + 0.5);
1763
	    fh = (ih + 0.5)/(ih0 + 0.5);
1758
	    rf = min(fw, fh);
1764
	    rf = min(fw, fh);
1759
	    xd->rescale_factor *= rf;
1765
	    xd->rescale_factor *= rf;
1760
	    xd->wanteddpi = xd->rescale_factor * xd->truedpi;
1766
	    xd->wanteddpi = xd->rescale_factor * xd->truedpi;
1761
	    /* dd->ps *= rf; dd->cra[0] *= rf; dd->cra[1] *= rf; */
1767
	    /* dd->ps *= rf; dd->cra[0] *= rf; dd->cra[1] *= rf; */
1762
	    REAL(scale)[0] = rf;
1768
	    REAL(scale)[0] = rf;
1763
	    GEHandleEvent(GE_ScalePS, dd, scale);
1769
	    GEHandleEvent(GE_ScalePS, dd, scale);
1764
	    if (fw < fh) {
1770
	    if (fw < fh) {
1765
		dd->left = 0.0;
1771
		dd->left = 0.0;
1766
		xd->showWidth = dd->right = iw;
1772
		xd->showWidth = dd->right = iw;
1767
		xd->showHeight =  ih0*fw;
1773
		xd->showHeight =  ih0*fw;
1768
		shift = (ih - xd->showHeight)/2.0;
1774
		shift = (ih - xd->showHeight)/2.0;
1769
		dd->top = shift;
1775
		dd->top = shift;
1770
		dd->bottom = ih0*fw + shift;
1776
		dd->bottom = ih0*fw + shift;
1771
		xd->xshift = 0; xd->yshift = shift;
1777
		xd->xshift = 0; xd->yshift = shift;
1772
	    } else {
1778
	    } else {
1773
		dd->top = 0.0;
1779
		dd->top = 0.0;
1774
		xd->showHeight = dd->bottom = ih;
1780
		xd->showHeight = dd->bottom = ih;
1775
		xd->showWidth = iw0*fh;
1781
		xd->showWidth = iw0*fh;
1776
		shift = (iw - xd->showWidth)/2.0;
1782
		shift = (iw - xd->showWidth)/2.0;
1777
		dd->left = shift;
1783
		dd->left = shift;
1778
		dd->right = iw0*fh + shift;
1784
		dd->right = iw0*fh + shift;
1779
		xd->xshift = shift; xd->yshift = 0;
1785
		xd->xshift = shift; xd->yshift = 0;
1780
	    }
1786
	    }
1781
	    xd->clip = getregion(xd);
1787
	    xd->clip = getregion(xd);
1782
	} else if (xd->resizing == 3) {
1788
	} else if (xd->resizing == 3) {
1783
	    if(iw0 < iw) shift = (iw - iw0)/2.0;
1789
	    if(iw0 < iw) shift = (iw - iw0)/2.0;
1784
	    else shift = min(0, xd->xshift);
1790
	    else shift = min(0, xd->xshift);
1785
	    dd->left = shift;
1791
	    dd->left = shift;
1786
	    dd->right = iw0 + shift;
1792
	    dd->right = iw0 + shift;
1787
	    xd->xshift = shift;
1793
	    xd->xshift = shift;
1788
	    gchangescrollbar(xd->gawin, HWINSB, max(-shift,0)/SF,
1794
	    gchangescrollbar(xd->gawin, HWINSB, max(-shift,0)/SF,
1789
			     xd->origWidth/SF - 1, xd->windowWidth/SF, 0);
1795
			     xd->origWidth/SF - 1, xd->windowWidth/SF, 0);
1790
	    if(ih0 < ih) shift = (ih - ih0)/2.0;
1796
	    if(ih0 < ih) shift = (ih - ih0)/2.0;
1791
	    else shift = min(0, xd->yshift);
1797
	    else shift = min(0, xd->yshift);
1792
	    dd->top = shift;
1798
	    dd->top = shift;
1793
	    dd->bottom = ih0 + shift;
1799
	    dd->bottom = ih0 + shift;
1794
	    xd->yshift = shift;
1800
	    xd->yshift = shift;
1795
	    gchangescrollbar(xd->gawin, VWINSB, max(-shift,0)/SF,
1801
	    gchangescrollbar(xd->gawin, VWINSB, max(-shift,0)/SF,
1796
			     xd->origHeight/SF - 1, xd->windowHeight/SF, 0);
1802
			     xd->origHeight/SF - 1, xd->windowHeight/SF, 0);
1797
	    xd->showWidth = xd->origWidth + min(0, xd->xshift);
1803
	    xd->showWidth = xd->origWidth + min(0, xd->xshift);
1798
	    xd->showHeight = xd->origHeight + min(0,  xd->yshift);
1804
	    xd->showHeight = xd->origHeight + min(0,  xd->yshift);
1799
	}
1805
	}
1800
	xd->resize = FALSE;
1806
	xd->resize = FALSE;
1801
	if (xd->kind == SCREEN) {
1807
	if (xd->kind == SCREEN) {
1802
	    del(xd->bm);
1808
	    del(xd->bm);
1803
	    xd->bm = newbitmap(iw, ih, getdepth(xd->gawin));
1809
	    xd->bm = newbitmap(iw, ih, getdepth(xd->gawin));
1804
	    if (!xd->bm) {
1810
	    if (!xd->bm) {
1805
		R_ShowMessage("Insufficient memory for resize. Killing device");
1811
		R_ShowMessage("Insufficient memory for resize. Killing device");
1806
		KillDevice(GetDevice(devNumber((DevDesc*) dd)));
1812
		KillDevice(GetDevice(devNumber((DevDesc*) dd)));
1807
	    }
1813
	    }
1808
	    gfillrect(xd->gawin, xd->outcolor, getrect(xd->gawin));
1814
	    gfillrect(xd->gawin, xd->outcolor, getrect(xd->gawin));
1809
	    gfillrect(xd->bm, xd->outcolor, getrect(xd->bm));
1815
	    gfillrect(xd->bm, xd->outcolor, getrect(xd->bm));
1810
	}
1816
	}
1811
    }
1817
    }
1812
    UNPROTECT(1);
1818
    UNPROTECT(1);
1813
}
1819
}
1814
 
1820
 
1815
	/********************************************************/
1821
	/********************************************************/
1816
	/* device_NewPage is called whenever a new plot requires*/
1822
	/* device_NewPage is called whenever a new plot requires*/
1817
	/* a new page.  a new page might mean just clearing the	*/
1823
	/* a new page.  a new page might mean just clearing the	*/
1818
	/* device (as in this case) or moving to a new page	*/
1824
	/* device (as in this case) or moving to a new page	*/
1819
	/* (e.g., postscript)					*/
1825
	/* (e.g., postscript)					*/
1820
	/********************************************************/
1826
	/********************************************************/
1821
 
1827
 
1822
static void GA_NewPage(R_GE_gcontext *gc,
1828
static void GA_NewPage(R_GE_gcontext *gc,
1823
		       NewDevDesc *dd)
1829
		       NewDevDesc *dd)
1824
{
1830
{
1825
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1831
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1826
 
1832
 
1827
    xd->npage++;
1833
    xd->npage++;
1828
    if ((xd->kind == PRINTER) && xd->needsave)
1834
    if ((xd->kind == PRINTER) && xd->needsave)
1829
	nextpage(xd->gawin);
1835
	nextpage(xd->gawin);
1830
    if ((xd->kind == METAFILE) && xd->needsave) {
1836
    if ((xd->kind == METAFILE) && xd->needsave) {
1831
	char buf[600];
1837
	char buf[600];
1832
	if (strlen(xd->filename) == 0)
1838
	if (strlen(xd->filename) == 0)
1833
	    error("A clipboard metafile can store only one figure.");
1839
	    error("A clipboard metafile can store only one figure.");
1834
	else {
1840
	else {
1835
	    del(xd->gawin);
1841
	    del(xd->gawin);
1836
	    snprintf(buf, 600, xd->filename, xd->npage);
1842
	    snprintf(buf, 600, xd->filename, xd->npage);
1837
	    xd->gawin = newmetafile(buf, xd->w, xd->h);
1843
	    xd->gawin = newmetafile(buf, xd->w, xd->h);
1838
	}
1844
	}
1839
    }
1845
    }
1840
    if ((xd->kind == PNG || xd->kind == JPEG || xd->kind == BMP)
1846
    if ((xd->kind == PNG || xd->kind == JPEG || xd->kind == BMP)
1841
	&& xd->needsave) {
1847
	&& xd->needsave) {
1842
	char buf[600];
1848
	char buf[600];
1843
	SaveAsBitmap(dd);
1849
	SaveAsBitmap(dd);
1844
	snprintf(buf, 600, xd->filename, xd->npage);
1850
	snprintf(buf, 600, xd->filename, xd->npage);
1845
	if ((xd->fp = fopen(buf, "wb")) == NULL)
1851
	if ((xd->fp = fopen(buf, "wb")) == NULL)
1846
	    error("Unable to open file `%s' for writing", buf);
1852
	    error("Unable to open file `%s' for writing", buf);
1847
    }
1853
    }
1848
    if (xd->kind == SCREEN) {
1854
    if (xd->kind == SCREEN) {
1849
        if(xd->buffered) SHOW;
1855
        if(xd->buffered) SHOW;
1850
#ifdef PLOTHISTORY
1856
#ifdef PLOTHISTORY
1851
	if (xd->recording && xd->needsave)
1857
	if (xd->recording && xd->needsave)
1852
	    AddtoPlotHistory(dd->savedSnapshot, 0);
1858
	    AddtoPlotHistory(dd->savedSnapshot, 0);
1853
	if (xd->replaying)
1859
	if (xd->replaying)
1854
	    xd->needsave = FALSE;
1860
	    xd->needsave = FALSE;
1855
	else
1861
	else
1856
	    xd->needsave = TRUE;
1862
	    xd->needsave = TRUE;
1857
#endif
1863
#endif
1858
    }
1864
    }
1859
    xd->bg = gc->fill;
1865
    xd->bg = gc->fill;
1860
    if (!R_OPAQUE(xd->bg))
1866
    if (!R_OPAQUE(xd->bg))
1861
	xd->bgcolor = xd->canvascolor;
1867
	xd->bgcolor = xd->canvascolor;
1862
    else
1868
    else
1863
	xd->bgcolor = GArgb(xd->bg, gc->gamma);
1869
	xd->bgcolor = GArgb(xd->bg, gc->gamma);
1864
    if (xd->kind != SCREEN) {
1870
    if (xd->kind != SCREEN) {
1865
	xd->needsave = TRUE;
1871
	xd->needsave = TRUE;
1866
	xd->clip = getrect(xd->gawin);
1872
	xd->clip = getrect(xd->gawin);
1867
	if(R_OPAQUE(xd->bg) || xd->kind == PNG ||
1873
	if(R_OPAQUE(xd->bg) || xd->kind == PNG ||
1868
	   xd->kind == BMP || xd->kind == JPEG )
1874
	   xd->kind == BMP || xd->kind == JPEG )
1869
	    DRAW(gfillrect(_d, R_OPAQUE(xd->bg) ? xd->bgcolor : PNG_TRANS,
1875
	    DRAW(gfillrect(_d, R_OPAQUE(xd->bg) ? xd->bgcolor : PNG_TRANS,
1870
			   xd->clip));
1876
			   xd->clip));
1871
	if(xd->kind == PNG) xd->pngtrans = ggetpixel(xd->gawin, pt(0,0));
1877
	if(xd->kind == PNG) xd->pngtrans = ggetpixel(xd->gawin, pt(0,0));
1872
    } else {
1878
    } else {
1873
	xd->clip = getregion(xd);
1879
	xd->clip = getregion(xd);
1874
	DRAW(gfillrect(_d, xd->bgcolor, xd->clip));
1880
	DRAW(gfillrect(_d, xd->bgcolor, xd->clip));
1875
    }
1881
    }
1876
    SH;
1882
    SH;
1877
}
1883
}
1878
 
1884
 
1879
	/********************************************************/
1885
	/********************************************************/
1880
	/* device_Close is called when the device is killed	*/
1886
	/* device_Close is called when the device is killed	*/
1881
	/* this function is responsible for destroying any 	*/
1887
	/* this function is responsible for destroying any 	*/
1882
	/* device-specific resources that were created in	*/
1888
	/* device-specific resources that were created in	*/
1883
	/* device_Open and for FREEing the device-specific	*/
1889
	/* device_Open and for FREEing the device-specific	*/
1884
	/* parameters structure					*/
1890
	/* parameters structure					*/
1885
	/********************************************************/
1891
	/********************************************************/
1886
 
1892
 
1887
static void GA_Close(NewDevDesc *dd)
1893
static void GA_Close(NewDevDesc *dd)
1888
{
1894
{
1889
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1895
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1890
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1896
    GEDevDesc *gdd = (GEDevDesc *) GetDevice(devNumber((DevDesc*) dd));
1891
    GETDL;
1897
    GETDL;
1892
 
1898
 
1893
    if (xd->kind == SCREEN) {
1899
    if (xd->kind == SCREEN) {
1894
	if(xd->recording) {
1900
	if(xd->recording) {
1895
	    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1901
	    AddtoPlotHistory(GEcreateSnapshot(gdd), 0);
1896
	    pCURRENTPOS++; /* so PgUp goes to the last saved plot
1902
	    pCURRENTPOS++; /* so PgUp goes to the last saved plot
1897
			      when a windows() device is opened */
1903
			      when a windows() device is opened */
1898
	}
1904
	}
1899
	hide(xd->gawin);
1905
	hide(xd->gawin);
1900
	del(xd->bm);
1906
	del(xd->bm);
1901
	if (xd == GA_xd) GA_xd = NULL;
1907
	if (xd == GA_xd) GA_xd = NULL;
1902
    } else if ((xd->kind == PNG) || (xd->kind == JPEG) || (xd->kind == BMP)) {
1908
    } else if ((xd->kind == PNG) || (xd->kind == JPEG) || (xd->kind == BMP)) {
1903
      SaveAsBitmap(dd);
1909
      SaveAsBitmap(dd);
1904
    }
1910
    }
1905
    del(xd->font);
1911
    del(xd->font);
1906
    del(xd->gawin);
1912
    del(xd->gawin);
1907
/*
1913
/*
1908
 * this is needed since the GraphApp delayed clean-up
1914
 * this is needed since the GraphApp delayed clean-up
1909
 * ,i.e, I want free all resources NOW
1915
 * ,i.e, I want free all resources NOW
1910
 */
1916
 */
1911
    doevent();
1917
    doevent();
1912
    free(xd);
1918
    free(xd);
1913
}
1919
}
1914
 
1920
 
1915
	/********************************************************/
1921
	/********************************************************/
1916
	/* device_Activate is called when a device becomes the 	*/
1922
	/* device_Activate is called when a device becomes the 	*/
1917
	/* active device.  in this case it is used to change the*/
1923
	/* active device.  in this case it is used to change the*/
1918
	/* title of a window to indicate the active status of 	*/
1924
	/* title of a window to indicate the active status of 	*/
1919
	/* the device to the user.  not all device types will 	*/
1925
	/* the device to the user.  not all device types will 	*/
1920
	/* do anything						*/
1926
	/* do anything						*/
1921
	/********************************************************/
1927
	/********************************************************/
1922
 
1928
 
1923
static unsigned char title[20] = "R Graphics";
1929
static unsigned char title[20] = "R Graphics";
1924
 
1930
 
1925
static void GA_Activate(NewDevDesc *dd)
1931
static void GA_Activate(NewDevDesc *dd)
1926
{
1932
{
1927
    char  t[50];
1933
    char  t[50];
1928
    char  num[3];
1934
    char  num[3];
1929
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1935
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1930
 
1936
 
1931
    if (xd->replaying || (xd->kind!=SCREEN))
1937
    if (xd->replaying || (xd->kind!=SCREEN))
1932
	return;
1938
	return;
1933
    strcpy(t, (char *) title);
1939
    strcpy(t, (char *) title);
1934
    strcat(t, ": Device ");
1940
    strcat(t, ": Device ");
1935
    sprintf(num, "%i", devNumber((DevDesc*) dd) + 1);
1941
    sprintf(num, "%i", devNumber((DevDesc*) dd) + 1);
1936
    strcat(t, num);
1942
    strcat(t, num);
1937
    strcat(t, " (ACTIVE)");
1943
    strcat(t, " (ACTIVE)");
1938
    settext(xd->gawin, t);
1944
    settext(xd->gawin, t);
1939
}
1945
}
1940
 
1946
 
1941
	/********************************************************/
1947
	/********************************************************/
1942
	/* device_Deactivate is called when a device becomes	*/
1948
	/* device_Deactivate is called when a device becomes	*/
1943
	/* inactive.  in this case it is used to change the 	*/
1949
	/* inactive.  in this case it is used to change the 	*/
1944
	/* title of a window to indicate the inactive status of */
1950
	/* title of a window to indicate the inactive status of */
1945
	/* the device to the user.  not all device types will	*/
1951
	/* the device to the user.  not all device types will	*/
1946
	/* do anything						*/
1952
	/* do anything						*/
1947
	/********************************************************/
1953
	/********************************************************/
1948
 
1954
 
1949
static void GA_Deactivate(NewDevDesc *dd)
1955
static void GA_Deactivate(NewDevDesc *dd)
1950
{
1956
{
1951
    char  t[50];
1957
    char  t[50];
1952
    char  num[3];
1958
    char  num[3];
1953
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1959
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1954
 
1960
 
1955
    if (xd->replaying || (xd->kind != SCREEN))
1961
    if (xd->replaying || (xd->kind != SCREEN))
1956
	return;
1962
	return;
1957
    strcpy(t, (char *) title);
1963
    strcpy(t, (char *) title);
1958
    strcat(t, ": Device ");
1964
    strcat(t, ": Device ");
1959
    sprintf(num, "%i", devNumber((DevDesc*) dd) + 1);
1965
    sprintf(num, "%i", devNumber((DevDesc*) dd) + 1);
1960
    strcat(t, num);
1966
    strcat(t, num);
1961
    strcat(t, " (inactive)");
1967
    strcat(t, " (inactive)");
1962
    settext(xd->gawin, t);
1968
    settext(xd->gawin, t);
1963
}
1969
}
1964
 
1970
 
1965
	/********************************************************/
1971
	/********************************************************/
1966
	/* device_Rect should have the side-effect that a 	*/
1972
	/* device_Rect should have the side-effect that a 	*/
1967
	/* rectangle is drawn with the given locations for its 	*/
1973
	/* rectangle is drawn with the given locations for its 	*/
1968
	/* opposite corners.  the border of the rectangle	*/
1974
	/* opposite corners.  the border of the rectangle	*/
1969
	/* should be in the given "fg" colour and the rectangle	*/
1975
	/* should be in the given "fg" colour and the rectangle	*/
1970
	/* should be filled with the given "bg" colour		*/
1976
	/* should be filled with the given "bg" colour		*/
1971
	/* if "fg" is NA_INTEGER then no border should be drawn */
1977
	/* if "fg" is NA_INTEGER then no border should be drawn */
1972
	/* if "bg" is NA_INTEGER then the rectangle should not 	*/
1978
	/* if "bg" is NA_INTEGER then the rectangle should not 	*/
1973
	/* be filled						*/
1979
	/* be filled						*/
1974
	/* the locations are in an arbitrary coordinate system	*/
1980
	/* the locations are in an arbitrary coordinate system	*/
1975
	/* and this function is responsible for converting the	*/
1981
	/* and this function is responsible for converting the	*/
1976
	/* locations to DEVICE coordinates using GConvert	*/
1982
	/* locations to DEVICE coordinates using GConvert	*/
1977
	/********************************************************/
1983
	/********************************************************/
1978
 
1984
 
1979
static void GA_Rect(double x0, double y0, double x1, double y1,
1985
static void GA_Rect(double x0, double y0, double x1, double y1,
1980
		    R_GE_gcontext *gc,
1986
		    R_GE_gcontext *gc,
1981
		    NewDevDesc *dd)
1987
		    NewDevDesc *dd)
1982
{
1988
{
1983
    int   tmp;
1989
    int   tmp;
1984
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1990
    gadesc *xd = (gadesc *) dd->deviceSpecific;
1985
    rect  r;
1991
    rect  r;
1986
 
1992
 
1987
    /* These in-place conversions are ok */
1993
    /* These in-place conversions are ok */
1988
    TRACEDEVGA("rect");
1994
    TRACEDEVGA("rect");
1989
 
1995
 
1990
    if (x0 > x1) {
1996
    if (x0 > x1) {
1991
	tmp = x0;
1997
	tmp = x0;
1992
	x0 = x1;
1998
	x0 = x1;
1993
	x1 = tmp;
1999
	x1 = tmp;
1994
    }
2000
    }
1995
    if (y0 > y1) {
2001
    if (y0 > y1) {
1996
	tmp = y0;
2002
	tmp = y0;
1997
	y0 = y1;
2003
	y0 = y1;
1998
	y1 = tmp;
2004
	y1 = tmp;
1999
    }
2005
    }
2000
    r = rect((int) x0, (int) y0, (int) x1 - (int) x0, (int) y1 - (int) y0);
2006
    r = rect((int) x0, (int) y0, (int) x1 - (int) x0, (int) y1 - (int) y0);
2001
    if (R_OPAQUE(gc->fill)) {
2007
    if (R_OPAQUE(gc->fill)) {
2002
	SetColor(gc->fill, gc->gamma, dd);
2008
	SetColor(gc->fill, gc->gamma, dd);
2003
	DRAW(gfillrect(_d, xd->fgcolor, r));
2009
	DRAW(gfillrect(_d, xd->fgcolor, r));
2004
 
2010
 
2005
    }
2011
    }
2006
    if (R_OPAQUE(gc->col)) {
2012
    if (R_OPAQUE(gc->col)) {
2007
	SetColor(gc->col, gc->gamma, dd);
2013
	SetColor(gc->col, gc->gamma, dd);
2008
	SetLinetype(gc->lty, gc->lwd, dd);
2014
	SetLinetype(gc->lty, gc->lwd, dd);
2009
	DRAW(gdrawrect(_d, xd->lwd, xd->lty, xd->fgcolor, r, 0));
2015
	DRAW(gdrawrect(_d, xd->lwd, xd->lty, xd->fgcolor, r, 0));
2010
    }
2016
    }
2011
    SH;
2017
    SH;
2012
}
2018
}
2013
 
2019
 
2014
	/********************************************************/
2020
	/********************************************************/
2015
	/* device_Circle should have the side-effect that a	*/
2021
	/* device_Circle should have the side-effect that a	*/
2016
	/* circle is drawn, centred at the given location, with */
2022
	/* circle is drawn, centred at the given location, with */
2017
	/* the given radius.  the border of the circle should be*/
2023
	/* the given radius.  the border of the circle should be*/
2018
	/* drawn in the given "col", and the circle should be	*/
2024
	/* drawn in the given "col", and the circle should be	*/
2019
	/* filled with the given "border" colour.		*/
2025
	/* filled with the given "border" colour.		*/
2020
	/* if "col" is NA_INTEGER then no border should be drawn*/
2026
	/* if "col" is NA_INTEGER then no border should be drawn*/
2021
	/* if "border" is NA_INTEGER then the circle should not */
2027
	/* if "border" is NA_INTEGER then the circle should not */
2022
	/* be filled						*/
2028
	/* be filled						*/
2023
	/* the location is in arbitrary coordinates and the 	*/
2029
	/* the location is in arbitrary coordinates and the 	*/
2024
	/* function is responsible for converting this to	*/
2030
	/* function is responsible for converting this to	*/
2025
	/* DEVICE coordinates.  the radius is given in DEVICE	*/
2031
	/* DEVICE coordinates.  the radius is given in DEVICE	*/
2026
	/* coordinates						*/
2032
	/* coordinates						*/
2027
	/********************************************************/
2033
	/********************************************************/
2028
 
2034
 
2029
static void GA_Circle(double x, double y, double r,
2035
static void GA_Circle(double x, double y, double r,
2030
		      R_GE_gcontext *gc,
2036
		      R_GE_gcontext *gc,
2031
		      NewDevDesc *dd)
2037
		      NewDevDesc *dd)
2032
{
2038
{
2033
    int   ir, ix, iy;
2039
    int   ir, ix, iy;
2034
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2040
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2035
    rect  rr;
2041
    rect  rr;
2036
 
2042
 
2037
    TRACEDEVGA("circle");
2043
    TRACEDEVGA("circle");
2038
    ir = floor(r + 0.5);
2044
    ir = floor(r + 0.5);
2039
    if (ir < 1) ir = 1;
2045
    if (ir < 1) ir = 1;
2040
    /* In-place conversion ok */
2046
    /* In-place conversion ok */
2041
 
2047
 
2042
    ix = (int) x;
2048
    ix = (int) x;
2043
    iy = (int) y;
2049
    iy = (int) y;
2044
    rr = rect(ix - ir, iy - ir, 2 * ir, 2 * ir);
2050
    rr = rect(ix - ir, iy - ir, 2 * ir, 2 * ir);
2045
    if (R_OPAQUE(gc->fill)) {
2051
    if (R_OPAQUE(gc->fill)) {
2046
	SetColor(gc->fill, gc->gamma, dd);
2052
	SetColor(gc->fill, gc->gamma, dd);
2047
	DRAW(gfillellipse(_d, xd->fgcolor, rr));
2053
	DRAW(gfillellipse(_d, xd->fgcolor, rr));
2048
    }
2054
    }
2049
    if (R_OPAQUE(gc->col)) {
2055
    if (R_OPAQUE(gc->col)) {
2050
	SetLinetype(gc->lty, gc->lwd, dd);
2056
	SetLinetype(gc->lty, gc->lwd, dd);
2051
	SetColor(gc->col, gc->gamma, dd);
2057
	SetColor(gc->col, gc->gamma, dd);
2052
	DRAW(gdrawellipse(_d, xd->lwd, xd->fgcolor, rr, 0));
2058
	DRAW(gdrawellipse(_d, xd->lwd, xd->fgcolor, rr, 0));
2053
    }
2059
    }
2054
    SH;
2060
    SH;
2055
}
2061
}
2056
 
2062
 
2057
	/********************************************************/
2063
	/********************************************************/
2058
	/* device_Line should have the side-effect that a single*/
2064
	/* device_Line should have the side-effect that a single*/
2059
	/* line is drawn (from x1,y1 to x2,y2)			*/
2065
	/* line is drawn (from x1,y1 to x2,y2)			*/
2060
	/* x1, y1, x2, and y2 are in arbitrary coordinates and	*/
2066
	/* x1, y1, x2, and y2 are in arbitrary coordinates and	*/
2061
	/* the function is responsible for converting them to	*/
2067
	/* the function is responsible for converting them to	*/
2062
	/* DEVICE coordinates using GConvert			*/
2068
	/* DEVICE coordinates using GConvert			*/
2063
	/********************************************************/
2069
	/********************************************************/
2064
 
2070
 
2065
static void GA_Line(double x1, double y1, double x2, double y2,
2071
static void GA_Line(double x1, double y1, double x2, double y2,
2066
		    R_GE_gcontext *gc,
2072
		    R_GE_gcontext *gc,
2067
		    NewDevDesc *dd)
2073
		    NewDevDesc *dd)
2068
{
2074
{
2069
    int   xx1, yy1, xx2, yy2;
2075
    int   xx1, yy1, xx2, yy2;
2070
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2076
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2071
 
2077
 
2072
    /* In-place conversion ok */
2078
    /* In-place conversion ok */
2073
    TRACEDEVGA("line");
2079
    TRACEDEVGA("line");
2074
    xx1 = (int) x1;
2080
    xx1 = (int) x1;
2075
    yy1 = (int) y1;
2081
    yy1 = (int) y1;
2076
    xx2 = (int) x2;
2082
    xx2 = (int) x2;
2077
    yy2 = (int) y2;
2083
    yy2 = (int) y2;
2078
 
2084
 
2079
    if (R_OPAQUE(gc->col)) {
2085
    if (R_OPAQUE(gc->col)) {
2080
	SetColor(gc->col, gc->gamma, dd);
2086
	SetColor(gc->col, gc->gamma, dd);
2081
	SetLinetype(gc->lty, gc->lwd, dd);
2087
	SetLinetype(gc->lty, gc->lwd, dd);
2082
	DRAW(gdrawline(_d, xd->lwd, xd->lty, xd->fgcolor,
2088
	DRAW(gdrawline(_d, xd->lwd, xd->lty, xd->fgcolor,
2083
		       pt(xx1, yy1), pt(xx2, yy2), 0));
2089
		       pt(xx1, yy1), pt(xx2, yy2), 0));
2084
	SH;
2090
	SH;
2085
    }
2091
    }
2086
}
2092
}
2087
 
2093
 
2088
	/********************************************************/
2094
	/********************************************************/
2089
	/* device_Polyline should have the side-effect that a	*/
2095
	/* device_Polyline should have the side-effect that a	*/
2090
	/* series of line segments are drawn using the given x	*/
2096
	/* series of line segments are drawn using the given x	*/
2091
	/* and y values						*/
2097
	/* and y values						*/
2092
	/* the x and y values are in arbitrary coordinates and	*/
2098
	/* the x and y values are in arbitrary coordinates and	*/
2093
	/* the function is responsible for converting them to	*/
2099
	/* the function is responsible for converting them to	*/
2094
	/* DEVICE coordinates using GConvert			*/
2100
	/* DEVICE coordinates using GConvert			*/
2095
	/********************************************************/
2101
	/********************************************************/
2096
 
2102
 
2097
static void GA_Polyline(int n, double *x, double *y,
2103
static void GA_Polyline(int n, double *x, double *y,
2098
			R_GE_gcontext *gc,
2104
			R_GE_gcontext *gc,
2099
			NewDevDesc *dd)
2105
			NewDevDesc *dd)
2100
{
2106
{
2101
    char *vmax = vmaxget();
2107
    char *vmax = vmaxget();
2102
    point *p = (point *) R_alloc(n, sizeof(point));
2108
    point *p = (point *) R_alloc(n, sizeof(point));
2103
    double devx, devy;
2109
    double devx, devy;
2104
    int   i;
2110
    int   i;
2105
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2111
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2106
 
2112
 
2107
    TRACEDEVGA("pl");
2113
    TRACEDEVGA("pl");
2108
    for (i = 0; i < n; i++) {
2114
    for (i = 0; i < n; i++) {
2109
	devx = x[i];
2115
	devx = x[i];
2110
	devy = y[i];
2116
	devy = y[i];
2111
	p[i].x = (int) devx;
2117
	p[i].x = (int) devx;
2112
	p[i].y = (int) devy;
2118
	p[i].y = (int) devy;
2113
    }
2119
    }
2114
    if (R_OPAQUE(gc->col)) {
2120
    if (R_OPAQUE(gc->col)) {
2115
	SetColor(gc->col, gc->gamma, dd);
2121
	SetColor(gc->col, gc->gamma, dd);
2116
	SetLinetype(gc->lty, gc->lwd, dd);
2122
	SetLinetype(gc->lty, gc->lwd, dd);
2117
	DRAW(gdrawpolyline(_d, xd->lwd, xd->lty, xd->fgcolor, p, n, 0, 0));
2123
	DRAW(gdrawpolyline(_d, xd->lwd, xd->lty, xd->fgcolor, p, n, 0, 0));
2118
    }
2124
    }
2119
    vmaxset(vmax);
2125
    vmaxset(vmax);
2120
    SH;
2126
    SH;
2121
}
2127
}
2122
 
2128
 
2123
	/********************************************************/
2129
	/********************************************************/
2124
	/* device_Polygon should have the side-effect that a 	*/
2130
	/* device_Polygon should have the side-effect that a 	*/
2125
	/* polygon is drawn using the given x and y values	*/
2131
	/* polygon is drawn using the given x and y values	*/
2126
	/* the polygon border should be drawn in the "fg" 	*/
2132
	/* the polygon border should be drawn in the "fg" 	*/
2127
	/* colour and filled with the "bg" colour		*/
2133
	/* colour and filled with the "bg" colour		*/
2128
	/* if "fg" is NA_INTEGER don't draw the border		*/
2134
	/* if "fg" is NA_INTEGER don't draw the border		*/
2129
	/* if "bg" is NA_INTEGER don't fill the polygon		*/
2135
	/* if "bg" is NA_INTEGER don't fill the polygon		*/
2130
	/* the x and y values are in arbitrary coordinates and 	*/
2136
	/* the x and y values are in arbitrary coordinates and 	*/
2131
	/* the function is responsible for converting them to 	*/
2137
	/* the function is responsible for converting them to 	*/
2132
	/* DEVICE coordinates using GConvert			*/
2138
	/* DEVICE coordinates using GConvert			*/
2133
	/********************************************************/
2139
	/********************************************************/
2134
 
2140
 
2135
static void GA_Polygon(int n, double *x, double *y,
2141
static void GA_Polygon(int n, double *x, double *y,
2136
		       R_GE_gcontext *gc,
2142
		       R_GE_gcontext *gc,
2137
		       NewDevDesc *dd)
2143
		       NewDevDesc *dd)
2138
{
2144
{
2139
    char *vmax = vmaxget();
2145
    char *vmax = vmaxget();
2140
    point *points;
2146
    point *points;
2141
    double devx, devy;
2147
    double devx, devy;
2142
    int   i;
2148
    int   i;
2143
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2149
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2144
 
2150
 
2145
    TRACEDEVGA("plg");
2151
    TRACEDEVGA("plg");
2146
    points = (point *) R_alloc(n , sizeof(point));
2152
    points = (point *) R_alloc(n , sizeof(point));
2147
    if (!points)
2153
    if (!points)
2148
	return;
2154
	return;
2149
    for (i = 0; i < n; i++) {
2155
    for (i = 0; i < n; i++) {
2150
	devx = x[i];
2156
	devx = x[i];
2151
	devy = y[i];
2157
	devy = y[i];
2152
	points[i].x = (int) (devx);
2158
	points[i].x = (int) (devx);
2153
	points[i].y = (int) (devy);
2159
	points[i].y = (int) (devy);
2154
    }
2160
    }
2155
    if (R_OPAQUE(gc->fill)) {
2161
    if (R_OPAQUE(gc->fill)) {
2156
	SetColor(gc->fill, gc->gamma, dd);
2162
	SetColor(gc->fill, gc->gamma, dd);
2157
	DRAW(gfillpolygon(_d, xd->fgcolor, points, n));
2163
	DRAW(gfillpolygon(_d, xd->fgcolor, points, n));
2158
    }
2164
    }
2159
    if (R_OPAQUE(gc->col)) {
2165
    if (R_OPAQUE(gc->col)) {
2160
	SetColor(gc->col, gc->gamma, dd);
2166
	SetColor(gc->col, gc->gamma, dd);
2161
	SetLinetype(gc->lty, gc->lwd, dd);
2167
	SetLinetype(gc->lty, gc->lwd, dd);
2162
	DRAW(gdrawpolygon(_d, xd->lwd, xd->lty, xd->fgcolor, points, n, 0 ));
2168
	DRAW(gdrawpolygon(_d, xd->lwd, xd->lty, xd->fgcolor, points, n, 0 ));
2163
    }
2169
    }
2164
    vmaxset(vmax);
2170
    vmaxset(vmax);
2165
    SH;
2171
    SH;
2166
}
2172
}
2167
 
2173
 
2168
 
2174
 
2169
	/********************************************************/
2175
	/********************************************************/
2170
	/* device_Text should have the side-effect that the 	*/
2176
	/* device_Text should have the side-effect that the 	*/
2171
	/* given text is drawn at the given location		*/
2177
	/* given text is drawn at the given location		*/
2172
	/* the text should be rotated according to rot (degrees)*/
2178
	/* the text should be rotated according to rot (degrees)*/
2173
	/* the location is in an arbitrary coordinate system	*/
2179
	/* the location is in an arbitrary coordinate system	*/
2174
	/* and this function is responsible for converting the	*/
2180
	/* and this function is responsible for converting the	*/
2175
	/* location to DEVICE coordinates using GConvert	*/
2181
	/* location to DEVICE coordinates using GConvert	*/
2176
	/********************************************************/
2182
	/********************************************************/
2177
 
2183
 
2178
 
2184
 
2179
static void GA_Text(double x, double y, char *str,
2185
static void GA_Text(double x, double y, char *str,
2180
		    double rot, double hadj,
2186
		    double rot, double hadj,
2181
		    R_GE_gcontext *gc,
2187
		    R_GE_gcontext *gc,
2182
		    NewDevDesc *dd)
2188
		    NewDevDesc *dd)
2183
{
2189
{
2184
    int   size;
2190
    int   size;
2185
    double pixs, xl, yl, rot1;
2191
    double pixs, xl, yl, rot1;
2186
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2192
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2187
 
2193
 
2188
    size = gc->cex * gc->ps + 0.5;
2194
    size = gc->cex * gc->ps + 0.5;
2189
    pixs = - 1;
2195
    pixs = - 1;
2190
    xl = 0.0;
2196
    xl = 0.0;
2191
    yl = -pixs;
2197
    yl = -pixs;
2192
    rot1 = rot * DEG2RAD;
2198
    rot1 = rot * DEG2RAD;
2193
    x += -xl * cos(rot1) + yl * sin(rot1);
2199
    x += -xl * cos(rot1) + yl * sin(rot1);
2194
    y -= -xl * sin(rot1) - yl * cos(rot1);
2200
    y -= -xl * sin(rot1) - yl * cos(rot1);
2195
    SetFont(gc->fontface, size, rot, dd);
2201
    SetFont(gc->fontface, size, rot, dd);
2196
    SetColor(gc->col, gc->gamma, dd);
2202
    SetColor(gc->col, gc->gamma, dd);
2197
    if (R_OPAQUE(xd->fgcolor)) {
2203
    if (R_OPAQUE(xd->fgcolor)) {
2198
#ifdef NOCLIPTEXT
2204
#ifdef NOCLIPTEXT
2199
	gsetcliprect(xd->gawin, getrect(xd->gawin));
2205
	gsetcliprect(xd->gawin, getrect(xd->gawin));
2200
	gdrawstr1(xd->gawin, xd->font, xd->fgcolor, pt(x, y), str, hadj);
2206
	gdrawstr1(xd->gawin, xd->font, xd->fgcolor, pt(x, y), str, hadj);
2201
	if (xd->kind==SCREEN) {
2207
	if (xd->kind==SCREEN) {
2202
	    gsetcliprect(xd->bm, getrect(xd->bm));
2208
	    gsetcliprect(xd->bm, getrect(xd->bm));
2203
	    gdrawstr1(xd->bm, xd->font, xd->fgcolor, pt(x, y), str, hadj);
2209
	    gdrawstr1(xd->bm, xd->font, xd->fgcolor, pt(x, y), str, hadj);
2204
	}
2210
	}
2205
#else
2211
#else
2206
	DRAW(gdrawstr1(_d, xd->font, xd->fgcolor, pt(x, y), str, hadj));
2212
	DRAW(gdrawstr1(_d, xd->font, xd->fgcolor, pt(x, y), str, hadj));
2207
#endif
2213
#endif
2208
    }
2214
    }
2209
    SH;
2215
    SH;
2210
}
2216
}
2211
 
2217
 
2212
	/********************************************************/
2218
	/********************************************************/
2213
	/* device_Locator should return the location of the next*/
2219
	/* device_Locator should return the location of the next*/
2214
	/* mouse click (in DEVICE coordinates;  GLocator is	*/
2220
	/* mouse click (in DEVICE coordinates;  GLocator is	*/
2215
	/* responsible for any conversions)			*/
2221
	/* responsible for any conversions)			*/
2216
	/* not all devices will do anything (e.g., postscript)	*/
2222
	/* not all devices will do anything (e.g., postscript)	*/
2217
	/********************************************************/
2223
	/********************************************************/
2218
 
2224
 
2219
static Rboolean GA_Locator(double *x, double *y, NewDevDesc *dd)
2225
static Rboolean GA_Locator(double *x, double *y, NewDevDesc *dd)
2220
{
2226
{
2221
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2227
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2222
 
2228
 
2223
    if (xd->kind != SCREEN)
2229
    if (xd->kind != SCREEN)
2224
	return FALSE;
2230
	return FALSE;
2225
    xd->locator = TRUE;
2231
    xd->locator = TRUE;
2226
    xd->clicked = 0;
2232
    xd->clicked = 0;
2227
    show(xd->gawin);
2233
    show(xd->gawin);
2228
    addto(xd->gawin);
2234
    addto(xd->gawin);
2229
    gchangemenubar(xd->mbarloc);
2235
    gchangemenubar(xd->mbarloc);
2230
    if (xd->stoploc) {
2236
    if (xd->stoploc) {
2231
      show(xd->stoploc);
2237
      show(xd->stoploc);
2232
      show(xd->gawin);
2238
      show(xd->gawin);
2233
    }
2239
    }
2234
    gchangepopup(xd->gawin, xd->locpopup);
2240
    gchangepopup(xd->gawin, xd->locpopup);
2235
    gsetcursor(xd->gawin, CrossCursor);
2241
    gsetcursor(xd->gawin, CrossCursor);
2236
    setstatus("Locator is active");
2242
    setstatus("Locator is active");
2237
    while (!xd->clicked) {
2243
    while (!xd->clicked) {
2238
	if(xd->buffered) SHOW;
2244
	if(xd->buffered) SHOW;
2239
        WaitMessage();
2245
        WaitMessage();
2240
	R_ProcessEvents();
2246
	R_ProcessEvents();
2241
    }
2247
    }
2242
    addto(xd->gawin);
2248
    addto(xd->gawin);
2243
    gchangemenubar(xd->mbar);
2249
    gchangemenubar(xd->mbar);
2244
    if (xd->stoploc) {
2250
    if (xd->stoploc) {
2245
      hide(xd->stoploc);
2251
      hide(xd->stoploc);
2246
      show(xd->gawin);
2252
      show(xd->gawin);
2247
    }
2253
    }
2248
    gsetcursor(xd->gawin, ArrowCursor);
2254
    gsetcursor(xd->gawin, ArrowCursor);
2249
    gchangepopup(xd->gawin, xd->grpopup);
2255
    gchangepopup(xd->gawin, xd->grpopup);
2250
    addto(xd->gawin);
2256
    addto(xd->gawin);
2251
    setstatus("R Graphics");
2257
    setstatus("R Graphics");
2252
    xd->locator = FALSE;
2258
    xd->locator = FALSE;
2253
    if (xd->clicked == 1) {
2259
    if (xd->clicked == 1) {
2254
	*x = xd->px;
2260
	*x = xd->px;
2255
	*y = xd->py;
2261
	*y = xd->py;
2256
	return TRUE;
2262
	return TRUE;
2257
    } else
2263
    } else
2258
	return FALSE;
2264
	return FALSE;
2259
}
2265
}
2260
 
2266
 
2261
	/********************************************************/
2267
	/********************************************************/
2262
	/* device_Mode is called whenever the graphics engine 	*/
2268
	/* device_Mode is called whenever the graphics engine 	*/
2263
	/* starts drawing (mode=1) or stops drawing (mode=1)	*/
2269
	/* starts drawing (mode=1) or stops drawing (mode=1)	*/
2264
	/* the device is not required to do anything		*/
2270
	/* the device is not required to do anything		*/
2265
	/********************************************************/
2271
	/********************************************************/
2266
 
2272
 
2267
/* Set Graphics mode - not needed for X11 */
2273
/* Set Graphics mode - not needed for X11 */
2268
static void GA_Mode(int mode, NewDevDesc *dd)
2274
static void GA_Mode(int mode, NewDevDesc *dd)
2269
{
2275
{
2270
}
2276
}
2271
 
2277
 
2272
	/********************************************************/
2278
	/********************************************************/
2273
	/* i don't know what this is for and i can't find it	*/
2279
	/* i don't know what this is for and i can't find it	*/
2274
	/* being used anywhere, but i'm loath to kill it in	*/
2280
	/* being used anywhere, but i'm loath to kill it in	*/
2275
	/* case i'm missing something important			*/
2281
	/* case i'm missing something important			*/
2276
	/********************************************************/
2282
	/********************************************************/
2277
 
2283
 
2278
/* Hold the Picture Onscreen - not needed for X11 */
2284
/* Hold the Picture Onscreen - not needed for X11 */
2279
static void GA_Hold(NewDevDesc *dd)
2285
static void GA_Hold(NewDevDesc *dd)
2280
{
2286
{
2281
}
2287
}
2282
 
2288
 
2283
 
2289
 
2284
	/********************************************************/
2290
	/********************************************************/
2285
	/* the device-driver entry point is given a device 	*/
2291
	/* the device-driver entry point is given a device 	*/
2286
	/* description structure that it must set up.  this 	*/
2292
	/* description structure that it must set up.  this 	*/
2287
	/* involves several important jobs ...			*/
2293
	/* involves several important jobs ...			*/
2288
	/* (1) it must ALLOCATE a new device-specific parameters*/
2294
	/* (1) it must ALLOCATE a new device-specific parameters*/
2289
	/* structure and FREE that structure if anything goes	*/
2295
	/* structure and FREE that structure if anything goes	*/
2290
	/* wrong (i.e., it won't report a successful setup to	*/
2296
	/* wrong (i.e., it won't report a successful setup to	*/
2291
	/* the graphics engine (the graphics engine is NOT	*/
2297
	/* the graphics engine (the graphics engine is NOT	*/
2292
	/* responsible for allocating or freeing device-specific*/
2298
	/* responsible for allocating or freeing device-specific*/
2293
	/* resources or parameters)				*/
2299
	/* resources or parameters)				*/
2294
	/* (2) it must initialise the device-specific resources */
2300
	/* (2) it must initialise the device-specific resources */
2295
	/* and parameters (mostly done by calling device_Open)	*/
2301
	/* and parameters (mostly done by calling device_Open)	*/
2296
	/* (3) it must initialise the generic graphical 	*/
2302
	/* (3) it must initialise the generic graphical 	*/
2297
	/* parameters that are not initialised by GInit (because*/
2303
	/* parameters that are not initialised by GInit (because*/
2298
	/* only the device knows what values they should have)	*/
2304
	/* only the device knows what values they should have)	*/
2299
	/* see Graphics.h for the official list of these	*/
2305
	/* see Graphics.h for the official list of these	*/
2300
	/* (4) it may reset generic graphics parameters that	*/
2306
	/* (4) it may reset generic graphics parameters that	*/
2301
	/* have already been initialised by GInit (although you	*/
2307
	/* have already been initialised by GInit (although you	*/
2302
	/* should know what you are doing if you do this)	*/
2308
	/* should know what you are doing if you do this)	*/
2303
	/* (5) it must attach the device-specific parameters	*/
2309
	/* (5) it must attach the device-specific parameters	*/
2304
        /* structure to the device description structure	*/
2310
        /* structure to the device description structure	*/
2305
	/* e.g., dd->deviceSpecific = (void *) xd;		*/
2311
	/* e.g., dd->deviceSpecific = (void *) xd;		*/
2306
	/* (6) it must FREE the overall device description if 	*/
2312
	/* (6) it must FREE the overall device description if 	*/
2307
	/* it wants to bail out to the top-level		*/
2313
	/* it wants to bail out to the top-level		*/
2308
	/* the graphics engine is responsible for allocating 	*/
2314
	/* the graphics engine is responsible for allocating 	*/
2309
	/* the device description and freeing it in most cases	*/
2315
	/* the device description and freeing it in most cases	*/
2310
	/* but if the device driver freaks out it needs to do 	*/
2316
	/* but if the device driver freaks out it needs to do 	*/
2311
	/* the clean-up itself					*/
2317
	/* the clean-up itself					*/
2312
	/********************************************************/
2318
	/********************************************************/
2313
 
2319
 
2314
 
2320
 
2315
 
2321
 
2316
Rboolean GADeviceDriver(NewDevDesc *dd, char *display, double width,
2322
Rboolean GADeviceDriver(NewDevDesc *dd, char *display, double width,
2317
			double height, double pointsize,
2323
			double height, double pointsize,
2318
			Rboolean recording, int resize, int canvas,
2324
			Rboolean recording, int resize, int canvas,
2319
			double gamma, int xpos, int ypos, Rboolean buffered,
2325
			double gamma, int xpos, int ypos, Rboolean buffered,
2320
			SEXP psenv)
2326
			SEXP psenv)
2321
{
2327
{
2322
    /* if need to bail out with some sort of "error" then */
2328
    /* if need to bail out with some sort of "error" then */
2323
    /* must free(dd) */
2329
    /* must free(dd) */
2324
 
2330
 
2325
    int   ps;
2331
    int   ps;
2326
    gadesc *xd;
2332
    gadesc *xd;
2327
    rect  rr;
2333
    rect  rr;
2328
    int a=0, d=0, w=0;
2334
    int a=0, d=0, w=0;
2329
 
2335
 
2330
    /* allocate new device description */
2336
    /* allocate new device description */
2331
    if (!(xd = (gadesc *) malloc(sizeof(gadesc))))
2337
    if (!(xd = (gadesc *) malloc(sizeof(gadesc))))
2332
	return FALSE;
2338
	return FALSE;
2333
 
2339
 
2334
    /* from here on, if need to bail out with "error", must also */
2340
    /* from here on, if need to bail out with "error", must also */
2335
    /* free(xd) */
2341
    /* free(xd) */
2336
 
2342
 
2337
    /* Font will load at first use  */
2343
    /* Font will load at first use  */
2338
 
2344
 
2339
    ps = pointsize;
2345
    ps = pointsize;
2340
    if (ps < 6 || ps > 48)
2346
    if (ps < 6 || ps > 48)
2341
	ps = 12;
2347
	ps = 12;
2342
    ps = 2 * (ps / 2);
2348
    ps = 2 * (ps / 2);
2343
    xd->fontface = -1;
2349
    xd->fontface = -1;
2344
    xd->fontsize = -1;
2350
    xd->fontsize = -1;
2345
    xd->basefontsize = ps ;
2351
    xd->basefontsize = ps ;
2346
    dd->startfont = 1;
2352
    dd->startfont = 1;
2347
    dd->startps = ps;
2353
    dd->startps = ps;
2348
    dd->startlty = LTY_SOLID;
2354
    dd->startlty = LTY_SOLID;
2349
    dd->startgamma = gamma;
2355
    dd->startgamma = gamma;
2350
 
2356
 
2351
    /* Start the Device Driver and Hardcopy.  */
2357
    /* Start the Device Driver and Hardcopy.  */
2352
 
2358
 
2353
    if (!GA_Open(dd, xd, display, width, height, recording, resize, canvas,
2359
    if (!GA_Open(dd, xd, display, width, height, recording, resize, canvas,
2354
		 gamma, xpos, ypos)) {
2360
		 gamma, xpos, ypos)) {
2355
	free(xd);
2361
	free(xd);
2356
	return FALSE;
2362
	return FALSE;
2357
    }
2363
    }
2358
    dd->deviceSpecific = (void *) xd;
2364
    dd->deviceSpecific = (void *) xd;
2359
    /* Set up Data Structures  */
2365
    /* Set up Data Structures  */
2360
 
2366
 
2361
    dd->newDevStruct = 1;
2367
    dd->newDevStruct = 1;
2362
 
2368
 
2363
    dd->open = GA_Open;
2369
    dd->open = GA_Open;
2364
    dd->close = GA_Close;
2370
    dd->close = GA_Close;
2365
    dd->activate = GA_Activate;
2371
    dd->activate = GA_Activate;
2366
    dd->deactivate = GA_Deactivate;
2372
    dd->deactivate = GA_Deactivate;
2367
    dd->size = GA_Size;
2373
    dd->size = GA_Size;
2368
    dd->newPage = GA_NewPage;
2374
    dd->newPage = GA_NewPage;
2369
    dd->clip = GA_Clip;
2375
    dd->clip = GA_Clip;
2370
    dd->strWidth = GA_StrWidth;
2376
    dd->strWidth = GA_StrWidth;
2371
    dd->text = GA_Text;
2377
    dd->text = GA_Text;
2372
    dd->rect = GA_Rect;
2378
    dd->rect = GA_Rect;
2373
    dd->circle = GA_Circle;
2379
    dd->circle = GA_Circle;
2374
    dd->line = GA_Line;
2380
    dd->line = GA_Line;
2375
    dd->polyline = GA_Polyline;
2381
    dd->polyline = GA_Polyline;
2376
    dd->polygon = GA_Polygon;
2382
    dd->polygon = GA_Polygon;
2377
    dd->locator = GA_Locator;
2383
    dd->locator = GA_Locator;
2378
    dd->mode = GA_Mode;
2384
    dd->mode = GA_Mode;
2379
    dd->hold = GA_Hold;
2385
    dd->hold = GA_Hold;
2380
    dd->metricInfo = GA_MetricInfo;
2386
    dd->metricInfo = GA_MetricInfo;
2381
 
2387
 
2382
    /* set graphics parameters that must be set by device driver */
2388
    /* set graphics parameters that must be set by device driver */
2383
    /* Window Dimensions in Pixels */
2389
    /* Window Dimensions in Pixels */
2384
    rr = getrect(xd->gawin);
2390
    rr = getrect(xd->gawin);
2385
    dd->left = (xd->kind == PRINTER) ? rr.x : 0;	/* left */
2391
    dd->left = (xd->kind == PRINTER) ? rr.x : 0;	/* left */
2386
    dd->right = dd->left + rr.width - 0.0001;	/* right */
2392
    dd->right = dd->left + rr.width - 0.0001;	/* right */
2387
    dd->top = (xd->kind == PRINTER) ? rr.y : 0;	/* top */
2393
    dd->top = (xd->kind == PRINTER) ? rr.y : 0;	/* top */
2388
    dd->bottom = dd->top + rr.height - 0.0001;	/* bottom */
2394
    dd->bottom = dd->top + rr.height - 0.0001;	/* bottom */
2389
 
2395
 
2390
    if (resize == 3) { /* might have got a shrunken window */
2396
    if (resize == 3) { /* might have got a shrunken window */
2391
	int iw = width/pixelWidth(NULL) + 0.5,
2397
	int iw = width/pixelWidth(NULL) + 0.5,
2392
	    ih = height/pixelHeight(NULL) + 0.5;
2398
	    ih = height/pixelHeight(NULL) + 0.5;
2393
	xd->origWidth = dd->right = iw;
2399
	xd->origWidth = dd->right = iw;
2394
	xd->origHeight = dd->bottom = ih;
2400
	xd->origHeight = dd->bottom = ih;
2395
    }
2401
    }
2396
 
2402
 
2397
    /* Nominal Character Sizes in Pixels */
2403
    /* Nominal Character Sizes in Pixels */
2398
    gcharmetric(xd->gawin, xd->font, -1, &a, &d, &w);
2404
    gcharmetric(xd->gawin, xd->font, -1, &a, &d, &w);
2399
    dd->cra[0] = w * xd->rescale_factor;
2405
    dd->cra[0] = w * xd->rescale_factor;
2400
    dd->cra[1] = (a + d) * xd->rescale_factor;
2406
    dd->cra[1] = (a + d) * xd->rescale_factor;
2401
    /* Set basefont to full size: now allow for initial re-scale */
2407
    /* Set basefont to full size: now allow for initial re-scale */
2402
    xd->wanteddpi = xd->truedpi * xd->rescale_factor;
2408
    xd->wanteddpi = xd->truedpi * xd->rescale_factor;
2403
 
2409
 
2404
    /* Character Addressing Offsets */
2410
    /* Character Addressing Offsets */
2405
    /* These are used to plot a single plotting character */
2411
    /* These are used to plot a single plotting character */
2406
    /* so that it is exactly over the plotting point */
2412
    /* so that it is exactly over the plotting point */
2407
 
2413
 
2408
    dd->xCharOffset = 0.50;
2414
    dd->xCharOffset = 0.50;
2409
    dd->yCharOffset = 0.40;
2415
    dd->yCharOffset = 0.40;
2410
    dd->yLineBias = 0.1;
2416
    dd->yLineBias = 0.1;
2411
 
2417
 
2412
    /* Inches per raster unit */
2418
    /* Inches per raster unit */
2413
 
2419
 
2414
    if (R_finite(user_xpinch) && user_xpinch > 0.0)
2420
    if (R_finite(user_xpinch) && user_xpinch > 0.0)
2415
	dd->ipr[0] = 1.0/user_xpinch;
2421
	dd->ipr[0] = 1.0/user_xpinch;
2416
    else
2422
    else
2417
	dd->ipr[0] = pixelWidth(xd->gawin);
2423
	dd->ipr[0] = pixelWidth(xd->gawin);
2418
    if (R_finite(user_ypinch) && user_ypinch > 0.0)
2424
    if (R_finite(user_ypinch) && user_ypinch > 0.0)
2419
	dd->ipr[1] = 1.0/user_ypinch;
2425
	dd->ipr[1] = 1.0/user_ypinch;
2420
    else
2426
    else
2421
	dd->ipr[1] = pixelHeight(xd->gawin);
2427
	dd->ipr[1] = pixelHeight(xd->gawin);
2422
 
2428
 
2423
    /* Device capabilities */
2429
    /* Device capabilities */
2424
    /* Clipping is problematic for X11 */
2430
    /* Clipping is problematic for X11 */
2425
    /* Graphics is clipped, text is not */
2431
    /* Graphics is clipped, text is not */
2426
 
2432
 
2427
    dd->canResizePlot= TRUE;
2433
    dd->canResizePlot= TRUE;
2428
    dd->canChangeFont= FALSE;
2434
    dd->canChangeFont= FALSE;
2429
    dd->canRotateText= TRUE;
2435
    dd->canRotateText= TRUE;
2430
    dd->canResizeText= TRUE;
2436
    dd->canResizeText= TRUE;
2431
    dd->canClip= TRUE;
2437
    dd->canClip= TRUE;
2432
    dd->canHAdj = 1; /* 0, 0.5, 1 */
2438
    dd->canHAdj = 1; /* 0, 0.5, 1 */
2433
    dd->canChangeGamma = TRUE;
2439
    dd->canChangeGamma = TRUE;
2434
 
2440
 
2435
    /* initialise device description (most of the work */
2441
    /* initialise device description (most of the work */
2436
    /* has been done in GA_Open) */
2442
    /* has been done in GA_Open) */
2437
 
2443
 
2438
    xd->resize = (resize == 3);
2444
    xd->resize = (resize == 3);
2439
    xd->locator = FALSE;
2445
    xd->locator = FALSE;
2440
    xd->buffered = buffered;
2446
    xd->buffered = buffered;
2441
    xd->psenv = psenv;
2447
    xd->psenv = psenv;
2442
    {
2448
    {
2443
	SEXP timeouts = GetOption(install("windowsTimeouts"), R_NilValue);
2449
	SEXP timeouts = GetOption(install("windowsTimeouts"), R_NilValue);
2444
	if(isInteger(timeouts)){
2450
	if(isInteger(timeouts)){
2445
	    xd->timeafter = INTEGER(timeouts)[0];
2451
	    xd->timeafter = INTEGER(timeouts)[0];
2446
	    xd->timesince = INTEGER(timeouts)[1];
2452
	    xd->timesince = INTEGER(timeouts)[1];
2447
	} else {
2453
	} else {
2448
	    warning("option `windowsTimeouts' should be integer");
2454
	    warning("option `windowsTimeouts' should be integer");
2449
	    xd->timeafter = 100;
2455
	    xd->timeafter = 100;
2450
	    xd->timesince = 500;
2456
	    xd->timesince = 500;
2451
	}
2457
	}
2452
    }
2458
    }
2453
    dd->displayListOn = (xd->kind == SCREEN);
2459
    dd->displayListOn = (xd->kind == SCREEN);
2454
    if (RConsole && (xd->kind!=SCREEN)) show(RConsole);
2460
    if (RConsole && (xd->kind!=SCREEN)) show(RConsole);
2455
    return TRUE;
2461
    return TRUE;
2456
}
2462
}
2457
 
2463
 
2458
SEXP do_saveDevga(SEXP call, SEXP op, SEXP args, SEXP env)
2464
SEXP do_saveDevga(SEXP call, SEXP op, SEXP args, SEXP env)
2459
{
2465
{
2460
    SEXP filename, type;
2466
    SEXP filename, type;
2461
    char *fn, *tp, display[550];
2467
    char *fn, *tp, display[550];
2462
    int device;
2468
    int device;
2463
    NewDevDesc* dd;
2469
    NewDevDesc* dd;
2464
 
2470
 
2465
    checkArity(op, args);
2471
    checkArity(op, args);
2466
    device = asInteger(CAR(args));
2472
    device = asInteger(CAR(args));
2467
    if(device < 1 || device > NumDevices())
2473
    if(device < 1 || device > NumDevices())
2468
	errorcall(call, "invalid device number");
2474
	errorcall(call, "invalid device number");
2469
    dd = ((GEDevDesc*) GetDevice(device - 1))->dev;
2475
    dd = ((GEDevDesc*) GetDevice(device - 1))->dev;
2470
    if(!dd) errorcall(call, "invalid device");
2476
    if(!dd) errorcall(call, "invalid device");
2471
    filename = CADR(args);
2477
    filename = CADR(args);
2472
    if (!isString(filename) || LENGTH(filename) != 1)
2478
    if (!isString(filename) || LENGTH(filename) != 1)
2473
	errorcall(call, "invalid filename argument");
2479
	errorcall(call, "invalid filename argument");
2474
    fn = CHAR(STRING_ELT(filename, 0));
2480
    fn = CHAR(STRING_ELT(filename, 0));
2475
    fixslash(fn);
2481
    fixslash(fn);
2476
    type = CADDR(args);
2482
    type = CADDR(args);
2477
    if (!isString(type) || LENGTH(type) != 1)
2483
    if (!isString(type) || LENGTH(type) != 1)
2478
	errorcall(call, "invalid type argument");
2484
	errorcall(call, "invalid type argument");
2479
    tp = CHAR(STRING_ELT(type, 0));
2485
    tp = CHAR(STRING_ELT(type, 0));
2480
 
2486
 
2481
    if(!strcmp(tp, "png")) {
2487
    if(!strcmp(tp, "png")) {
2482
	SaveAsPng(dd, fn);
2488
	SaveAsPng(dd, fn);
2483
    } else if (!strcmp(tp,"bmp")) {
2489
    } else if (!strcmp(tp,"bmp")) {
2484
        SaveAsBmp(dd,fn);
2490
        SaveAsBmp(dd,fn);
2485
    } else if(!strcmp(tp, "jpeg") || !strcmp(tp,"jpg")) {
2491
    } else if(!strcmp(tp, "jpeg") || !strcmp(tp,"jpg")) {
2486
      /*Default quality suggested in libjpeg*/
2492
      /*Default quality suggested in libjpeg*/
2487
        SaveAsJpeg(dd, 75, fn);
2493
        SaveAsJpeg(dd, 75, fn);
2488
    } else if (!strcmp(tp, "wmf")) {
2494
    } else if (!strcmp(tp, "wmf")) {
2489
	if(strlen(fn) > 512) {
2495
	if(strlen(fn) > 512) {
2490
	    askok("file path selected is too long: only 512 bytes are allowed");
2496
	    askok("file path selected is too long: only 512 bytes are allowed");
2491
	    return R_NilValue;
2497
	    return R_NilValue;
2492
	}
2498
	}
2493
	sprintf(display, "win.metafile:%s", fn);
2499
	sprintf(display, "win.metafile:%s", fn);
2494
	SaveAsWin(dd, display);
2500
	SaveAsWin(dd, display);
2495
    } else if (!strcmp(tp, "ps")) {
2501
    } else if (!strcmp(tp, "ps")) {
2496
	SaveAsPostscript(dd, fn);
2502
	SaveAsPostscript(dd, fn);
2497
    } else if (!strcmp(tp, "pdf")) {
2503
    } else if (!strcmp(tp, "pdf")) {
2498
	SaveAsPDF(dd, fn);
2504
	SaveAsPDF(dd, fn);
2499
    } else
2505
    } else
2500
	errorcall(call, "unknown type");
2506
	errorcall(call, "unknown type");
2501
    return R_NilValue;
2507
    return R_NilValue;
2502
}
2508
}
2503
 
2509
 
2504
 
2510
 
2505
/* Rbitmap  */
2511
/* Rbitmap  */
2506
#define BITMAP_DLL_NAME "\\BIN\\RBITMAP.DLL\0"
2512
#define BITMAP_DLL_NAME "\\BIN\\RBITMAP.DLL\0"
2507
typedef int (*R_SaveAsBitmap)();
2513
typedef int (*R_SaveAsBitmap)();
2508
static R_SaveAsBitmap R_SaveAsPng, R_SaveAsJpeg, R_SaveAsBmp;
2514
static R_SaveAsBitmap R_SaveAsPng, R_SaveAsJpeg, R_SaveAsBmp;
2509
static int RbitmapAlreadyLoaded = 0;
2515
static int RbitmapAlreadyLoaded = 0;
2510
static HINSTANCE hRbitmapDll;
2516
static HINSTANCE hRbitmapDll;
2511
 
2517
 
2512
static int Load_Rbitmap_Dll()
2518
static int Load_Rbitmap_Dll()
2513
{
2519
{
2514
    if (!RbitmapAlreadyLoaded) {
2520
    if (!RbitmapAlreadyLoaded) {
2515
	char szFullPath[PATH_MAX];
2521
	char szFullPath[PATH_MAX];
2516
	strcpy(szFullPath, R_HomeDir());
2522
	strcpy(szFullPath, R_HomeDir());
2517
	strcat(szFullPath, BITMAP_DLL_NAME);
2523
	strcat(szFullPath, BITMAP_DLL_NAME);
2518
	if (((hRbitmapDll = LoadLibrary(szFullPath)) != NULL) &&
2524
	if (((hRbitmapDll = LoadLibrary(szFullPath)) != NULL) &&
2519
	    ((R_SaveAsPng=
2525
	    ((R_SaveAsPng=
2520
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsPng"))
2526
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsPng"))
2521
	     != NULL) &&
2527
	     != NULL) &&
2522
	    ((R_SaveAsBmp=
2528
	    ((R_SaveAsBmp=
2523
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsBmp"))
2529
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsBmp"))
2524
	     != NULL) &&
2530
	     != NULL) &&
2525
	    ((R_SaveAsJpeg=
2531
	    ((R_SaveAsJpeg=
2526
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsJpeg"))
2532
	      (R_SaveAsBitmap)GetProcAddress(hRbitmapDll, "R_SaveAsJpeg"))
2527
	     != NULL)) {
2533
	     != NULL)) {
2528
	    RbitmapAlreadyLoaded = 1;
2534
	    RbitmapAlreadyLoaded = 1;
2529
	} else {
2535
	} else {
2530
	    if (hRbitmapDll != NULL) FreeLibrary(hRbitmapDll);
2536
	    if (hRbitmapDll != NULL) FreeLibrary(hRbitmapDll);
2531
	    RbitmapAlreadyLoaded= -1;
2537
	    RbitmapAlreadyLoaded= -1;
2532
	}
2538
	}
2533
    }
2539
    }
2534
    return (RbitmapAlreadyLoaded>0);
2540
    return (RbitmapAlreadyLoaded>0);
2535
}
2541
}
2536
 
2542
 
2537
void UnLoad_Rbitmap_Dll()
2543
void UnLoad_Rbitmap_Dll()
2538
{
2544
{
2539
    if (RbitmapAlreadyLoaded) FreeLibrary(hRbitmapDll);
2545
    if (RbitmapAlreadyLoaded) FreeLibrary(hRbitmapDll);
2540
    RbitmapAlreadyLoaded = 0;
2546
    RbitmapAlreadyLoaded = 0;
2541
}
2547
}
2542
 
2548
 
2543
static int png_rows = 0;
2549
static int png_rows = 0;
2544
 
2550
 
2545
static unsigned long privategetpixel2(void *d,int i, int j)
2551
static unsigned long privategetpixel2(void *d,int i, int j)
2546
{
2552
{
2547
    rgb c;
2553
    rgb c;
2548
    c = ((rgb *)d)[i*png_rows + j];
2554
    c = ((rgb *)d)[i*png_rows + j];
2549
    return c;
2555
    return c;
2550
}
2556
}
2551
 
2557
 
2552
/* This is the device version */
2558
/* This is the device version */
2553
static void SaveAsBitmap(NewDevDesc *dd)
2559
static void SaveAsBitmap(NewDevDesc *dd)
2554
{
2560
{
2555
    rect r, r2;
2561
    rect r, r2;
2556
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2562
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2557
    unsigned char *data;
2563
    unsigned char *data;
2558
 
2564
 
2559
    r = ggetcliprect(xd->gawin);
2565
    r = ggetcliprect(xd->gawin);
2560
    gsetcliprect(xd->gawin, r2 = getrect(xd->gawin));
2566
    gsetcliprect(xd->gawin, r2 = getrect(xd->gawin));
2561
    if(xd->fp) {
2567
    if(xd->fp) {
2562
	getbitmapdata2(xd->gawin, &data);
2568
	getbitmapdata2(xd->gawin, &data);
2563
	if(data) {
2569
	if(data) {
2564
	    png_rows = r2.width;
2570
	    png_rows = r2.width;
2565
	    if (xd->kind == PNG)
2571
	    if (xd->kind == PNG)
2566
		R_SaveAsPng(data, xd->windowWidth, xd->windowHeight,
2572
		R_SaveAsPng(data, xd->windowWidth, xd->windowHeight,
2567
			    privategetpixel2, 0, xd->fp,
2573
			    privategetpixel2, 0, xd->fp,
2568
			    R_OPAQUE(xd->bg) ? 0 : xd->pngtrans) ;
2574
			    R_OPAQUE(xd->bg) ? 0 : xd->pngtrans) ;
2569
	    else if (xd->kind == JPEG)
2575
	    else if (xd->kind == JPEG)
2570
		R_SaveAsJpeg(data, xd->windowWidth, xd->windowHeight,
2576
		R_SaveAsJpeg(data, xd->windowWidth, xd->windowHeight,
2571
			     privategetpixel2, 0, xd->quality, xd->fp) ;
2577
			     privategetpixel2, 0, xd->quality, xd->fp) ;
2572
	    else
2578
	    else
2573
		R_SaveAsBmp(data, xd->windowWidth, xd->windowHeight,
2579
		R_SaveAsBmp(data, xd->windowWidth, xd->windowHeight,
2574
			    privategetpixel2, 0, xd->fp);
2580
			    privategetpixel2, 0, xd->fp);
2575
	    free(data);
2581
	    free(data);
2576
	} else
2582
	} else
2577
	    warning("processing of the plot ran out of memory");
2583
	    warning("processing of the plot ran out of memory");
2578
	fclose(xd->fp);
2584
	fclose(xd->fp);
2579
    }
2585
    }
2580
    gsetcliprect(xd->gawin, r);
2586
    gsetcliprect(xd->gawin, r);
2581
    xd->fp = NULL;
2587
    xd->fp = NULL;
2582
}
2588
}
2583
 
2589
 
2584
/* These are the menu item versions */
2590
/* These are the menu item versions */
2585
static void SaveAsPng(NewDevDesc *dd,char *fn)
2591
static void SaveAsPng(NewDevDesc *dd,char *fn)
2586
{
2592
{
2587
    FILE *fp;
2593
    FILE *fp;
2588
    rect r, r2;
2594
    rect r, r2;
2589
    unsigned char *data;
2595
    unsigned char *data;
2590
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2596
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2591
 
2597
 
2592
    if (!Load_Rbitmap_Dll()) {
2598
    if (!Load_Rbitmap_Dll()) {
2593
	R_ShowMessage("Impossible to load Rbitmap.dll");
2599
	R_ShowMessage("Impossible to load Rbitmap.dll");
2594
	return;
2600
	return;
2595
    }
2601
    }
2596
    if ((fp=fopen(fn, "wb")) == NULL) {
2602
    if ((fp=fopen(fn, "wb")) == NULL) {
2597
	char msg[MAX_PATH+32];
2603
	char msg[MAX_PATH+32];
2598
 
2604
 
2599
	strcpy(msg, "Impossible to open ");
2605
	strcpy(msg, "Impossible to open ");
2600
	strncat(msg, fn, MAX_PATH);
2606
	strncat(msg, fn, MAX_PATH);
2601
	R_ShowMessage(msg);
2607
	R_ShowMessage(msg);
2602
	return;
2608
	return;
2603
    }
2609
    }
2604
    r = ggetcliprect(xd->bm);
2610
    r = ggetcliprect(xd->bm);
2605
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2611
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2606
    getbitmapdata2(xd->bm, &data);
2612
    getbitmapdata2(xd->bm, &data);
2607
    if(data) {
2613
    if(data) {
2608
	png_rows = r2.width;
2614
	png_rows = r2.width;
2609
	R_SaveAsPng(data, xd->windowWidth, xd->windowHeight,
2615
	R_SaveAsPng(data, xd->windowWidth, xd->windowHeight,
2610
		    privategetpixel2, 0, fp, 0) ;
2616
		    privategetpixel2, 0, fp, 0) ;
2611
	free(data);
2617
	free(data);
2612
    } else
2618
    } else
2613
	warning("processing of the plot ran out of memory");
2619
	warning("processing of the plot ran out of memory");
2614
    /* R_OPAQUE(xd->bg) ? 0 : xd->canvascolor) ; */
2620
    /* R_OPAQUE(xd->bg) ? 0 : xd->canvascolor) ; */
2615
    gsetcliprect(xd->bm, r);
2621
    gsetcliprect(xd->bm, r);
2616
    fclose(fp);
2622
    fclose(fp);
2617
}
2623
}
2618
 
2624
 
2619
static void SaveAsJpeg(NewDevDesc *dd,int quality,char *fn)
2625
static void SaveAsJpeg(NewDevDesc *dd,int quality,char *fn)
2620
{
2626
{
2621
    FILE *fp;
2627
    FILE *fp;
2622
    rect r, r2;
2628
    rect r, r2;
2623
    unsigned char *data;
2629
    unsigned char *data;
2624
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2630
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2625
 
2631
 
2626
    if (!Load_Rbitmap_Dll()) {
2632
    if (!Load_Rbitmap_Dll()) {
2627
	R_ShowMessage("Impossible to load Rbitmap.dll");
2633
	R_ShowMessage("Impossible to load Rbitmap.dll");
2628
	return;
2634
	return;
2629
    }
2635
    }
2630
    if ((fp=fopen(fn,"wb")) == NULL) {
2636
    if ((fp=fopen(fn,"wb")) == NULL) {
2631
	char msg[MAX_PATH+32];
2637
	char msg[MAX_PATH+32];
2632
	strcpy(msg, "Impossible to open ");
2638
	strcpy(msg, "Impossible to open ");
2633
	strncat(msg, fn, MAX_PATH);
2639
	strncat(msg, fn, MAX_PATH);
2634
	R_ShowMessage(msg);
2640
	R_ShowMessage(msg);
2635
	return;
2641
	return;
2636
    }
2642
    }
2637
    r = ggetcliprect(xd->bm);
2643
    r = ggetcliprect(xd->bm);
2638
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2644
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2639
    getbitmapdata2(xd->bm, &data);
2645
    getbitmapdata2(xd->bm, &data);
2640
    if(data) {
2646
    if(data) {
2641
	png_rows = r2.width;
2647
	png_rows = r2.width;
2642
	R_SaveAsJpeg(data,xd->windowWidth, xd->windowHeight,
2648
	R_SaveAsJpeg(data,xd->windowWidth, xd->windowHeight,
2643
		     privategetpixel2, 0, quality, fp) ;
2649
		     privategetpixel2, 0, quality, fp) ;
2644
	free(data);
2650
	free(data);
2645
    } else
2651
    } else
2646
	warning("processing of the plot ran out of memory");
2652
	warning("processing of the plot ran out of memory");
2647
    gsetcliprect(xd->bm, r);
2653
    gsetcliprect(xd->bm, r);
2648
    fclose(fp);
2654
    fclose(fp);
2649
}
2655
}
2650
 
2656
 
2651
 
2657
 
2652
static void SaveAsBmp(NewDevDesc *dd,char *fn)
2658
static void SaveAsBmp(NewDevDesc *dd,char *fn)
2653
{
2659
{
2654
    FILE *fp;
2660
    FILE *fp;
2655
    rect r, r2;
2661
    rect r, r2;
2656
    unsigned char *data;
2662
    unsigned char *data;
2657
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2663
    gadesc *xd = (gadesc *) dd->deviceSpecific;
2658
 
2664
 
2659
    if (!Load_Rbitmap_Dll()) {
2665
    if (!Load_Rbitmap_Dll()) {
2660
	R_ShowMessage("Impossible to load Rbitmap.dll");
2666
	R_ShowMessage("Impossible to load Rbitmap.dll");
2661
	return;
2667
	return;
2662
    }
2668
    }
2663
    if ((fp=fopen(fn, "wb")) == NULL) {
2669
    if ((fp=fopen(fn, "wb")) == NULL) {
2664
	char msg[MAX_PATH+32];
2670
	char msg[MAX_PATH+32];
2665
 
2671
 
2666
	strcpy(msg, "Impossible to open ");
2672
	strcpy(msg, "Impossible to open ");
2667
	strncat(msg, fn, MAX_PATH);
2673
	strncat(msg, fn, MAX_PATH);
2668
	R_ShowMessage(msg);
2674
	R_ShowMessage(msg);
2669
	return;
2675
	return;
2670
    }
2676
    }
2671
    r = ggetcliprect(xd->bm);
2677
    r = ggetcliprect(xd->bm);
2672
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2678
    gsetcliprect(xd->bm, r2 = getrect(xd->bm));
2673
 
2679
 
2674
    getbitmapdata2(xd->bm, &data);
2680
    getbitmapdata2(xd->bm, &data);
2675
    if(data) {
2681
    if(data) {
2676
	png_rows = r2.width;
2682
	png_rows = r2.width;
2677
	R_SaveAsBmp(data, xd->windowWidth, xd->windowHeight,
2683
	R_SaveAsBmp(data, xd->windowWidth, xd->windowHeight,
2678
		    privategetpixel2, 0, fp) ;
2684
		    privategetpixel2, 0, fp) ;
2679
	free(data);
2685
	free(data);
2680
    } else
2686
    } else
2681
	warning("processing of the plot ran out of memory");
2687
	warning("processing of the plot ran out of memory");
2682
    gsetcliprect(xd->bm, r);
2688
    gsetcliprect(xd->bm, r);
2683
    fclose(fp);
2689
    fclose(fp);
2684
}
2690
}
2685
 
2691
 
2686
#include "Startup.h"
2692
#include "Startup.h"
2687
extern UImode CharacterMode;
2693
extern UImode CharacterMode;
2688
 
2694
 
2689
SEXP do_bringtotop(SEXP call, SEXP op, SEXP args, SEXP env)
2695
SEXP do_bringtotop(SEXP call, SEXP op, SEXP args, SEXP env)
2690
{
2696
{
2691
    int dev, stay;
2697
    int dev, stay;
2692
    GEDevDesc *gdd;
2698
    GEDevDesc *gdd;
2693
    gadesc *xd;
2699
    gadesc *xd;
2694
 
2700
 
2695
    checkArity(op, args);
2701
    checkArity(op, args);
2696
    dev = asInteger(CAR(args));
2702
    dev = asInteger(CAR(args));
2697
    stay = asInteger(CADR(args));
2703
    stay = asInteger(CADR(args));
2698
 
2704
 
2699
    if(dev == -1) { /* console */
2705
    if(dev == -1) { /* console */
2700
	if(CharacterMode == RGui) BringToTop(RConsole, stay);
2706
	if(CharacterMode == RGui) BringToTop(RConsole, stay);
2701
    } else {
2707
    } else {
2702
	if(dev < 1 || dev > R_MaxDevices || dev == NA_INTEGER)
2708
	if(dev < 1 || dev > R_MaxDevices || dev == NA_INTEGER)
2703
	    errorcall(call, "invalid value of `which'");
2709
	    errorcall(call, "invalid value of `which'");
2704
	gdd = (GEDevDesc *) GetDevice(dev - 1);
2710
	gdd = (GEDevDesc *) GetDevice(dev - 1);
2705
	if(!gdd) errorcall(call, "invalid device");
2711
	if(!gdd) errorcall(call, "invalid device");
2706
	xd = (gadesc *) gdd->dev->deviceSpecific;
2712
	xd = (gadesc *) gdd->dev->deviceSpecific;
2707
	if(!xd) errorcall(call, "invalid device");
2713
	if(!xd) errorcall(call, "invalid device");
2708
	if(stay && ismdi()) error("requires SDI mode");
2714
	if(stay && ismdi()) error("requires SDI mode");
2709
	BringToTop(xd->gawin, stay);
2715
	BringToTop(xd->gawin, stay);
2710
    }
2716
    }
2711
    return R_NilValue;
2717
    return R_NilValue;
2712
}
2718
}