The R Project SVN R

Rev

Rev 28254 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
19652 iacus 1
 /*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  file devQuartz.c
24766 iacus 4
 *  Copyright (C) 2002-2003  Stefano M. Iacus and the R core team
19652 iacus 5
 *
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
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
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
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 */
25156 maechler 20
 
19652 iacus 21
#ifndef __QUARTZ_DEVICE__
22
#define __QUARTZ_DEVICE__
23
 
25522 iacus 24
 
19665 iacus 25
#ifdef HAVE_CONFIG_H
26
#include <config.h>
27
#endif
28
#include <Defn.h>
29
#include <Graphics.h>
30
#include <Rdevices.h>
31
 
19652 iacus 32
 
25137 iacus 33
#if defined(__APPLE_CC__) && defined(HAVE_AQUA)
26036 iacus 34
#define __DEBUGGING__
25137 iacus 35
 
26114 iacus 36
unsigned char Lat2Mac[] = { 
37
 32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 
38
 32,  32,  32,  32,  32,  32, 245,  96, 171, 246,
39
247, 248, 249, 250, 172,  32, 251, 252,  32, 253, 
40
254, 255,  32, 193, 162, 163,  32, 180,  32, 164, 
41
172, 169, 187, 199, 194,  45, 168, 248, 161, 177,
42
 32,  32, 171, 181, 166, 225, 252,  32, 188, 200, 
43
 32,  32,  32, 192, 203, 231, 229, 204, 128, 129,
44
174, 130, 233, 131, 230, 232, 237, 234, 235, 236,
45
 32, 132, 241, 238, 239, 205, 133,  32, 175, 244,
46
242, 243, 134,  32,  32, 167, 136, 135, 137, 139,
47
138, 140, 190, 141, 143, 142, 144, 145, 147, 146,
48
148, 149,  32, 150, 152, 151, 153, 155, 154, 214, 
49
191, 157, 156, 158, 159,  32,  32, 216};
50
 
28362 murdoch 51
#define MAX_NON_SYMBS 17
52
unsigned char NotSymbols[] = {
53
 32, 33, 37, 38, 40, 41, 42, 43, 44, 58, 
54
 60, 61, 62, 91, 93, 95, 123, 125
55
};
56
 
57
/* conversion table to use symbol font enoded as
58
   unicode under MacOSX and no longer MacRoman
59
*/
60
unsigned char Lat2Uni[] = { 
61
    32, /* space */
62
	33, /* exclam */
63
    34, /* universal" */
64
	35, /* numbersign */
65
   154, /* existential */
66
	37, /* percent */
67
	38, /* ampersand */
68
	39, /* suchthat */
69
    40, /* parenleft */
70
    41, /* parenright */
71
   155, /* asteriskmath */
72
	 3, /* plus */
73
	44, /* comma */
74
	60, /* minus */
75
	46, /* period */
76
	58, /* slash*/
77
	48, /* 0 */
78
	49, /* 1 */
79
	50, /* 2 */
80
	51, /* 3 */
81
	52, /* 4 */
82
	53, /* 5 */
83
	54, /* 6 */
84
	55, /* 7 */
85
	56, /* 8 */
86
	57, /* 9 */
87
    58, /* colon */
88
	59, /* semicolon */
89
	60, /* less */
90
	62, /* equal */
91
	62, /* greater */
92
	63, /* question */
93
   129, /* congruent */
94
    73, /* Alpha */
95
	74, /* Beta */
96
	93, /* Chi */
97
	54, /* Delta */
98
	76, /* Epsilon */
99
	92, /* Phi */
100
	75, /* Gamma */
101
	78, /* Eta */
102
	80, /* Iota */
103
	85, /* theta1 */
104
	81, /* Kappa */
105
	82, /* Lambda */
106
	83, /* Mu */
107
	84, /* Nu */
108
	86, /* Omicron */
109
	87, /* Pi */
110
	79, /* Theta */
111
	88, /* Rho */
112
	89, /* Sigma */
113
	90, /* Tau */
114
	91, /* Upsilon */
115
	45, /* sigma1 */
116
	49, /* Omega */
117
	93, /* Xi */
118
	94, /* Psi */
119
	77, /* Zeta */
120
	33, /* bracketleft */  /* Miscellaneous Special Characters */
121
    92, /* therefore */
122
	35, /* bracketright */
123
   140, /* perpendicular */
124
	32, /* underscore */
125
	51, /* radicalex */
126
 95, /* alpha */
127
 96, /* beta */
128
114, /* chi */
129
 98, /* delta */
130
 161, /* epsilon */
131
 113, /* phi */
132
 97, /* gamma */
133
 100, /* eta */
134
 102, /* iota */
135
 160, /* phi1 */
136
 103, /* kappa */
137
 104, /* lambda */
138
  43, /* mu */
139
 105, /* nu */
140
 107, /* omicron */
141
 47, /* pi */
142
 101, /* theta */
143
 108, /* rho */
144
 109, /* sigma */
145
 111, /* tau */
146
 112, /* upsilon */
147
 159, /* omega1 */
148
 116, /* omega */
149
 106, /* xi */
150
 115, /* psi */
151
 110, /* zeta */
152
 123, /* braceleft */
153
 180, /* bar */
154
 125, /* braceright */
155
 126, /* similar */
156
 32, 32, 32, 32, 
157
 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
158
 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
159
 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
160
 175, /* Upsilon1 */	/* Lone Greek */
161
 118, /* minute */
162
  41, /* lessequal */
163
 177, /* fraction */
164
  39, /* infinity */
165
 166, /* florin      ??? */
166
 121, /* club */
167
 122, /* diamond */
168
 120, /* heart */
169
 123, /* spade */
170
  67, /* arrowboth */
171
  64, /* arrowleft */
172
  66, /* arrowup */
173
  65, /* arrowright */
174
  63, /* arrowdown */
175
  36, /* degree */
176
  40, /* plusminus */
177
 119, /* second */
178
  42, /* greaterequal */
179
 155, /* multiply */
180
 124, /* proportional */
181
  44, /* partialdiff */
182
  20, /* bullet */
183
  56, /* divide */
184
  38, /* notequal */
185
  62, /* equivalence */
186
  53, /* approxequal ??? */
187
  55, /* ellipsis    ??? */
188
 189, /* arrowvertex ??? */ 
189
 190, /* arrowhorizex ??? */
190
 191, /* carriagereturn */
191
 148, /* aleph */
192
 188, /* Ifraktur */
193
 189, /* Rfraktur */
194
 195, /* weierstrass ??? */
195
 128, /* circlemultiply */
196
 127, /* circleplus */
197
 146, /* emptyset */
198
  69, /* intersection */
199
  70, /* union */
200
 130, /* propersuperset */
201
 131, /* reflexsuperset */
202
 134, /* notsubset */
203
 132, /* propersubset */
204
 133, /* reflexsubset */
205
  68, /* element */
206
 141, /* notelement */
207
 144, /* angle */
208
 162, /* gradient */
209
 186, /* registerserif */
210
 185, /* copyrightserif */
211
 184, /* trademarkserif */
212
  87, /* product */
213
  51, /* radical */
214
  46, /* dotmath */
215
  32,
216
 217, /* logicaland ???*/
217
 218, /* logicalor ???*/
218
 139, /* arrowdblboth */
219
 136, /* arrowdblleft */
220
 138, /* arrowdblup */
221
 137, /* arrowdblright */
222
 135, /* arrowdbldown */
223
  57, /* lozenge */
224
 225, /* angleleft ???*/
225
 183, /* registersans */
226
 182, /* copyrightsans */
227
 181, /* trademarksans */
228
  89, /* summation */
229
 163, /* parenlefttp */
230
 179, /* parenleftex */
231
 164, /* parenleftbt */
232
 149, /* bracketlefttp */
233
 147, /* bracketleftex */
234
 150, /* bracketleftbt */
235
 168, /* bracelefttp */
236
 169, /* braceleftmid */
237
 170, /* braceleftbt */
238
 172, /* braceex */
239
  32,
240
 241, /* angleright */
241
  48, /* integral */
242
  71, /* integraltp */
243
 180, /* integralex */
244
  72, /* integralbt */
245
 165, /* parenrighttp */
246
 181, /* parenrightex */
247
 166, /* parenrightbt */
248
 151, /* bracketrighttp */
249
 166, /* bracketrightex */
250
 152, /* bracketrightbt */
251
 172, /* bracerighttp */
252
 173, /* bracerightmid */
253
 174, /* bracerightbt */
254
 255 /* NULL */
255
};
256
 
26114 iacus 257
unsigned char Mac2Lat[] = { 
258
196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 
259
228, 227, 229, 231, 233, 232, 234, 235, 237, 236, 
260
238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 
261
251, 252,  32, 176, 162, 163, 167,  32, 182, 223, 
262
174, 169,  32, 146, 152,  32, 198, 216,  32, 177,
263
 32,  32, 165, 181,  32,  32,  32,  32,  32, 170, 
264
186,  32, 230, 248, 191, 161, 172,  32,  32,  32,
265
 32, 171, 187,  32,  32, 192, 195, 213,  32,  32,
266
 32,  32,  32,  32,  96,  39, 247,  32, 255,  32, 
267
 32,  32,  32,  32,  32,  32,  32, 183,  32,  32,
268
 32, 194, 202, 193, 203, 200, 205, 206, 207, 204, 
269
211, 212,  32, 210, 218, 219, 217, 144, 147, 148, 
270
149, 150, 151, 154, 155, 157, 158, 159};
271
 
19652 iacus 272
#include <Carbon/Carbon.h>
273
#include <CoreFoundation/CoreFoundation.h>
274
#include <ApplicationServices/ApplicationServices.h>
275
 
276
 
277
#define R_RED(col)	(((col)	   )&255)
278
#define R_GREEN(col)	(((col)>> 8)&255)
279
#define R_BLUE(col)	(((col)>>16)&255)
24935 iacus 280
#define kRAppSignature '0FFF'
19652 iacus 281
 
27014 ripley 282
#if HAVE_AQUA
25175 iacus 283
extern  DL_FUNC ptr_GetQuartzParameters;
27014 ripley 284
extern	Rboolean useaqua;
19652 iacus 285
 
25175 iacus 286
void GetQuartzParameters(double *width, double *height, double *ps, char *family, Rboolean *antialias, Rboolean *autorefresh) {ptr_GetQuartzParameters(width, height, ps, family, antialias, autorefresh);}
27014 ripley 287
#endif
25175 iacus 288
 
25837 iacus 289
#define kOnScreen 	0
290
#define kOnFilePDF 	1
291
#define kOnFilePICT	2
292
#define kOnClipboard 	3
293
#define kOnPrinter	4
25175 iacus 294
 
25837 iacus 295
 
19652 iacus 296
   /***************************************************************************/
297
   /* Each driver can have its own device-specic graphical                    */
298
   /* parameters and resources.  these should be wrapped                      */
299
   /* in a structure (like the x11Desc structure below)                       */
300
   /* and attached to the overall device description via                      */
301
   /* the dd->deviceSpecific pointer                                          */
302
   /* NOTE that there are generic graphical parameters                        */
303
   /* which must be set by the device driver, but are                         */
304
   /* common to all device types (see Graphics.h)                             */
305
   /* so go in the GPar structure rather than this device-                    */
306
   /* specific structure                                                      */
307
   /***************************************************************************/
25156 maechler 308
 
19652 iacus 309
typedef struct {
310
    int cex;
311
    int windowWidth;
312
    int windowHeight;
313
    Boolean resize;
314
    int Text_Font;          /* 0 is system font and 4 is monaco */
315
    int fontface;           /* Typeface */
316
    int fontsize;           /* Size in points */
317
    int usefixed;
25837 iacus 318
    int color;		        /* color */
319
    int fill;	        	/* fill color */
19652 iacus 320
    WindowPtr window;
321
    int	lineType;
322
    int lineWidth;
323
    Boolean Antialias;		/* Use Antialiasing */
324
    Boolean Autorefresh;
325
    char	*family;
25837 iacus 326
    CGContextRef context;     /* This is the context used by Quartz for OnScreen drawings */
327
    CGContextRef auxcontext;  /* Additional context used for: cliboard, printer, file     */
19652 iacus 328
    double	xscale;
329
    double	yscale;
25837 iacus 330
    int		where;
19652 iacus 331
}
332
QuartzDesc;
333
 
25750 iacus 334
OSStatus QuartzEventHandler(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
335
 
336
static const EventTypeSpec	QuartzEvents[] =
24987 iacus 337
{
25750 iacus 338
        { kEventClassWindow, kEventWindowClose },
339
        { kEventClassWindow, kEventWindowBoundsChanged }
24987 iacus 340
};
19652 iacus 341
 
342
Rboolean innerQuartzDeviceDriver(NewDevDesc *dd, char *display,
25156 maechler 343
			 double width, double height, double pointsize,
19652 iacus 344
			 char *family, Rboolean antialias, Rboolean autorefresh);
25156 maechler 345
 
19652 iacus 346
Rboolean QuartzDeviceDriver(DevDesc *dd, char *display,
25156 maechler 347
			 double width, double height, double pointsize,
19652 iacus 348
			 char *family, Rboolean antialias, Rboolean autorefresh);
349
 
24935 iacus 350
OSStatus SetCGContext(QuartzDesc *xd);
19652 iacus 351
 
352
 
353
/* Device primitives */
354
 
355
static Rboolean	Quartz_Open(NewDevDesc *, QuartzDesc *, char *,double, double);
356
static void 	Quartz_Close(NewDevDesc *dd);
357
static void 	Quartz_Activate(NewDevDesc *dd);
358
static void 	Quartz_Deactivate(NewDevDesc *dd);
359
static void 	Quartz_Size(double *left, double *right,
360
		     	 double *bottom, double *top, NewDevDesc *dd);
27236 murrell 361
static void 	Quartz_NewPage(R_GE_gcontext *gc, NewDevDesc *dd);
25156 maechler 362
static void 	Quartz_Clip(double x0, double x1, double y0, double y1,
27236 murrell 363
			    NewDevDesc *dd);
364
static double 	Quartz_StrWidth(char *str, 
365
				R_GE_gcontext *gc,
366
				NewDevDesc *dd);
25156 maechler 367
static void 	Quartz_Text(double x, double y, char *str,
27236 murrell 368
			    double rot, double hadj, 
369
			    R_GE_gcontext *gc,
370
			    NewDevDesc *dd);
19652 iacus 371
static void 	Quartz_Rect(double x0, double y0, double x1, double y1,
27236 murrell 372
			    R_GE_gcontext *gc,
373
			    NewDevDesc *dd);
374
static void 	Quartz_Circle(double x, double y, double r, 
375
			      R_GE_gcontext *gc,
376
			      NewDevDesc *dd);
19652 iacus 377
static void 	Quartz_Line(double x1, double y1, double x2, double y2,
27236 murrell 378
			    R_GE_gcontext *gc,
379
			    NewDevDesc *dd);
380
static void 	Quartz_Polyline(int n, double *x, double *y, 
381
				R_GE_gcontext *gc,
382
				NewDevDesc *dd);
383
static void 	Quartz_Polygon(int n, double *x, double *y, 
384
			       R_GE_gcontext *gc,
385
			       NewDevDesc *dd);
19652 iacus 386
static Rboolean Quartz_Locator(double *x, double *y, NewDevDesc *dd);
387
static void 	Quartz_Mode(int mode, NewDevDesc *dd);
388
static void 	Quartz_Hold(NewDevDesc *dd);
27236 murrell 389
static void 	Quartz_MetricInfo(int c,
390
				  R_GE_gcontext *gc,
391
				  double* ascent, double* descent, 
392
				  double* width,
393
				  NewDevDesc *dd);
19652 iacus 394
 
395
 
396
static void Quartz_SetFill(int fill, double gamma,  NewDevDesc *dd);
397
static void Quartz_SetStroke(int color, double gamma,  NewDevDesc *dd);
26131 iacus 398
static void Quartz_SetLineDash(int lty, double lwd, NewDevDesc *dd);
19652 iacus 399
static void Quartz_SetLineWidth(double lwd,  NewDevDesc *dd);
27236 murrell 400
static void Quartz_SetFont(int style,  double cex, double ps,  NewDevDesc *dd);
25855 iacus 401
static CGContextRef	GetContext(QuartzDesc *xd);
19652 iacus 402
 
403
 
404
 
25855 iacus 405
 
19652 iacus 406
static SEXP gcall;
407
static char *SaveString(SEXP sxp, int offset)
408
{
409
    char *s;
410
    if(!isString(sxp) || length(sxp) <= offset)
411
	errorcall(gcall, "invalid string argument");
412
    s = R_alloc(strlen(CHAR(STRING_ELT(sxp, offset)))+1, sizeof(char));
413
    strcpy(s, CHAR(STRING_ELT(sxp, offset)));
414
    return s;
415
}
416
 
417
 
418
/*  Quartz Device Driver Parameters:
419
 *  -----------------		cf with ../unix/X11/devX11.c
420
 *  display	= display
421
 *  width	= width in inches
422
 *  height	= height in inches
423
 *  ps		= pointsize
424
 *  family  = Postscript fon family name
425
 *  Antialias = wheter to make antialiasing
426
 */
427
 
25156 maechler 428
 
19652 iacus 429
SEXP do_Quartz(SEXP call, SEXP op, SEXP args, SEXP env)
430
{
431
    NewDevDesc *dev = NULL;
432
    GEDevDesc *dd;
433
    char *display, *vmax, *family=NULL;
25175 iacus 434
    char fontfamily[255];
19652 iacus 435
    double height, width, ps;
436
    Rboolean  antialias, autorefresh;
437
    gcall = call;
438
    vmax = vmaxget();
25156 maechler 439
    display = SaveString(CAR(args), 0);
19652 iacus 440
    args = CDR(args);
441
    width = asReal(CAR(args));	args = CDR(args);
442
    height = asReal(CAR(args)); args = CDR(args);
443
    if (width <= 0 || height <= 0)
444
	errorcall(call, "invalid width or height");
445
    ps = asReal(CAR(args));  args = CDR(args);
446
    family = SaveString(CAR(args), 0);    args = CDR(args);
447
    antialias = asLogical(CAR(args));   args = CDR(args);
25156 maechler 448
    autorefresh = asLogical(CAR(args));
449
 
450
 
451
 
19652 iacus 452
     R_CheckDeviceAvailable();
453
    /* Allocate and initialize the device driver data */
454
     BEGIN_SUSPEND_INTERRUPTS {
455
      if (!(dev = (NewDevDesc *) calloc(1, sizeof(NewDevDesc))))
456
	   return 0;
457
    /* Do this for early redraw attempts */
458
    dev->displayList = R_NilValue;
459
    /* Make sure that this is initialised before a GC can occur.
460
     * This (and displayList) get protected during GC
461
     */
462
    dev->savedSnapshot = R_NilValue;
463
 
25175 iacus 464
    strcpy(fontfamily, family);
27014 ripley 465
#ifdef HAVE_AQUA
466
    if(useaqua)
467
     GetQuartzParameters(&width, &height, &ps, fontfamily, &antialias, &autorefresh);
468
#endif
25855 iacus 469
 
25156 maechler 470
    if (!QuartzDeviceDriver((DevDesc *)dev, display, width, height, ps,
25175 iacus 471
       fontfamily, antialias, autorefresh)) {
19652 iacus 472
	 free(dev);
473
	 errorcall(call, "unable to start device Quartz\n");
474
    }
25156 maechler 475
    gsetVar(install(".Device"), mkString("quartz"), R_NilValue);
19652 iacus 476
    dd = GEcreateDevDesc(dev);
477
    addDevice((DevDesc*)dd);
478
    GEinitDisplayList(dd);
479
    } END_SUSPEND_INTERRUPTS;
480
    vmaxset(vmax);
481
    return R_NilValue;
482
}
483
 
484
 
485
 
486
 
487
 
488
Rboolean QuartzDeviceDriver(DevDesc *dd, char *display,
25156 maechler 489
			 double width, double height, double pointsize,
19652 iacus 490
			 char *family, Rboolean antialias, Rboolean autorefresh)
491
{
492
return innerQuartzDeviceDriver((NewDevDesc *)dd, display,
493
			 width,  height,  pointsize, family, antialias, autorefresh);
494
}
495
 
496
 
497
Rboolean innerQuartzDeviceDriver(NewDevDesc *dd, char *display,
25156 maechler 498
			 double width, double height, double pointsize,
19652 iacus 499
			 char *family, Rboolean antialias, Rboolean autorefresh)
500
{
501
    QuartzDesc *xd;
502
    int ps;
503
    Rect rect;
504
    OSStatus err;
25156 maechler 505
 
506
 
19652 iacus 507
    if (!(xd = (QuartzDesc *)malloc(sizeof(QuartzDesc))))
508
	return 0;
25156 maechler 509
 
20597 iacus 510
    if(!Quartz_Open(dd, xd, display, width, height))
511
     return(FALSE);
25156 maechler 512
 
19652 iacus 513
    ps = pointsize;
514
    if (ps < 6 || ps > 24) ps = 10;
515
    ps = 2 * (ps / 2);
516
    dd->startps = ps;
517
    dd->startfont = 1;
518
    dd->startlty = LTY_SOLID;
519
    dd->startgamma = 1;
520
 
521
    dd->newDevStruct = 1;
522
 
523
    dd->open       = Quartz_Open;
524
    dd->close      = Quartz_Close;
525
    dd->activate   = Quartz_Activate;
526
    dd->deactivate = Quartz_Deactivate;
527
    dd->size       = Quartz_Size;
528
    dd->newPage    = Quartz_NewPage;
529
    dd->clip       = Quartz_Clip;
530
    dd->strWidth   = Quartz_StrWidth;
531
    dd->text       = Quartz_Text;
532
    dd->rect       = Quartz_Rect;
533
    dd->circle     = Quartz_Circle;
534
    dd->line       = Quartz_Line;
535
    dd->polyline   = Quartz_Polyline;
536
    dd->polygon    = Quartz_Polygon;
537
    dd->locator    = Quartz_Locator;
538
    dd->mode       = Quartz_Mode;
539
    dd->hold       = Quartz_Hold;
540
 
541
    dd->metricInfo = Quartz_MetricInfo;
542
 
543
    dd->left        = 0;
544
    dd->right       =  xd->windowWidth;
545
    dd->bottom      =  xd->windowHeight;
546
    dd->top         = 0;
547
 
548
    dd->xCharOffset = 0.4900;
549
    dd->yCharOffset = 0.3333;
550
    dd->yLineBias = 0.1;
551
 
552
    dd->cra[0] = ps / 2;
553
    dd->cra[1] = ps;
554
 
555
    dd->ipr[0] = 1.0 / 72;
556
    dd->ipr[1] = 1.0 / 72;
557
 
558
    dd->canResizePlot = TRUE;
559
    dd->canChangeFont = TRUE;
560
    dd->canRotateText = TRUE;
561
    dd->canResizeText = TRUE;
562
    dd->canClip       = FALSE;
563
    dd->canHAdj = 0;
564
    dd->canChangeGamma = FALSE;
565
 
566
 
567
    /* It is used to set the font that you will be used on the postscript and
568
       drawing.
569
    */
25156 maechler 570
 
19652 iacus 571
    /* There is the place for you to set the default value of the MAC Devices */
572
    xd->cex = 1.0;
573
    xd->resize = 0;
574
    xd->Text_Font = 4; /* initial is monaco */
575
    xd->fontface = 0;  /* initial is plain text */
576
    xd->fontsize = 12; /* initial is 12 size */
577
    xd->Antialias = antialias; /* by default Antialias if on */
578
    xd->Autorefresh = autorefresh; /* by default it is on */
25156 maechler 579
 
19652 iacus 580
    if(family){
581
     xd->family = malloc(sizeof(family)+1);
25156 maechler 582
     strcpy(xd->family,family);
19652 iacus 583
    }
584
    else
585
     xd->family = NULL;
25156 maechler 586
 
25837 iacus 587
    xd->where  = kOnScreen;
24935 iacus 588
    err = SetCGContext(xd);
589
 
590
/* This scale factor is needed in MetricInfo */
591
    xd->xscale = width/72.0;
592
    xd->yscale = height/72.0;
25156 maechler 593
 
24935 iacus 594
    dd->deviceSpecific = (void *) xd;
595
    dd->displayListOn = TRUE;
596
 
597
    return 1;
598
}
599
 
600
OSStatus SetCGContext(QuartzDesc *xd)
601
{
602
    Rect rect;
25156 maechler 603
    OSStatus	err = noErr;
24935 iacus 604
    CGRect    cgRect;
25156 maechler 605
 
24935 iacus 606
    if(xd->context)
607
        CGContextRelease(xd->context);
25156 maechler 608
 
25855 iacus 609
    if(xd->auxcontext)
610
        CGContextRelease(xd->auxcontext);
611
 
24766 iacus 612
    err = CreateCGContextForPort(GetWindowPort(xd->window), &xd->context);
25156 maechler 613
 
19652 iacus 614
    /*  Translate to QuickDraw coordinate system */
24935 iacus 615
 
19652 iacus 616
    GetPortBounds(GetWindowPort(xd->window), &rect);
24766 iacus 617
    CGContextTranslateCTM(xd->context,0, (float)(rect.bottom - rect.top));
25156 maechler 618
 
19652 iacus 619
/* Be aware that by performing a negative scale in the following line of
620
   code, your text will also be flipped
621
*/
24766 iacus 622
    CGContextScaleCTM(xd->context, 1, -1);
19652 iacus 623
 
624
  /* We apply here Antialiasing if necessary */
24766 iacus 625
    CGContextSetShouldAntialias(xd->context, xd->Antialias);
19652 iacus 626
 
24935 iacus 627
   return err;
19652 iacus 628
}
629
 
630
static Rboolean	Quartz_Open(NewDevDesc *dd, QuartzDesc *xd, char *dsp,
631
		    double wid, double hgt)
632
{
633
 
634
	OSStatus	err;
635
	WindowRef 	devWindow =  NULL;
636
	Rect		devBounds;
24935 iacus 637
        Str255		Title;
19652 iacus 638
	char		buffer[250];
639
	int 		devnum = devNumber((DevDesc *)dd);
25156 maechler 640
 
19652 iacus 641
    xd->windowWidth = wid*72;
642
    xd->windowHeight = hgt*72;
643
    xd->window = NULL;
24935 iacus 644
    xd->context = NULL;
25855 iacus 645
    xd->auxcontext = NULL;
19652 iacus 646
    dd->startfill = R_RGB(255, 255, 255);
647
    dd->startcol = R_RGB(0, 0, 0);
648
    /* Create a new window with the specified size */
25156 maechler 649
 
650
 
19652 iacus 651
	SetRect(&devBounds, 400, 400, 400 + xd->windowWidth, 400 + xd->windowHeight ) ;
25156 maechler 652
 
25786 iacus 653
        err = CreateNewWindow( kDocumentWindowClass, kWindowStandardHandlerAttribute|kWindowVerticalZoomAttribute | kWindowCollapseBoxAttribute|kWindowResizableAttribute | kWindowCloseBoxAttribute ,
19652 iacus 654
		& devBounds, & devWindow);
25156 maechler 655
 
19652 iacus 656
	sprintf(buffer,"Quartz (%d) - Active",devnum+1);
657
	CopyCStringToPascal(buffer,Title);
24935 iacus 658
        SetWTitle(devWindow, Title);
25156 maechler 659
 
19652 iacus 660
	ShowWindow(devWindow);
25786 iacus 661
 
25750 iacus 662
	err = InstallWindowEventHandler( devWindow, NewEventHandlerUPP(QuartzEventHandler),
663
                                          GetEventTypeCount(QuartzEvents),
664
                                          QuartzEvents, (void *)devWindow, NULL);
665
 
19652 iacus 666
    if(err != noErr)
667
     return(0);
25156 maechler 668
 
19652 iacus 669
    xd->window = devWindow;
670
    xd->color = xd->fill = NA_INTEGER;
671
    xd->resize = false;
672
    xd->lineType = 0;
673
    xd->lineWidth = 1;
674
    return TRUE;
675
}
676
 
677
static void 	Quartz_Close(NewDevDesc *dd)
678
{
679
  QuartzDesc *xd = (QuartzDesc *) dd->deviceSpecific;
680
 
681
  if(xd->window)
682
   DisposeWindow(xd->window);
25156 maechler 683
 
19652 iacus 684
  if(xd->family)
685
   free(xd->family);
24935 iacus 686
 
687
  if(xd->context)
688
   CGContextRelease(xd->context);
25156 maechler 689
 
25855 iacus 690
  if(xd->auxcontext)
691
   CGContextRelease(xd->auxcontext);
692
 
19652 iacus 693
  free(xd);
694
}
695
 
696
static void 	Quartz_Activate(NewDevDesc *dd)
697
{
698
	Str255	Title;
699
	char	buffer[250];
700
	QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
701
	int devnum = devNumber((DevDesc *)dd);
24935 iacus 702
        OSStatus err;
25156 maechler 703
 
19652 iacus 704
	sprintf(buffer,"Quartz (%d) - Active",devnum+1);
705
	CopyCStringToPascal(buffer,Title);
706
	SetWTitle(xd->window,Title);
24935 iacus 707
 
25156 maechler 708
/*
24935 iacus 709
   We add a property to the Window each time we activate it.
710
   We should only make this the first time we open the device.
711
*/
25688 iacus 712
        err = SetWindowProperty(xd->window,kRAppSignature,'QRTZ',sizeof(int),&devnum);
25156 maechler 713
 
19652 iacus 714
	ShowWindow(xd->window);
715
 
716
}
717
 
718
 
719
 
720
static void 	Quartz_Deactivate(NewDevDesc *dd)
721
{
722
	Str255	Title;
723
	char	buffer[250];
724
	QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
725
	int devnum = devNumber((DevDesc *)dd);
25156 maechler 726
 
19652 iacus 727
	sprintf(buffer,"Quartz (%d) - Not Active",devnum+1);
728
	CopyCStringToPascal(buffer,Title);
729
	SetWTitle(xd->window,Title);
730
	ShowWindow(xd->window);
731
}
732
 
733
 
734
static void 	Quartz_Size(double *left, double *right,
735
		     	 double *bottom, double *top, NewDevDesc *dd)
736
{
24935 iacus 737
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
738
    Rect portRect;
25156 maechler 739
 
24935 iacus 740
    GetWindowPortBounds ( xd->window, & portRect ) ;
25156 maechler 741
 
24935 iacus 742
    *left = 0.0;
743
    *right = portRect.right;
744
    *bottom = portRect.bottom;
745
    *top = 0.0;
25156 maechler 746
 
24935 iacus 747
    xd->windowWidth = *right - *left;
748
    xd->windowHeight = *bottom - *top;
749
    SetCGContext(xd);
25156 maechler 750
 
24935 iacus 751
    return;
19652 iacus 752
}
753
 
24984 iacus 754
void Quartz_ReSizeWin(NewDevDesc *dd)
755
{
756
 
757
}
758
 
25855 iacus 759
static CGContextRef     GetContext(QuartzDesc *xd){
760
 
761
   switch(xd->where){
762
 
763
    case kOnScreen:
764
        return(xd->context);
765
    break;
766
 
767
    case kOnFilePDF:
768
        return(xd->auxcontext);
769
    break;
770
 
771
    default:
772
        return(NULL);
773
    break;
774
 
775
   }
776
}
777
 
27236 murrell 778
static void 	Quartz_NewPage(R_GE_gcontext *gc,
779
			       NewDevDesc *dd)
19652 iacus 780
{
781
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
782
    CGPoint origin = {0.0, 0.0};
783
    CGSize  size;
784
    CGRect area;
25156 maechler 785
 
19652 iacus 786
    size.width = xd->windowWidth;
787
    size.height = xd->windowHeight;
25156 maechler 788
 
19652 iacus 789
    area.origin = origin;
790
    area.size = size;
25156 maechler 791
 
27236 murrell 792
    if(gc->fill == NA_INTEGER)
793
      gc->fill = R_RGB(255, 255, 255);
25789 iacus 794
 
27236 murrell 795
    Quartz_SetFill(gc->fill, gc->gamma, dd);
25156 maechler 796
 
25855 iacus 797
    CGContextFillRect( GetContext(xd), area);
798
    CGContextFlush( GetContext(xd) );   /* we need to flash it just now */
19652 iacus 799
 
800
}
801
 
25156 maechler 802
static void 	Quartz_Clip(double x0, double x1, double y0, double y1,
19652 iacus 803
		     	NewDevDesc *dd)
804
{
805
 return;
806
}
807
 
27236 murrell 808
static double 	Quartz_StrWidth(char *str, 
809
				R_GE_gcontext *gc,
810
				NewDevDesc *dd)
19652 iacus 811
{
812
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
813
    CGPoint position;
814
 
25855 iacus 815
    CGContextSaveGState( GetContext(xd) );
816
    CGContextTranslateCTM( GetContext(xd), 0, 0 );
19652 iacus 817
 
25855 iacus 818
    CGContextScaleCTM( GetContext(xd), -1, 1);
25156 maechler 819
 
25855 iacus 820
    CGContextRotateCTM( GetContext(xd), -1.0 * 3.1416);
25156 maechler 821
 
25855 iacus 822
    CGContextSetTextDrawingMode( GetContext(xd), kCGTextInvisible );
25156 maechler 823
 
27236 murrell 824
    Quartz_SetFont(gc->fontface, gc->cex,  gc->ps, dd);
19652 iacus 825
 
25855 iacus 826
    CGContextShowTextAtPoint( GetContext(xd), 0, 0, str, strlen(str) );
25156 maechler 827
 
25855 iacus 828
    position = CGContextGetTextPosition( GetContext(xd) );
25156 maechler 829
 
25855 iacus 830
    CGContextRestoreGState( GetContext(xd) );
25156 maechler 831
    return(position.x);
19652 iacus 832
}
833
 
834
 
26131 iacus 835
 
28362 murdoch 836
/* This new version of Quartz_SetFont handles correctly the unicode encoding of
837
   the Symbol font under Panther
838
 */
26131 iacus 839
 
27236 murrell 840
static void Quartz_SetFont(int style,  double cex, double ps, NewDevDesc *dd)
19652 iacus 841
{
26131 iacus 842
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
19652 iacus 843
    int size = cex * ps + 0.5;
26131 iacus 844
    FMFontFamily CurrFontId;
845
    GrafPtr 	savePort;
846
    Str255	CurrFontName;
847
    char	CurrFont[256];
848
 
849
    GetPort(&savePort);
850
    SetPortWindowPort(xd->window);
851
 
27236 murrell 852
    switch(style){
19652 iacus 853
     case 5:
26131 iacus 854
      strcpy(CurrFont,"Symbol");
28362 murdoch 855
	  CGContextSelectFont( GetContext(xd), CurrFont, size,kCGEncodingFontSpecific);
19652 iacus 856
     break;
25156 maechler 857
 
19652 iacus 858
     default:
26131 iacus 859
        if(xd->family)
860
            strcpy(CurrFont,xd->family);
861
        else
862
            strcpy(CurrFont,"Helvetica");
28362 murdoch 863
		    CGContextSelectFont( GetContext(xd), CurrFont, size, kCGEncodingMacRoman);	
19652 iacus 864
     break;
865
    }
866
 
28362 murdoch 867
/* This is needed for test only purposes 
868
    if(strcmp(CurrFont,"Symbol")==0)
869
     CGContextSelectFont( GetContext(xd), CurrFont, size, kCGEncodingFontSpecific);
870
*/
26131 iacus 871
    CopyCStringToPascal(CurrFont,CurrFontName);
872
    GetFNum(CurrFontName, &CurrFontId);
873
    TextSize(size);
874
    TextFont(CurrFontId);
875
    SetPort(savePort);
19652 iacus 876
}
877
 
25855 iacus 878
 
28362 murdoch 879
 
880
Boolean IsThisASymbol(unsigned char c);
881
Boolean IsThisASymbol(unsigned char c){
882
 int i;
883
 for(i=0; i <  MAX_NON_SYMBS; i++){
884
  if(c == NotSymbols[i])
885
   return(false);
886
  }
887
 
888
  return(true); 
889
}
890
 
891
/* This new version of Quartz_Text handles correctly the symbol font under Panther */
892
 
893
 
25156 maechler 894
static void 	Quartz_Text(double x, double y, char *str,
27236 murrell 895
			    double rot, double hadj, 
896
			    R_GE_gcontext *gc,
897
			    NewDevDesc *dd)
19652 iacus 898
{
26114 iacus 899
    int len,i;
900
    char *buf=NULL;
28362 murdoch 901
	char symbuf;
26114 iacus 902
    unsigned char tmp;
25156 maechler 903
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
28362 murdoch 904
 
25855 iacus 905
    CGContextSaveGState( GetContext(xd) );
906
    CGContextTranslateCTM( GetContext(xd), x, y );
19652 iacus 907
 
25855 iacus 908
    CGContextScaleCTM( GetContext(xd) , -1, 1);
25156 maechler 909
 
25855 iacus 910
    CGContextRotateCTM( GetContext(xd) , (-1.0  + 2*rot/360)  * 3.1416);
19652 iacus 911
 
27236 murrell 912
    Quartz_SetStroke( gc->col, gc->gamma, dd);
19652 iacus 913
 
25855 iacus 914
    CGContextSetTextDrawingMode( GetContext(xd), kCGTextFill );
27236 murrell 915
    Quartz_SetFill(gc->col, gc->gamma, dd);
916
    Quartz_SetFont(gc->fontface, gc->cex,  gc->ps, dd);
26114 iacus 917
    len = strlen(str);
25156 maechler 918
 
28362 murdoch 919
    if( (gc->fontface == 5) && (len==1) ){
920
	   tmp = (unsigned char)str[0];
921
       if(tmp>31)
922
        symbuf = (char)Lat2Uni[tmp-31-1];
923
	   else
924
	    symbuf = str[0];
925
       if( !IsThisASymbol(tmp) ){
926
		 Quartz_SetFont(-1, gc->cex,  gc->ps, dd);
927
		 symbuf = str[0];
928
       }
929
     CGContextShowTextAtPoint( GetContext(xd), 0, 0, &symbuf, len );
930
     } else {
26114 iacus 931
     if( (buf = malloc(len)) != NULL){
932
      for(i=0;i <len;i++){
933
        tmp = (unsigned char)str[i];
934
      if(tmp>127)
935
       buf[i] = (char)Lat2Mac[tmp-127-1];
936
      else
937
       buf[i] = str[i]; 
938
      }
939
     CGContextShowTextAtPoint( GetContext(xd), 0, 0, buf, len );
940
     free(buf);
941
     }  
942
    }
25855 iacus 943
    CGContextRestoreGState( GetContext(xd) );
19652 iacus 944
}
945
 
946
 
28362 murdoch 947
 
19652 iacus 948
static void 	Quartz_Rect(double x0, double y0, double x1, double y1,
27236 murrell 949
			    R_GE_gcontext *gc,
950
			    NewDevDesc *dd)
19652 iacus 951
{
952
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
953
	CGRect rect;
954
    CGPoint origin;
955
    CGSize  size;
956
 
957
    origin.x = x0;
958
    origin.y = y0;
25156 maechler 959
 
19652 iacus 960
    size.width = x1-x0;
961
    size.height = y1-y0;
962
 
963
    rect.size = size;
964
    rect.origin = origin;
965
 
25855 iacus 966
    CGContextSaveGState( GetContext(xd) );
19652 iacus 967
 
27236 murrell 968
    Quartz_SetLineWidth(gc->lwd, dd);
969
    Quartz_SetLineDash(gc->lty, gc->lwd, dd);
25156 maechler 970
 
27236 murrell 971
    Quartz_SetFill( gc->fill, gc->gamma, dd);
25855 iacus 972
    CGContextFillRect( GetContext(xd), rect);
25156 maechler 973
 
27236 murrell 974
    Quartz_SetStroke( gc->col, gc->gamma, dd);
25855 iacus 975
    CGContextStrokeRect( GetContext(xd), rect);
19652 iacus 976
 
25855 iacus 977
    CGContextRestoreGState( GetContext(xd) );
25156 maechler 978
 
19652 iacus 979
 
980
}
981
 
27236 murrell 982
static void 	Quartz_Circle(double x, double y, double r,
983
			      R_GE_gcontext *gc,
984
			      NewDevDesc *dd)
19652 iacus 985
{
986
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
25156 maechler 987
 
25855 iacus 988
    CGContextSaveGState( GetContext(xd) );
25156 maechler 989
 
990
 
25855 iacus 991
    CGContextBeginPath( GetContext(xd) );
25156 maechler 992
 
27236 murrell 993
    Quartz_SetLineWidth(gc->lwd, dd);
994
    Quartz_SetLineDash(gc->lty, gc->lwd, dd);
25156 maechler 995
 
25855 iacus 996
    CGContextAddArc( GetContext(xd), (float)x , (float)y, (float)r, 3.141592654 * 2.0, 0.0, 0);
27236 murrell 997
    Quartz_SetFill( gc->fill, gc->gamma, dd);
25855 iacus 998
    CGContextFillPath( GetContext(xd) );
25156 maechler 999
 
27236 murrell 1000
    Quartz_SetStroke( gc->col, gc->gamma, dd);
25855 iacus 1001
    CGContextAddArc( GetContext(xd), (float)x , (float)y, (float)r, 3.141592654 * 2.0, 0.0, 0);
1002
    CGContextStrokePath( GetContext(xd) );
25156 maechler 1003
 
1004
 
25855 iacus 1005
    CGContextRestoreGState( GetContext(xd) );
19652 iacus 1006
 
1007
}
1008
 
1009
 
1010
static void 	Quartz_Line(double x1, double y1, double x2, double y2,
27236 murrell 1011
			    R_GE_gcontext *gc,
1012
			    NewDevDesc *dd)
19652 iacus 1013
{
1014
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1015
    CGPoint lines[ 2 ];
1016
    Rect rect;
1017
 
25855 iacus 1018
    CGContextSaveGState( GetContext(xd) );
25156 maechler 1019
 
1020
 
25855 iacus 1021
    CGContextBeginPath( GetContext(xd) );
25156 maechler 1022
 
19652 iacus 1023
    lines[0].x = (float)x1;
1024
    lines[0].y = (float)y1;
1025
    lines[1].x = (float)x2;
1026
    lines[1].y = (float)y2;
1027
 
25156 maechler 1028
 
27236 murrell 1029
    Quartz_SetLineWidth(gc->lwd,  dd);
1030
    Quartz_SetLineDash(gc->lty, gc->lwd, dd);
19652 iacus 1031
 
25855 iacus 1032
    CGContextAddLines( GetContext(xd), &lines[0], 2 );
25156 maechler 1033
 
27236 murrell 1034
    Quartz_SetStroke( gc->col, gc->gamma,  dd);
25156 maechler 1035
 
25855 iacus 1036
    CGContextStrokePath( GetContext(xd) );
25156 maechler 1037
 
25855 iacus 1038
    CGContextRestoreGState( GetContext(xd) );
19652 iacus 1039
 
1040
}
1041
 
1042
 
27236 murrell 1043
static void 	Quartz_Polyline(int n, double *x, double *y,
1044
				R_GE_gcontext *gc,
1045
				NewDevDesc *dd)
19652 iacus 1046
{
1047
  	CGPoint *lines;
1048
    int	i;
25156 maechler 1049
    CGrafPtr savedPort, port;
19652 iacus 1050
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1051
 
1052
    lines = (CGPoint *)malloc(sizeof(CGPoint)*n);
1053
 
1054
    if(lines == NULL)
1055
     return;
25156 maechler 1056
 
19652 iacus 1057
    for (i = 0; i < n; i++) {
1058
	  lines[i].x = (float)x[i];
1059
	  lines[i].y = (float)y[i];
1060
	 }
1061
 
1062
 
25855 iacus 1063
    CGContextSaveGState( GetContext(xd) );
19652 iacus 1064
 
27236 murrell 1065
    Quartz_SetLineWidth(gc->lwd,  dd);
1066
    Quartz_SetLineDash(gc->lty, gc->lwd,  dd);
19652 iacus 1067
 
25855 iacus 1068
    CGContextBeginPath( GetContext(xd) );
1069
    CGContextAddLines( GetContext(xd), &lines[0], n );
27236 murrell 1070
    Quartz_SetStroke( gc->col, gc->gamma, dd);
25855 iacus 1071
    CGContextStrokePath( GetContext(xd) );
19652 iacus 1072
 
25855 iacus 1073
    CGContextRestoreGState( GetContext(xd) );
19652 iacus 1074
 
1075
}
1076
 
1077
 
1078
 
26131 iacus 1079
static void Quartz_SetLineDash(int newlty, double lwd, NewDevDesc *dd)
19652 iacus 1080
{
1081
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
26131 iacus 1082
    float dashlist[8];
1083
    int i, ndash = 0;
1084
 
1085
    lwd *= 0.75;  /* kludge from postscript/pdf */
1086
    for(i = 0; i < 8 && newlty & 15 ; i++) {
1087
	dashlist[ndash++] = (lwd >= 1 ? lwd: 1) * (newlty & 15);
1088
	newlty = newlty >> 4;
1089
    }
1090
    CGContextSetLineDash( GetContext(xd), 0, dashlist, ndash);
1091
    xd->lineType = newlty;
1092
}
25156 maechler 1093
 
1094
 
19652 iacus 1095
static void Quartz_SetLineWidth(double lwd, NewDevDesc *dd)
1096
{
1097
 	QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
25156 maechler 1098
 
19652 iacus 1099
	if(lwd < 1)
1100
	 lwd=1;
1101
 
1102
 	xd->lineWidth = lwd;
1103
 
25156 maechler 1104
 
25855 iacus 1105
    CGContextSetLineWidth( GetContext(xd), lwd );
19652 iacus 1106
 
1107
}
1108
 
1109
 
1110
 
1111
static void Quartz_SetStroke(int color, double gamma, NewDevDesc *dd)
1112
{
1113
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1114
    float alpha = 1.0;
25156 maechler 1115
 
19652 iacus 1116
 	xd->color = color;
25156 maechler 1117
 
19652 iacus 1118
	if(color == NA_INTEGER)
1119
	 alpha = 0.0;
25156 maechler 1120
 
25855 iacus 1121
    CGContextSetRGBStrokeColor( GetContext(xd), (float)R_RED(color)/255.0, (float)R_GREEN(color)/255.0, (float)R_BLUE(color)/255.0, alpha);
25156 maechler 1122
 
19652 iacus 1123
}
1124
 
1125
static void Quartz_SetFill(int fill, double gamma, NewDevDesc *dd)
1126
{
1127
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1128
    float alpha = 1.0;
25156 maechler 1129
 
19652 iacus 1130
    xd->fill = fill;
25156 maechler 1131
 
19652 iacus 1132
 	if(fill == NA_INTEGER)
1133
 	 alpha = 0.0;
25156 maechler 1134
 
25855 iacus 1135
    CGContextSetRGBFillColor( GetContext(xd), (float)R_RED(fill)/255.0, (float)R_GREEN(fill)/255.0, (float)R_BLUE(fill)/255.0, alpha);
19652 iacus 1136
 
1137
}
1138
 
27236 murrell 1139
static void 	Quartz_Polygon(int n, double *x, double *y, 
1140
			       R_GE_gcontext *gc,
1141
			       NewDevDesc *dd)
19652 iacus 1142
{
1143
   int	i;
1144
   QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1145
   CGPoint *lines;
1146
 
1147
 
25855 iacus 1148
   CGContextSaveGState( GetContext(xd) );
25156 maechler 1149
 
1150
 
25855 iacus 1151
   CGContextBeginPath( GetContext(xd) );
27236 murrell 1152
   Quartz_SetLineWidth(gc->lwd, dd);
1153
   Quartz_SetLineDash(gc->lty,  gc->lwd, dd);
19652 iacus 1154
 
1155
 
1156
    lines = (CGPoint *)malloc(sizeof(CGPoint)*(n+1));
1157
 
1158
    if(lines == NULL)
1159
     return;
25156 maechler 1160
 
19652 iacus 1161
    for (i = 0; i < n; i++) {
1162
	  lines[i].x = (float)x[i];
1163
	  lines[i].y = (float)y[i];
25855 iacus 1164
    }
1165
    lines[n].x = (float)x[0];
1166
    lines[n].y = (float)y[0];
19652 iacus 1167
 
25855 iacus 1168
    CGContextAddLines( GetContext(xd), &lines[0], n+1 );
27236 murrell 1169
    Quartz_SetFill( gc->fill, gc->gamma, dd);
25855 iacus 1170
    CGContextFillPath( GetContext(xd) );
19652 iacus 1171
 
25855 iacus 1172
    CGContextAddLines( GetContext(xd), &lines[0], n+1 );
27236 murrell 1173
    Quartz_SetStroke( gc->col, gc->gamma,  dd);
25855 iacus 1174
    CGContextStrokePath( GetContext(xd) );
25156 maechler 1175
 
25855 iacus 1176
    CGContextRestoreGState( GetContext(xd) );
19652 iacus 1177
 
1178
}
1179
 
1180
static Rboolean Quartz_Locator(double *x, double *y, NewDevDesc *dd)
1181
{
25886 iacus 1182
    EventRecord event;
1183
    SInt16 key;
1184
    Boolean gotEvent;
1185
    Boolean mouseClick = false;
1186
    Point myPoint;
1187
    WindowPtr window;
1188
    SInt16 partCode;
1189
    GrafPtr savePort;
1190
    Cursor		arrow ;
1191
    QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1192
 
1193
    GetPort(&savePort);
1194
 
1195
    SetPortWindowPort(xd->window);
1196
    SetCursor( GetQDGlobalsArrow ( & arrow ) ) ;
1197
 
1198
 
1199
    while(!mouseClick) {
1200
 
1201
 
1202
	gotEvent = WaitNextEvent( everyEvent, &event, 0, nil);
1203
 
1204
 
1205
	if (event.what == mouseDown) {
1206
	    partCode = FindWindow(event.where, &window);
1207
	    if ((window == (xd->window)) && (partCode == inContent)) {
1208
		myPoint = event.where;
1209
		GlobalToLocal(&myPoint);
1210
		*x = (double)(myPoint.h);
1211
		*y = (double)(myPoint.v);
1212
		mouseClick = true;
1213
	    }
1214
 
1215
	}
1216
 
1217
	if (event.what == keyDown) {
1218
	    key = (event.message & charCodeMask);
1219
	    if (key == 0x0D){
1220
		SetPort(savePort);
1221
		return FALSE;
1222
	    }
1223
	}
1224
    }
1225
 
1226
    SetPort(savePort);
1227
    return TRUE;
19652 iacus 1228
}
1229
 
1230
static void 	Quartz_Mode(int mode, NewDevDesc *dd)
1231
{
25786 iacus 1232
  QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
1233
 
1234
  if(mode == 0)
25855 iacus 1235
   CGContextFlush( GetContext(xd) );
19652 iacus 1236
}
1237
 
1238
static void 	Quartz_Hold(NewDevDesc *dd)
1239
{
1240
 return;
1241
}
1242
 
28362 murdoch 1243
#if !defined(FixedToFloat)
1244
# define FixedToFloat(a)	((float)(a) / fixed1)
1245
# define FloatToFixed(a)	((Fixed)((float) (a) * fixed1))
1246
#endif
19652 iacus 1247
 
27236 murrell 1248
static void 	Quartz_MetricInfo(int c, 
1249
				  R_GE_gcontext *gc,
1250
				  double* ascent, double* descent, 
1251
				  double* width,
1252
				  NewDevDesc *dd)
19652 iacus 1253
{
26131 iacus 1254
    FMetricRec myFMetric;
1255
    QuartzDesc *xd = (QuartzDesc *) dd-> deviceSpecific;
19652 iacus 1256
    char testo[2];
26131 iacus 1257
    CGrafPtr savedPort;
1258
    Rect bounds;
1259
    CGPoint position;
28362 murdoch 1260
	unsigned char tmp;
25156 maechler 1261
 
19652 iacus 1262
    testo[0] = c;
1263
    testo[1] = '\0';
1264
 
1265
    GetPort(&savedPort);
25156 maechler 1266
 
19652 iacus 1267
    SetPort(GetWindowPort(xd->window));
1268
 
27236 murrell 1269
    Quartz_SetFont(gc->fontface, gc->cex,  gc->ps, dd);
25156 maechler 1270
 
26131 iacus 1271
    if(c==0){
1272
        FontMetrics(&myFMetric);
27236 murrell 1273
        *ascent = xd->yscale *floor(gc->cex * gc->ps + 0.5) * FixedToFloat(myFMetric.ascent);
1274
        *descent = xd->yscale*floor(gc->cex * gc->ps + 0.5) * FixedToFloat(myFMetric.descent);
26131 iacus 1275
    } else {
19652 iacus 1276
 
26131 iacus 1277
    CGContextSaveGState( GetContext(xd) );
1278
    CGContextTranslateCTM( GetContext(xd), 0, 0 );
1279
    CGContextScaleCTM( GetContext(xd), -1, 1);
1280
    CGContextRotateCTM( GetContext(xd), -1.0 * 3.1416);
1281
    CGContextSetTextDrawingMode( GetContext(xd), kCGTextInvisible );
27236 murrell 1282
    Quartz_SetFont(gc->fontface, gc->cex,  gc->ps, dd);
28362 murdoch 1283
 
1284
	tmp = (unsigned char)c;
1285
    if( (gc->fontface == 5) ){
1286
       if( (tmp>31) && IsThisASymbol(tmp))
1287
        testo[0] = (char)Lat2Uni[tmp-31-1];
1288
       else	
1289
		Quartz_SetFont(-1, gc->cex,  gc->ps, dd);
1290
	 } else {
1291
        if(tmp>127)
1292
         testo[0] = (char)Lat2Mac[tmp-127-1];
1293
     }	 
1294
 
26131 iacus 1295
    CGContextShowTextAtPoint( GetContext(xd), 0, 0, testo, 1 );
28362 murdoch 1296
 
1297
 
26131 iacus 1298
    position = CGContextGetTextPosition( GetContext(xd) );
1299
    CGContextRestoreGState( GetContext(xd) );
1300
 
1301
        QDTextBounds(1,testo,&bounds);
1302
        *ascent = -bounds.top;
1303
        *descent = bounds.bottom;
1304
        *width = bounds.right - bounds.left;
1305
        *width = position.x;
1306
    }    
1307
 
19652 iacus 1308
    SetPort(savedPort);
1309
 
1310
 
1311
 return;
1312
}
24935 iacus 1313
 
25750 iacus 1314
OSStatus QuartzEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData )
1315
{
1316
	OSStatus 	err = eventNotHandledErr;
1317
	UInt32		eventKind = GetEventKind( inEvent ), RWinCode, devsize;
1318
        int		devnum;
1319
        WindowRef 	EventWindow;
1320
        EventRef	REvent;
25753 iacus 1321
        NewDevDesc 	*dd;
1322
 
25750 iacus 1323
        if( GetEventClass(inEvent) != kEventClassWindow)
1324
         return(err);
1325
 
1326
        GetEventParameter(inEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(EventWindow),
1327
                                NULL, &EventWindow);
1328
 
1329
        if(GetWindowProperty(EventWindow, kRAppSignature, 'QRTZ', sizeof(int), NULL, &devnum) != noErr)
1330
           return eventNotHandledErr;
1331
 
1332
        switch(eventKind){
1333
            case kEventWindowClose:
1334
            {
1335
                KillDevice(GetDevice(devnum));
1336
                err= noErr; 
1337
            }
1338
            break;
1339
 
25753 iacus 1340
            case kEventWindowBoundsChanged:
25750 iacus 1341
                if( (dd = ((GEDevDesc*) GetDevice(devnum))->dev) ){
25753 iacus 1342
                    QuartzDesc *xd = (QuartzDesc *) dd-> deviceSpecific;
1343
                    Rect portRect;
1344
                    GetWindowPortBounds ( xd->window, & portRect ) ;
1345
                    if( (xd->windowWidth != portRect.right) || (xd->windowHeight != portRect.bottom) ){
1346
                     dd->size(&(dd->left), &(dd->right), &(dd->bottom), &(dd->top), dd);
1347
                     GEplayDisplayList((GEDevDesc*) GetDevice(devnum));      
1348
                    }  
25750 iacus 1349
                    err = noErr;
1350
                }
1351
            break;
1352
 
1353
            default:
1354
            break;
1355
        }    
1356
 
1357
	return err;
1358
}
1359
 
25156 maechler 1360
#else
19665 iacus 1361
SEXP do_Quartz(SEXP call, SEXP op, SEXP args, SEXP env)
1362
{
25156 maechler 1363
	warning("Quartz device not available on this platform\n");
19665 iacus 1364
    return R_NilValue;
1365
}
25137 iacus 1366
#endif  /* __APPLE_CC__  && HAVE_AQUA*/
19652 iacus 1367
 
1368
#endif /* __QUARTZ_DEVICE__ */