The R Project SVN R

Rev

Rev 62314 | Rev 65368 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13974 hornik 1
/*
2
 *  R : A Computer Langage for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
59764 ripley 4
 *  Copyright (C) 1998--2012  The R Core Team
13974 hornik 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
42307 ripley 17
 *  along with this program; if not, a copy is available at
18
 *  http://www.r-project.org/Licenses/
13974 hornik 19
 */
20
 
34639 ripley 21
/* <UTF8>
32555 ripley 22
   Used XTextWidth and XDrawText, so need to use fontsets
32422 ripley 23
 
32555 ripley 24
   Also needed input context.
32432 ripley 25
*/
26
 
34639 ripley 27
/* The version for R 2.1.0 is partly based on patches by
35930 ripley 28
   Ei-ji Nakama <nakama@ki.rim.or.jp> for use with Japanese fonts. */
32429 ripley 29
 
34639 ripley 30
#define DPRINTS(x) printf(#x "=[%s]\n", x)
31
#define DPRINTX(x) printf(#x "=%x\n", x)
32
#define DPRINTD(x) printf(#x "=%d\n", x)
33
 
13974 hornik 34
#ifdef HAVE_CONFIG_H
35
#include <config.h>
36
#endif
37
 
57538 ripley 38
#define R_USE_SIGNALS 1
36498 ripley 39
#include <Defn.h>
13974 hornik 40
#include <stdlib.h>
46045 murdoch 41
#include <Rinternals.h>
42
#include <R_ext/Parse.h>  /* parsing is used in handling escape codes */
13974 hornik 43
 
46045 murdoch 44
 
29066 ripley 45
#ifndef _Xconst
46
#define _Xconst const
47
#endif
13974 hornik 48
#include <X11/X.h>
49
#include <X11/Xlib.h>
50
#include <X11/Xutil.h>
51
#include <X11/keysym.h>
52
#include <X11/cursorfont.h>
36044 ripley 53
#include <X11/Intrinsic.h>
13974 hornik 54
 
40756 ripley 55
#include <Print.h>
56
/* For the input handlers of the event loop mechanism: */
57
#include <R_ext/eventloop.h>
41831 rgentlem 58
#include <R_ext/RS.h>           /* for CallocCharBuf */
32677 ripley 59
# define USE_FONTSET 1
35844 ripley 60
/* In theory we should do this, but it works less well
61
# ifdef X_HAVE_UTF8_STRING
62
#  define HAVE_XUTF8TEXTEXTENTS 1
63
#  define HAVE_XUTF8DRAWSTRING 1
64
#  define HAVE_XUTF8DRAWIMAGESTRING 1
65
# endif */
32677 ripley 66
 
29067 ripley 67
#ifndef HAVE_KEYSYM
68
#define KeySym int
69
#endif
28840 ripley 70
 
13974 hornik 71
#define DEEvent XEvent
72
 
73
typedef enum { UP, DOWN, LEFT, RIGHT } DE_DIRECTION;
74
 
75
typedef enum {UNKNOWNN, NUMERIC, CHARACTER} CellType;
76
 
77
/* EXPORTS : */
44345 ripley 78
SEXP in_RX11_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho);
13974 hornik 79
 
40759 ripley 80
/* Global variables needed for the graphics */
81
static Display *iodisplay = NULL;
82
static XContext deContext;
83
static int nView = 0; /* number of open data windows */
84
static int fdView = -1;
85
 
86
typedef struct {
87
    Window iowindow;
88
    GC iogc;
89
    XFontStruct *font_info;
90
    SEXP work, names, lens;
91
    PROTECT_INDEX wpi, npi, lpi;
92
    int box_w;                       /* width of a box */
93
    int boxw[100];                   /* widths of cells */
94
    int box_h;                       /* height of a box */
95
    int windowWidth;                 /* current width of the window */
96
    int fullwindowWidth;
97
    int windowHeight;                /* current height of the window */
98
    int fullwindowHeight;
99
    int crow;                        /* current row */
100
    int ccol;                        /* current column */
101
    int nwide, nhigh;
102
    int colmax, colmin, rowmax, rowmin;
103
    int bwidth;			/* width of the border */
104
    int hht;			/* height of header  */
105
    int text_offset;
106
    int nboxchars;
107
    int xmaxused, ymaxused;
108
    char labform[6];
109
    Rboolean isEditor;
110
    Atom prot;
111
} destruct, *DEstruct;
112
 
13974 hornik 113
/* Local Function Definitions */
32424 ripley 114
 
40759 ripley 115
static void advancerect(DEstruct, DE_DIRECTION);
116
static int  CheckControl(DEEvent *);
117
static int  CheckShift(DEEvent *);
13974 hornik 118
static int  checkquit(int);
40759 ripley 119
static void clearrect(DEstruct);
120
static void closerect(DEstruct);
121
static void clearwindow(DEstruct);
122
static void closewin(DEstruct);
123
static void copycell(DEstruct);
124
static void doControl(DEstruct, DEEvent*);
125
static int  doMouseDown(DEstruct, DEEvent*);
126
static void doSpreadKey(DEstruct, int, DEEvent*);
127
static void downlightrect(DEstruct);
128
static void drawwindow(DEstruct);
129
static void drawcol(DEstruct, int);
130
static void drawrow(DEstruct, int);
131
static void eventloop(DEstruct);
132
static void find_coords(DEstruct, int, int, int*, int*);
133
static int  findcell(DEstruct);
32432 ripley 134
static char *GetCharP(DEEvent*);
13974 hornik 135
static KeySym GetKey(DEEvent*);
41835 ripley 136
static void handlechar(DEstruct, char *);
40759 ripley 137
static void highlightrect(DEstruct);
41831 rgentlem 138
static Rboolean initwin(DEstruct, const char *);
40759 ripley 139
static void jumppage(DEstruct, DE_DIRECTION);
140
static void jumpwin(DEstruct, int, int);
141
static void pastecell(DEstruct, int, int);
142
static void popdownmenu(DEstruct);
143
static void popupmenu(DEstruct, int, int, int, int);
144
static void printlabs(DEstruct);
145
static void printrect(DEstruct, int, int);
41831 rgentlem 146
static void printstring(DEstruct, const char*, int, int, int, int);
40759 ripley 147
static void printelt(DEstruct, SEXP, int, int, int);
13974 hornik 148
static void RefreshKeyboardMapping(DEEvent*);
40759 ripley 149
static void cell_cursor_init(DEstruct);
32424 ripley 150
 
13974 hornik 151
/* Functions to hide Xlib calls */
152
static void bell(void);
40759 ripley 153
static void cleararea(DEstruct, int, int, int, int);
154
static void copyH(DEstruct, int, int, int);
155
static void copyarea(DEstruct, int, int, int, int);
156
static void doConfigure(DEstruct, DEEvent *ioevent);
157
static void drawrectangle(DEstruct, int, int, int, int, int, int);
158
static void drawtext(DEstruct, int, int, char*, int);
13974 hornik 159
static void RefreshKeyboardMapping(DEEvent *ioevent);
40759 ripley 160
static void Rsync(DEstruct);
41831 rgentlem 161
static int textwidth(DEstruct, const char*, int);
13974 hornik 162
static int WhichEvent(DEEvent ioevent);
163
 
40756 ripley 164
static void R_ProcessX11Events(void *data);
165
 
166
 
41831 rgentlem 167
static const char *get_col_name(DEstruct, int col);
40759 ripley 168
static int  get_col_width(DEstruct, int col);
169
static CellType get_col_type(DEstruct, int col);
170
static void calc_pre_edit_pos(DEstruct DE);
34639 ripley 171
static int last_wchar_bytes(char *);
40756 ripley 172
static SEXP ssNewVector(SEXPTYPE, int);
24274 ripley 173
static SEXP ssNA_STRING;
13974 hornik 174
 
32424 ripley 175
 
40756 ripley 176
/* only used in the editor */
177
static Atom _XA_WM_PROTOCOLS = 0;
178
static Window menuwindow, menupanes[4];
179
static Rboolean CellModified;
180
static int box_coords[6];
181
static int currentexp;                  /* whether an cell is active */
13974 hornik 182
static int ndecimal;                    /* count decimal points */
183
static int ne;                          /* count exponents */
184
static int nneg;			/* indicate whether its a negative */
185
static int clength;                     /* number of characters currently entered */
40747 ripley 186
static int inSpecial;
34639 ripley 187
 
188
#define BOOSTED_BUF_SIZE    201
189
static char buf[BOOSTED_BUF_SIZE];	/* boosted to allow for MBCS */
13974 hornik 190
static char *bufp;
32424 ripley 191
static char copycontents[sizeof(buf)+1] ;
13974 hornik 192
 
40756 ripley 193
/* The next few and used only for the editor in MBCS locales */
34639 ripley 194
static Status           status;
46169 ripley 195
static XFontSet         font_set = NULL;
32424 ripley 196
static XFontStruct	**fs_list;
197
static int		font_set_cnt;
44345 ripley 198
static char             fontset_name[]="-*-fixed-medium-r-*-*-*-120-*-*-*-*-*-*";
32518 ripley 199
static XIM		ioim;
34639 ripley 200
static XIMStyle         ioim_style;
201
static XIMStyles        *ioim_styles;
202
 
203
/*
204
 * XIM:
205
 * OverTheSpot XIMPreeditPosition | XIMStatusArea;
206
 * OffTheSpot  XIMPreeditArea     | XIMStatusArea;
207
 * Root        XIMPreeditNothing  | XIMStatusNothing;
208
 */
40756 ripley 209
static XIMStyle preedit_styles[] = {
210
    XIMPreeditPosition,
211
    XIMPreeditArea,
212
    XIMPreeditNothing,
213
    XIMPreeditNone,
214
    (XIMStyle)NULL,
34639 ripley 215
};
40756 ripley 216
static XIMStyle status_styles[] = {
217
    XIMStatusArea,
218
    XIMStatusNothing,
219
    XIMStatusNone,
220
    (XIMStyle)NULL,
34639 ripley 221
};
46169 ripley 222
static XIC ioic = NULL;
13974 hornik 223
 
224
#ifndef max
225
#define max(a, b) (((a)>(b))?(a):(b))
226
#endif
227
#ifndef min
228
#define min(a, b) (((a)<(b))?(a):(b))
229
#endif
40759 ripley 230
#define BOXW(x) (min(((x<100 && DE->nboxchars==0)?DE->boxw[x]:DE->box_w), DE->fullwindowWidth-DE->boxw[0]-2*DE->bwidth-2))
13974 hornik 231
 
24274 ripley 232
/*
233
  Underlying assumptions (for this version R >= 1.8.0)
13974 hornik 234
 
24274 ripley 235
  The data are stored in a list `work', with unused columns having
236
  NULL entries.  The names for the list are in `names', which should
32424 ripley 237
  have a name for all displayable columns (up to xmaxused).
24274 ripley 238
  The *used* lengths of the columns are in `lens': this needs only be
239
  set for non-NULL columns.
240
 
32424 ripley 241
  If the list was originally length(0), that should work with
32432 ripley 242
 
24274 ripley 243
 
244
  All row and col numbers are 1-based.
245
 
246
  BDR May 2003
247
 */
248
 
13974 hornik 249
/*
250
   The spreadsheet function returns a list of vectors. The types of
251
   these vectors can be specified by the user as can their names. It
252
   the names are specified they are set during initialization. The
253
   user can change these via a menu interface, they can also change
254
   the type.
255
 
256
   The vectors are created too long and if they need to be increased
257
   this is done by using the next higher power of 2. They start 100
32360 ripley 258
   long.  Vectors are initialized to NA when they are created so that
40759 ripley 259
   NA is returned for any cell that was not set by the user.  We use
40747 ripley 260
   a special type of NA to distinguish this from user-supplied NAs.
13974 hornik 261
 
24733 ripley 262
   In Macintosh we needed to call the main event loop to get
13974 hornik 263
   events. This ensures that the spreadsheet interacts well with the
264
   other windows. Under X windows we let the window manager handle
265
   those sorts of details.
266
 
267
 */
268
 
269
static char *menu_label[] =
270
{
34639 ripley 271
    " Real",
272
    " Character",
273
    "Change Name ",
13974 hornik 274
};
275
 
276
/*
277
   ssNewVector is just an interface to allocVector but it lets us
278
   set the fields to NA. We need to have a special NA for reals and
279
   strings so that we can differentiate between uninitialized elements
40747 ripley 280
   in the vectors and user supplied NA's; hence ssNA_STRING
13974 hornik 281
 */
282
 
283
static SEXP ssNewVector(SEXPTYPE type, int vlen)
284
{
285
    SEXP tvec;
286
    int j;
287
 
288
    tvec = allocVector(type, vlen);
289
    for (j = 0; j < vlen; j++)
290
	if (type == REALSXP)
40747 ripley 291
	    REAL(tvec)[j] = NA_REAL;
13974 hornik 292
	else if (type == STRSXP)
40747 ripley 293
	    SET_STRING_ELT(tvec, j, ssNA_STRING);
13974 hornik 294
    return (tvec);
295
}
296
 
14561 luke 297
static void closewin_cend(void *data)
298
{
40759 ripley 299
    DEstruct DE = (DEstruct) data;
300
    closewin(DE);
14561 luke 301
}
302
 
44345 ripley 303
SEXP in_RX11_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho)
13974 hornik 304
{
24274 ripley 305
    SEXP colmodes, tnames, tvec, tvec2, work2;
13974 hornik 306
    SEXPTYPE type;
24274 ripley 307
    int i, j, cnt, len, nprotect;
13974 hornik 308
    RCNTXT cntxt;
24274 ripley 309
    char clab[25];
40754 ripley 310
    char *title = "R Data Editor";
40759 ripley 311
    destruct DE1;
312
    DEstruct DE = &DE1;
13974 hornik 313
 
314
    nprotect = 0;/* count the PROTECT()s */
40759 ripley 315
    PROTECT_WITH_INDEX(DE->work = duplicate(CAR(args)), &DE->wpi); nprotect++;
24274 ripley 316
    colmodes = CADR(args);
40759 ripley 317
    tnames = getAttrib(DE->work, R_NamesSymbol);
13974 hornik 318
 
40759 ripley 319
    if (TYPEOF(DE->work) != VECSXP || TYPEOF(colmodes) != VECSXP)
13974 hornik 320
	errorcall(call, "invalid argument");
321
 
24274 ripley 322
    /* initialize the constants */
13974 hornik 323
 
324
    bufp = buf;
325
    ne = 0;
326
    currentexp = 0;
327
    nneg = 0;
328
    ndecimal = 0;
329
    clength = 0;
40747 ripley 330
    inSpecial = 0;
40759 ripley 331
    DE->ccol = 1;
332
    DE->crow = 1;
333
    DE->colmin = 1;
334
    DE->rowmin = 1;
40747 ripley 335
    PROTECT(ssNA_STRING = duplicate(NA_STRING));
336
    nprotect++;
40759 ripley 337
    DE->bwidth = 5;
338
    DE->hht = 30;
339
    DE->isEditor = TRUE;
13974 hornik 340
 
24274 ripley 341
    /* setup work, names, lens  */
40759 ripley 342
    DE->xmaxused = length(DE->work); DE->ymaxused = 0;
343
    PROTECT_WITH_INDEX(DE->lens = allocVector(INTSXP, DE->xmaxused), &DE->lpi);
24274 ripley 344
    nprotect++;
13974 hornik 345
 
24274 ripley 346
    if (isNull(tnames)) {
40759 ripley 347
	PROTECT_WITH_INDEX(DE->names = allocVector(STRSXP, DE->xmaxused),
348
			   &DE->npi);
349
	for(i = 0; i < DE->xmaxused; i++) {
24274 ripley 350
	    sprintf(clab, "var%d", i);
40759 ripley 351
	    SET_STRING_ELT(DE->names, i, mkChar(clab));
13974 hornik 352
	}
24274 ripley 353
    } else
40759 ripley 354
	PROTECT_WITH_INDEX(DE->names = duplicate(tnames), &DE->npi);
24274 ripley 355
    nprotect++;
40759 ripley 356
    for (i = 0; i < DE->xmaxused; i++) {
357
	int len = LENGTH(VECTOR_ELT(DE->work, i));
358
	INTEGER(DE->lens)[i] = len;
359
	DE->ymaxused = max(len, DE->ymaxused);
360
	type = TYPEOF(VECTOR_ELT(DE->work, i));
25365 ripley 361
	if (LENGTH(colmodes) > 0 && !isNull(VECTOR_ELT(colmodes, i)))
24274 ripley 362
	    type = str2type(CHAR(STRING_ELT(VECTOR_ELT(colmodes, i), 0)));
363
	if (type != STRSXP) type = REALSXP;
40759 ripley 364
	if (isNull(VECTOR_ELT(DE->work, i))) {
24274 ripley 365
	    if (type == NILSXP) type = REALSXP;
40759 ripley 366
	    SET_VECTOR_ELT(DE->work, i, ssNewVector(type, 100));
367
	} else if (!isVector(VECTOR_ELT(DE->work, i)))
24274 ripley 368
	    errorcall(call, "invalid type for value");
369
	else {
40759 ripley 370
	    if (TYPEOF(VECTOR_ELT(DE->work, i)) != type)
371
		SET_VECTOR_ELT(DE->work, i,
372
			       coerceVector(VECTOR_ELT(DE->work, i), type));
24274 ripley 373
	}
13974 hornik 374
    }
375
 
376
 
377
    /* start up the window, more initializing in here */
40759 ripley 378
    if (initwin(DE, title))
13974 hornik 379
	errorcall(call, "invalid device");
380
 
381
    /* set up a context which will close the window if there is an error */
35450 murdoch 382
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
23463 luke 383
		 R_NilValue, R_NilValue);
14561 luke 384
    cntxt.cend = &closewin_cend;
40759 ripley 385
    cntxt.cenddata = (void *) DE;
13974 hornik 386
 
40759 ripley 387
    highlightrect(DE);
13974 hornik 388
 
40759 ripley 389
    cell_cursor_init(DE);
34639 ripley 390
 
40759 ripley 391
    eventloop(DE);
13974 hornik 392
 
393
    endcontext(&cntxt);
40759 ripley 394
    closewin(DE);
395
    if(nView == 0) {
46169 ripley 396
	if(fdView >= 0) { /* might be open after viewers, but unlikely */
397
	    removeInputHandler(&R_InputHandlers,
398
			       getInputHandler(R_InputHandlers,fdView));
399
	    fdView = -1;
400
	}
401
	if(font_set) {
402
	    XFreeFontSet(iodisplay, font_set);
403
	    font_set = NULL;
404
	}
40759 ripley 405
	XCloseDisplay(iodisplay);
406
	iodisplay = NULL;
407
    }
13974 hornik 408
 
409
    /* drop out unused columns */
40759 ripley 410
    for(i = 0, cnt = 0; i < DE->xmaxused; i++)
411
	if(!isNull(VECTOR_ELT(DE->work, i))) cnt++;
412
    if (cnt < DE->xmaxused) {
24274 ripley 413
	PROTECT(work2 = allocVector(VECSXP, cnt)); nprotect++;
40759 ripley 414
	for(i = 0, j = 0; i < DE->xmaxused; i++) {
415
	    if(!isNull(VECTOR_ELT(DE->work, i))) {
416
		SET_VECTOR_ELT(work2, j, VECTOR_ELT(DE->work, i));
417
		INTEGER(DE->lens)[j] = INTEGER(DE->lens)[i];
418
		SET_STRING_ELT(DE->names, j, STRING_ELT(DE->names, i));
24274 ripley 419
		j++;
13974 hornik 420
	    }
421
	}
40759 ripley 422
	REPROTECT(DE->names = lengthgets(DE->names, cnt), DE->npi);
423
    } else work2 = DE->work;
13974 hornik 424
 
24274 ripley 425
    for (i = 0; i < LENGTH(work2); i++) {
40759 ripley 426
	len = INTEGER(DE->lens)[i];
24274 ripley 427
	tvec = VECTOR_ELT(work2, i);
428
	if (LENGTH(tvec) != len) {
429
	    tvec2 = ssNewVector(TYPEOF(tvec), len);
430
	    for (j = 0; j < len; j++) {
431
		if (TYPEOF(tvec) == REALSXP) {
432
			REAL(tvec2)[j] = REAL(tvec)[j];
433
		} else if (TYPEOF(tvec) == STRSXP) {
40747 ripley 434
		    if (STRING_ELT(tvec, j) != ssNA_STRING)
24274 ripley 435
			SET_STRING_ELT(tvec2, j, STRING_ELT(tvec, j));
13974 hornik 436
		    else
437
			SET_STRING_ELT(tvec2, j, NA_STRING);
438
		} else
439
		    error("dataentry: internal memory problem");
24274 ripley 440
	    }
441
	    SET_VECTOR_ELT(work2, i, tvec2);
13974 hornik 442
	}
443
    }
444
 
40759 ripley 445
    setAttrib(work2, R_NamesSymbol, DE->names);
13974 hornik 446
    UNPROTECT(nprotect);
24274 ripley 447
    return work2;
13974 hornik 448
}
449
 
40759 ripley 450
static void dv_closewin_cend(void *data)
451
{
452
    DEstruct DE = (DEstruct) data;
453
    R_ReleaseObject(DE->lens);
454
    R_ReleaseObject(DE->work);
455
    closewin(DE);
456
    free(DE);
457
    nView--;
458
}
459
 
40754 ripley 460
SEXP in_R_X11_dataviewer(SEXP call, SEXP op, SEXP args, SEXP rho)
461
{
40756 ripley 462
    SEXP stitle;
40754 ripley 463
    SEXPTYPE type;
464
    int i, nprotect;
465
    RCNTXT cntxt;
40759 ripley 466
    DEstruct DE = (DEstruct) malloc(sizeof(destruct));
13974 hornik 467
 
40759 ripley 468
    nView++;
469
 
40754 ripley 470
    nprotect = 0;/* count the PROTECT()s */
40759 ripley 471
    DE->work = CAR(args);
472
    DE->names = getAttrib(DE->work, R_NamesSymbol);
40754 ripley 473
 
40759 ripley 474
    if (TYPEOF(DE->work) != VECSXP)
40754 ripley 475
	errorcall(call, "invalid argument");
476
    stitle = CADR(args);
477
    if (!isString(stitle) || LENGTH(stitle) != 1)
478
	errorcall(call, "invalid argument");
479
 
480
    /* initialize the constants */
481
 
482
    bufp = buf;
483
    ne = 0;
484
    currentexp = 0;
485
    nneg = 0;
486
    ndecimal = 0;
487
    clength = 0;
488
    inSpecial = 0;
40759 ripley 489
    DE->ccol = 1;
490
    DE->crow = 1;
491
    DE->colmin = 1;
492
    DE->rowmin = 1;
493
    DE->bwidth = 5;
494
    DE->hht = 10;
495
    DE->isEditor = FALSE;
40754 ripley 496
 
497
    /* setup work, names, lens  */
40759 ripley 498
    DE->xmaxused = length(DE->work); DE->ymaxused = 0;
499
    PROTECT_WITH_INDEX(DE->lens = allocVector(INTSXP, DE->xmaxused), &DE->lpi);
40754 ripley 500
    nprotect++;
501
 
40759 ripley 502
    for (i = 0; i < DE->xmaxused; i++) {
503
	int len = LENGTH(VECTOR_ELT(DE->work, i));
504
	INTEGER(DE->lens)[i] = len;
505
	DE->ymaxused = max(len, DE->ymaxused);
506
	type = TYPEOF(VECTOR_ELT(DE->work, i));
40756 ripley 507
	if (type != STRSXP && type != REALSXP)
508
	    errorcall(call, "invalid argument");
40754 ripley 509
    }
510
 
511
 
512
    /* start up the window, more initializing in here */
40759 ripley 513
    if (initwin(DE, CHAR(STRING_ELT(stitle, 0))))
40754 ripley 514
	errorcall(call, "invalid device");
515
 
516
    /* set up a context which will close the window if there is an error */
517
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
518
		 R_NilValue, R_NilValue);
40759 ripley 519
    cntxt.cend = &dv_closewin_cend;
520
    cntxt.cenddata = (void *) DE;
40754 ripley 521
 
40759 ripley 522
    highlightrect(DE);
40754 ripley 523
 
40759 ripley 524
    cell_cursor_init(DE);
40754 ripley 525
 
40759 ripley 526
    if(fdView < 0) {
527
	fdView = ConnectionNumber(iodisplay);
528
	addInputHandler(R_InputHandlers, fdView,
529
			R_ProcessX11Events, XActivity);
530
    }
40754 ripley 531
 
40759 ripley 532
    drawwindow(DE);
40756 ripley 533
 
40759 ripley 534
    R_PreserveObject(DE->work); /* also preserves names */
535
    R_PreserveObject(DE->lens);
536
    UNPROTECT(nprotect);
40754 ripley 537
    return R_NilValue;
538
}
539
 
13974 hornik 540
/* Window Drawing Routines */
541
 
40759 ripley 542
static void setcellwidths(DEstruct DE)
13974 hornik 543
{
544
    int i, w, dw;
545
 
40759 ripley 546
    DE->windowWidth = w = 2*DE->bwidth + DE->boxw[0] + BOXW(DE->colmin);
547
    DE->nwide = 2;
13974 hornik 548
    for (i = 2; i < 100; i++) { /* 100 on-screen columns cannot occur */
40759 ripley 549
	dw = BOXW(i + DE->colmin - 1);
550
	if((w += dw) > DE->fullwindowWidth ||
551
	   (!DE->isEditor && i > DE->xmaxused - DE->colmin + 1)) {
552
	    DE->nwide = i;
553
	    DE->windowWidth = w - dw;
13974 hornik 554
	    break;
555
	}
556
    }
557
}
558
 
40759 ripley 559
static void drawwindow(DEstruct DE)
13974 hornik 560
{
561
    int i, st;
562
    XWindowAttributes attribs;
563
 
564
    /* if there is an active cell enter the data in it */
34639 ripley 565
    /*
566
     * case colname input Expose not use.
567
     * closerect();
568
     */
13974 hornik 569
 
570
    /* now set up the window with the new dimensions */
40759 ripley 571
    XGetWindowAttributes(iodisplay, DE->iowindow, &attribs);
572
    DE->bwidth = attribs.border_width;
573
    DE->fullwindowWidth = attribs.width;
574
    DE->fullwindowHeight = attribs.height;
575
    setcellwidths(DE);
576
    DE->nhigh = (DE->fullwindowHeight - 2 * DE->bwidth - DE->hht) / DE->box_h;
577
    DE->windowHeight = DE->nhigh * DE->box_h + 2 * DE->bwidth;
13974 hornik 578
 
40759 ripley 579
    clearwindow(DE);
13974 hornik 580
 
581
 
40759 ripley 582
    for (i = 1; i < DE->nhigh; i++)
583
	drawrectangle(DE, 0, DE->hht + i * DE->box_h, DE->boxw[0], DE->box_h,
584
		      1, 1);
13974 hornik 585
     /* so row 0 and col 0 are reserved for labels */
40759 ripley 586
    DE->colmax = DE->colmin + (DE->nwide - 2);
587
    DE->rowmax = DE->rowmin + (DE->nhigh - 2);
588
    printlabs(DE);
589
    for (i = DE->colmin; i <= DE->colmax; i++) drawcol(DE, i);
13974 hornik 590
 
40759 ripley 591
    if(DE->isEditor) {
40755 ripley 592
	/* draw the quit etc boxes */
13974 hornik 593
 
40759 ripley 594
	i = textwidth(DE, "Quit", 4);
595
	box_coords[0] = st = DE->fullwindowWidth - 6 - DE->bwidth;
40755 ripley 596
	box_coords[1] = st - i;
40759 ripley 597
	drawrectangle(DE, st - i, 3, i + 4, DE->hht - 6, 1, 1);
598
	drawtext(DE, st + 2 - i, DE->hht - 7, "Quit", 4);
13974 hornik 599
 
40755 ripley 600
	box_coords[4] = st = st - 5*i;
40759 ripley 601
	i = textwidth(DE, "Paste", 5);
40755 ripley 602
	box_coords[5] = st - i;
40759 ripley 603
	drawrectangle(DE, st - i, 3, i + 4, DE->hht - 6, 1, 1);
604
	drawtext(DE, st + 2 - i, DE->hht - 7, "Paste", 5);
13974 hornik 605
 
40755 ripley 606
	box_coords[2] = st = st - 2*i;
40759 ripley 607
	i = textwidth(DE, "Copy", 4);
40755 ripley 608
	box_coords[3] = st - i;
40759 ripley 609
	drawrectangle(DE, st - i, 3, i + 4, DE->hht - 6, 1, 1);
610
	drawtext(DE, st + 2 - i, DE->hht - 7, "Copy", 4);
40755 ripley 611
    }
13974 hornik 612
 
40759 ripley 613
    highlightrect(DE);
13974 hornik 614
 
40759 ripley 615
    Rsync(DE);
616
 
13974 hornik 617
}
618
 
40759 ripley 619
static void doHscroll(DEstruct DE, int oldcol)
13974 hornik 620
{
621
    int i, dw;
40759 ripley 622
    int oldnwide = DE->nwide, oldwindowWidth = DE->windowWidth;
13974 hornik 623
 
624
    /* horizontal re-position */
40759 ripley 625
    setcellwidths(DE);
626
    DE->colmax = DE->colmin + (DE->nwide - 2);
627
    if (oldcol < DE->colmin) { /* drop oldcol...colmin - 1 */
628
	dw = DE->boxw[0];
629
	for (i = oldcol; i < DE->colmin; i++) dw += BOXW(i);
630
	copyH(DE, dw, DE->boxw[0], oldwindowWidth - dw + 1);
13974 hornik 631
	dw = oldwindowWidth - BOXW(oldcol) + 1;
40759 ripley 632
	cleararea(DE, dw, DE->hht, DE->fullwindowWidth-dw,
633
		  DE->fullwindowHeight);
13974 hornik 634
	/* oldnwide includes the row labels */
40759 ripley 635
	for (i = oldcol+oldnwide-1; i <= DE->colmax; i++) drawcol(DE, i);
13974 hornik 636
    } else {
637
	/* move one or more cols left */
40759 ripley 638
	dw = BOXW(DE->colmin);
639
	copyH(DE, DE->boxw[0], DE->boxw[0] + dw, DE->windowWidth - dw + 1);
640
	dw = DE->windowWidth + 1;
641
	cleararea(DE, dw, DE->hht, DE->fullwindowWidth-dw,
642
		  DE->fullwindowHeight);
643
	drawcol(DE, DE->colmin);
13974 hornik 644
    }
645
 
40759 ripley 646
    highlightrect(DE);
647
    cell_cursor_init(DE);
13974 hornik 648
 
40759 ripley 649
    Rsync(DE);
13974 hornik 650
}
651
 
652
/* find_coords finds the coordinates of the upper left corner of the
653
   given cell on the screen: row and col are on-screen coords */
654
 
40759 ripley 655
static void find_coords(DEstruct DE,
656
			int row, int col, int *xcoord, int *ycoord)
13974 hornik 657
{
658
    int i, w;
40759 ripley 659
    w = DE->bwidth;
660
    if (col > 0) w += DE->boxw[0];
661
    for(i = 1; i < col; i ++) w += BOXW(i + DE->colmin - 1);
13974 hornik 662
    *xcoord = w;
40759 ripley 663
    *ycoord = DE->bwidth + DE->hht + DE->box_h * row;
13974 hornik 664
}
665
 
666
/* draw the window with the top left box at column wcol and row wrow */
667
 
40759 ripley 668
static void jumpwin(DEstruct DE, int wcol, int wrow)
13974 hornik 669
{
670
    if (wcol < 0 || wrow < 0) {
671
	bell();
672
	return;
673
    }
40759 ripley 674
    closerect(DE);
675
    if (DE->colmin != wcol || DE->rowmin != wrow) {
676
	DE->colmin = wcol;
677
	DE->rowmin = wrow;
678
	closerect(DE);
679
	drawwindow(DE);
680
    } else highlightrect(DE);
13974 hornik 681
}
682
 
40759 ripley 683
static void advancerect(DEstruct DE, DE_DIRECTION which)
13974 hornik 684
{
685
 
686
    /* if we are in the header, changing a name then only down is
687
       allowed */
40759 ripley 688
    if (DE->crow < 1 && which != DOWN) {
13974 hornik 689
	bell();
690
	return;
691
    }
692
 
40759 ripley 693
    closerect(DE);
13974 hornik 694
 
695
    switch (which) {
696
    case UP:
40759 ripley 697
	if (DE->crow == 1) {
698
	    if (DE->rowmin == 1)
13974 hornik 699
		bell();
700
	    else
40759 ripley 701
		jumppage(DE, UP);
13974 hornik 702
	} else
40759 ripley 703
	    DE->crow--;
13974 hornik 704
	break;
705
    case DOWN:
40759 ripley 706
	if (!DE->isEditor && DE->crow+DE->rowmin > DE->ymaxused) {
40755 ripley 707
	    bell();
708
	    break;
709
	}
40759 ripley 710
	if (DE->crow == (DE->nhigh - 1))
711
	    jumppage(DE, DOWN);
13974 hornik 712
	else
40759 ripley 713
	    DE->crow++;
13974 hornik 714
	break;
715
    case RIGHT:
40759 ripley 716
	if (!DE->isEditor && DE->ccol+DE->colmin > DE->xmaxused) {
40755 ripley 717
	    bell();
718
	    break;
719
	}
40759 ripley 720
	if (DE->ccol == (DE->nwide - 1))
721
	    jumppage(DE, RIGHT);
13974 hornik 722
	else
40759 ripley 723
	    DE->ccol++;
13974 hornik 724
	break;
725
    case LEFT:
40759 ripley 726
	if (DE->ccol == 1) {
727
	    if (DE->colmin == 1)
13974 hornik 728
		bell();
729
	    else
40759 ripley 730
		jumppage(DE, LEFT);
13974 hornik 731
	} else
40759 ripley 732
	    DE->ccol--;
13974 hornik 733
	break;
734
    default:
735
	UNIMPLEMENTED("advancerect");
736
    }
737
 
40759 ripley 738
    highlightrect(DE);
34639 ripley 739
 
40759 ripley 740
    cell_cursor_init(DE);
13974 hornik 741
}
742
 
40759 ripley 743
static void cell_cursor_init(DEstruct DE)
34639 ripley 744
{
40759 ripley 745
    int i, whichrow = DE->crow + DE->rowmin - 1,
746
	whichcol = DE->ccol + DE->colmin -1;
34639 ripley 747
    SEXP tmp;
748
 
749
    memset(buf,0,sizeof(buf));
750
 
40759 ripley 751
    if (DE->crow == 0 ){
34639 ripley 752
	strncpy(buf,
40759 ripley 753
		get_col_name(DE, whichcol),
34639 ripley 754
		BOOSTED_BUF_SIZE-1);
755
    } else {
40759 ripley 756
	if (length(DE->work) >= whichcol) {
757
	    tmp = VECTOR_ELT(DE->work, whichcol - 1);
34639 ripley 758
	    if (tmp != R_NilValue &&
759
		(i = whichrow - 1) < LENGTH(tmp) ) {
54049 ripley 760
		PrintDefaults();
34639 ripley 761
		if (TYPEOF(tmp) == REALSXP) {
40747 ripley 762
		    strncpy(buf, EncodeElement(tmp, i, 0, '.'),
763
			    BOOSTED_BUF_SIZE-1);
34639 ripley 764
		} else if (TYPEOF(tmp) == STRSXP) {
40747 ripley 765
		    if (STRING_ELT(tmp, i) != ssNA_STRING)
34639 ripley 766
			strncpy(buf, EncodeElement(tmp, i, 0, '.'),
767
				BOOSTED_BUF_SIZE-1);
768
		}
769
	    }
770
	}
771
    }
772
    buf[BOOSTED_BUF_SIZE-1] = '\0';
59764 ripley 773
    clength = (int) strlen(buf);
34639 ripley 774
    bufp = buf + clength;
775
}
776
 
41831 rgentlem 777
static const char *get_col_name(DEstruct DE, int col)
13974 hornik 778
{
24274 ripley 779
    static char clab[25];
41831 rgentlem 780
    int nwrote;
40759 ripley 781
    if (col <= DE->xmaxused) {
24274 ripley 782
	/* don't use NA labels */
40759 ripley 783
	SEXP tmp = STRING_ELT(DE->names, col - 1);
24274 ripley 784
	if(tmp != NA_STRING) return(CHAR(tmp));
13974 hornik 785
    }
41831 rgentlem 786
    nwrote = snprintf(clab, 25, "var%d", col);
787
    if (nwrote >= 25)
45475 ripley 788
	error("get_col_name: column number too big to stringify");
41831 rgentlem 789
    return (const char *)clab;
13974 hornik 790
}
791
 
40759 ripley 792
static int get_col_width(DEstruct DE, int col)
13974 hornik 793
{
794
    int i, w = 0, w1;
41831 rgentlem 795
    const char *strp;
24274 ripley 796
    SEXP tmp, lab;
13974 hornik 797
 
40759 ripley 798
    if (DE->nboxchars > 0) return DE->box_w;
799
    if (col <= DE->xmaxused) {
800
	tmp = VECTOR_ELT(DE->work, col - 1);
801
	if (isNull(tmp)) return DE->box_w;
24274 ripley 802
	/* don't use NA labels */
40759 ripley 803
	lab = STRING_ELT(DE->names, col - 1);
24274 ripley 804
	if(lab != NA_STRING) strp = CHAR(lab); else strp = "var12";
54049 ripley 805
	PrintDefaults();
34639 ripley 806
 
59764 ripley 807
	w = textwidth(DE, strp, (int) strlen(strp));
40759 ripley 808
	for (i = 0; i < INTEGER(DE->lens)[col - 1]; i++) {
34294 ripley 809
	    strp = EncodeElement(tmp, i, 0, '.');
59764 ripley 810
	    w1 = textwidth(DE, strp, (int) strlen(strp));
13974 hornik 811
	    if (w1 > w) w = w1;
812
	}
59764 ripley 813
	if(w < 0.5*DE->box_w) w = (int) (0.5*DE->box_w);
814
	if(w < 0.8*DE->box_w) w+= (int) (0.1*DE->box_w);
13974 hornik 815
	if(w > 600) w = 600;
816
	return w+8;
817
    }
40759 ripley 818
    return DE->box_w;
13974 hornik 819
}
820
 
40759 ripley 821
static CellType get_col_type(DEstruct DE, int col)
13974 hornik 822
{
823
    SEXP tmp;
824
    CellType res = UNKNOWNN;
825
 
40759 ripley 826
    if (col <= DE->xmaxused) {
827
	tmp = VECTOR_ELT(DE->work, col - 1);
13974 hornik 828
	if(TYPEOF(tmp) == REALSXP) res = NUMERIC;
829
	if(TYPEOF(tmp) == STRSXP) res = CHARACTER;
830
    }
831
    return res;
832
}
833
 
834
 
835
/* whichcol is absolute col no, col is position on screen */
40759 ripley 836
static void drawcol(DEstruct DE, int whichcol)
13974 hornik 837
{
40759 ripley 838
    int i, src_x, src_y, len, col = whichcol - DE->colmin + 1,
839
	bw = BOXW(whichcol);
41831 rgentlem 840
    const char *clab;
13974 hornik 841
    SEXP tmp;
842
 
40759 ripley 843
    find_coords(DE, 0, col, &src_x, &src_y);
844
    cleararea(DE, src_x, src_y, bw, DE->windowHeight);
845
    for (i = 0; i < DE->nhigh; i++)
846
	drawrectangle(DE, src_x, DE->hht + i * DE->box_h, bw, DE->box_h, 1, 1);
13974 hornik 847
 
848
    /* now fill it in if it is active */
40759 ripley 849
    clab = get_col_name(DE, whichcol);
59764 ripley 850
    printstring(DE, clab, (int) strlen(clab), 0, col, 0);
13974 hornik 851
 
40759 ripley 852
   if (DE->xmaxused >= whichcol) {
853
	tmp = VECTOR_ELT(DE->work, whichcol - 1);
24274 ripley 854
	if (!isNull(tmp)) {
40759 ripley 855
	    len = min(DE->rowmax, INTEGER(DE->lens)[whichcol - 1]);
856
	    for (i = (DE->rowmin - 1); i < len; i++)
857
		printelt(DE, tmp, i, i - DE->rowmin + 2, col);
13974 hornik 858
	}
859
    }
40759 ripley 860
    Rsync(DE);
13974 hornik 861
}
862
 
863
 
864
/* whichrow is absolute row no */
40759 ripley 865
static void drawrow(DEstruct DE, int whichrow)
13974 hornik 866
{
40759 ripley 867
    int i, src_x, src_y, row = whichrow - DE->rowmin + 1, w;
13974 hornik 868
    char rlab[15];
869
    SEXP tvec;
870
 
40759 ripley 871
    find_coords(DE, row, 0, &src_x, &src_y);
872
    cleararea(DE, src_x, src_y, DE->windowWidth, DE->box_h);
873
    drawrectangle(DE, src_x, src_y, DE->boxw[0], DE->box_h, 1, 1);
13974 hornik 874
 
40759 ripley 875
    sprintf(rlab, DE->labform, whichrow);
59764 ripley 876
    printstring(DE, rlab, (int)strlen(rlab), row, 0, 0);
13974 hornik 877
 
40759 ripley 878
    w = DE->bwidth + DE->boxw[0];
879
    for (i = DE->colmin; i <= DE->colmax; i++) {
880
	drawrectangle(DE, w, src_y, BOXW(i), DE->box_h, 1, 1);
13974 hornik 881
	w += BOXW(i);
882
    }
883
 
40759 ripley 884
    for (i = DE->colmin; i <= DE->colmax; i++) {
885
	if (i > DE->xmaxused) break;
886
	if (!isNull(tvec = VECTOR_ELT(DE->work, i - 1)))
887
	    if (whichrow <= INTEGER(DE->lens)[i - 1])
888
		printelt(DE, tvec, whichrow - 1, row, i - DE->colmin + 1);
13974 hornik 889
    }
890
 
40759 ripley 891
    Rsync(DE);
13974 hornik 892
}
893
 
894
/* printelt: print the correct value from vector[vrow] into the
895
   spreadsheet in row ssrow and col sscol */
896
 
897
/* WARNING: This has no check that you're not beyond the end of the
898
   vector. Caller must check. */
899
 
40759 ripley 900
static void printelt(DEstruct DE, SEXP invec, int vrow, int ssrow, int sscol)
13974 hornik 901
{
41861 ripley 902
    const char *strp;
54049 ripley 903
    PrintDefaults();
13974 hornik 904
    if (TYPEOF(invec) == REALSXP) {
40747 ripley 905
	strp = EncodeElement(invec, vrow, 0, '.');
59764 ripley 906
	printstring(DE ,strp, (int) strlen(strp), ssrow, sscol, 0);
13974 hornik 907
    }
908
    else if (TYPEOF(invec) == STRSXP) {
40747 ripley 909
	if (STRING_ELT(invec, vrow) != ssNA_STRING) {
34294 ripley 910
	    strp = EncodeElement(invec, vrow, 0, '.');
59764 ripley 911
	    printstring(DE ,strp, (int) strlen(strp), ssrow, sscol, 0);
13974 hornik 912
	}
913
    }
914
    else
915
	error("dataentry: internal memory error");
916
}
917
 
918
 
40759 ripley 919
static void drawelt(DEstruct DE, int whichrow, int whichcol)
13974 hornik 920
{
921
    int i;
41831 rgentlem 922
    const char *clab;
13974 hornik 923
    SEXP tmp;
924
 
925
    if (whichrow == 0) {
40759 ripley 926
	clab = get_col_name(DE, whichcol + DE->colmin - 1);
59764 ripley 927
	printstring(DE ,clab, (int) strlen(clab), 0, whichcol, 0);
13974 hornik 928
    } else {
40759 ripley 929
	if (DE->xmaxused >= whichcol + DE->colmin - 1) {
930
	    tmp = VECTOR_ELT(DE->work, whichcol + DE->colmin - 2);
931
	    if (!isNull(tmp) && (i = DE->rowmin + whichrow - 2) <
932
		INTEGER(DE->lens)[whichcol + DE->colmin - 2] )
933
		printelt(DE, tmp, i, whichrow, whichcol);
13974 hornik 934
	} else
40759 ripley 935
	    printstring(DE, "", 0, whichrow,  whichcol, 0);
13974 hornik 936
    }
937
 
40759 ripley 938
    Rsync(DE);
13974 hornik 939
}
940
 
40759 ripley 941
static void jumppage(DEstruct DE, DE_DIRECTION dir)
13974 hornik 942
{
943
    int i, w, oldcol, wcol;
944
 
945
    switch (dir) {
946
    case UP:
40759 ripley 947
	DE->rowmin--;
948
	DE->rowmax--;
949
	copyarea(DE, 0, DE->hht + DE->box_h, 0, DE->hht + 2 * DE->box_h);
950
	drawrow(DE, DE->rowmin);
13974 hornik 951
	break;
952
    case DOWN:
40759 ripley 953
	if (DE->rowmax >= 65535) return;
954
	DE->rowmin++;
955
	DE->rowmax++;
956
	copyarea(DE, 0, DE->hht + 2 * DE->box_h, 0, DE->hht + DE->box_h);
957
	drawrow(DE, DE->rowmax);
13974 hornik 958
	break;
959
    case LEFT:
40759 ripley 960
	DE->colmin--;
961
	doHscroll(DE, DE->colmin+1);
13974 hornik 962
	break;
963
    case RIGHT:
40759 ripley 964
	oldcol = DE->colmin;
965
	wcol = DE->colmin + DE->ccol + 1; /* column to be selected */
45475 ripley 966
	/* There may not be room to fit the next column in */
40759 ripley 967
	w = DE->fullwindowWidth - DE->boxw[0] - BOXW(DE->colmax + 1);
968
	for (i = DE->colmax; i >= oldcol; i--) {
13974 hornik 969
	    w -= BOXW(i);
970
	    if(w < 0) {
40759 ripley 971
		DE->colmin = i + 1;
13974 hornik 972
		break;
973
	    }
974
	}
40759 ripley 975
	DE->ccol = wcol - DE->colmin;
976
	doHscroll(DE, oldcol);
13974 hornik 977
	break;
978
    }
979
}
980
/* draw a rectangle, used to highlight/downlight the current box */
981
 
40759 ripley 982
static void printrect(DEstruct DE, int lwd, int fore)
13974 hornik 983
{
984
    int x, y;
40759 ripley 985
    find_coords(DE, DE->crow, DE->ccol, &x, &y);
986
    drawrectangle(DE, x + lwd - 1, y + lwd - 1,
987
		  BOXW(DE->ccol+DE->colmin-1) - lwd + 1,
988
		  DE->box_h - lwd + 1, lwd, fore);
989
    Rsync(DE);
13974 hornik 990
}
991
 
40759 ripley 992
static void downlightrect(DEstruct DE)
13974 hornik 993
{
40759 ripley 994
    printrect(DE, 2, 0);
995
    printrect(DE, 1, 1);
13974 hornik 996
}
997
 
40759 ripley 998
static void highlightrect(DEstruct DE)
13974 hornik 999
{
40759 ripley 1000
    printrect(DE, 2, 1);
13974 hornik 1001
}
1002
 
24274 ripley 1003
 
40759 ripley 1004
static Rboolean getccol(DEstruct DE)
13974 hornik 1005
{
1006
    SEXP tmp, tmp2;
1007
    int i, len, newlen, wcol, wrow;
1008
    SEXPTYPE type;
24274 ripley 1009
    char clab[25];
40747 ripley 1010
    Rboolean newcol = FALSE;
13974 hornik 1011
 
40759 ripley 1012
    wcol = DE->ccol + DE->colmin - 1;
1013
    wrow = DE->crow + DE->rowmin - 1;
1014
    if (wcol > DE->xmaxused) {
24274 ripley 1015
	/* extend work, names and lens */
40759 ripley 1016
	REPROTECT(DE->work = lengthgets(DE->work, wcol), DE->wpi);
1017
	REPROTECT(DE->names = lengthgets(DE->names, wcol), DE->npi);
1018
	for (i = DE->xmaxused; i < wcol; i++) {
24274 ripley 1019
	    sprintf(clab, "var%d", i + 1);
40759 ripley 1020
	    SET_STRING_ELT(DE->names, i, mkChar(clab));
24274 ripley 1021
	}
40759 ripley 1022
	REPROTECT(DE->lens = lengthgets(DE->lens, wcol), DE->lpi);
1023
	DE->xmaxused = wcol;
24274 ripley 1024
    }
40759 ripley 1025
    if (isNull(VECTOR_ELT(DE->work, wcol - 1))) {
13974 hornik 1026
	newcol = TRUE;
40759 ripley 1027
	SET_VECTOR_ELT(DE->work, wcol - 1,
1028
		       ssNewVector(REALSXP, max(100, wrow)));
1029
	INTEGER(DE->lens)[wcol - 1] = 0;
13974 hornik 1030
    }
40759 ripley 1031
    if (!isVector(tmp = VECTOR_ELT(DE->work, wcol - 1)))
13974 hornik 1032
	error("internal type error in dataentry");
40759 ripley 1033
    len = INTEGER(DE->lens)[wcol - 1];
24274 ripley 1034
    type = TYPEOF(tmp);
13974 hornik 1035
    if (len < wrow) {
1036
	for (newlen = max(len * 2, 10) ; newlen < wrow ; newlen *= 2)
1037
	    ;
1038
	tmp2 = ssNewVector(type, newlen);
1039
	for (i = 0; i < len; i++)
1040
	    if (type == REALSXP)
24274 ripley 1041
		REAL(tmp2)[i] = REAL(tmp)[i];
13974 hornik 1042
	    else if (type == STRSXP)
24274 ripley 1043
		SET_STRING_ELT(tmp2, i, STRING_ELT(tmp, i));
13974 hornik 1044
	    else
1045
		error("internal type error in dataentry");
40759 ripley 1046
	SET_VECTOR_ELT(DE->work, wcol - 1, tmp2);
13974 hornik 1047
    }
40747 ripley 1048
    return newcol;
13974 hornik 1049
}
1050
 
46045 murdoch 1051
static SEXP processEscapes(SEXP x)
1052
{
1053
    SEXP newval, pattern, replacement, expr;
1054
    ParseStatus status;
51659 maechler 1055
 
46045 murdoch 1056
    /* We process escape sequences in a scalar string by escaping
1057
       unescaped quotes, then quoting the whole thing and parsing it.  This
1058
       is supposed to be equivalent to the R code
1059
 
1060
       newval <- gsub(perl=TRUE, "(?<!\\\\)((\\\\\\\\)*)\"", "\\1\\\\\"", x)
1061
       newval <- sub('(^.*$)', '"\1"', newval)
1062
       newval <- eval(parse(text=newval))
1063
 
1064
       We do it this way to avoid extracting the escape handling
1065
       code from the parser.  We need it in C code because this may be executed
1066
       numerous times from C in dataentry.c */
51659 maechler 1067
 
46045 murdoch 1068
    PROTECT( pattern = mkString("(?<!\\\\)((\\\\\\\\)*)\"") );
1069
    PROTECT( replacement = mkString("\\1\\\\\"") );
1070
    PROTECT( expr = lang5(install("gsub"), ScalarLogical(1), pattern, replacement, x) );
1071
    SET_TAG( CDR(expr), install("perl") );
1072
 
1073
    PROTECT( newval = eval(expr, R_BaseEnv) );
1074
    PROTECT( pattern = mkString("(^.*$)") );
1075
    PROTECT( replacement = mkString("\"\\1\"") );
1076
    PROTECT( expr = lang4(install("sub"), pattern, replacement, newval) );
1077
    PROTECT( newval = eval(expr, R_BaseEnv) );
1078
    PROTECT( expr = R_ParseVector( newval, 1, &status, R_NilValue) );
51659 maechler 1079
 
46045 murdoch 1080
    /* We only handle the first entry. If this were available more generally,
1081
       we'd probably want to loop over all of expr */
51659 maechler 1082
 
46045 murdoch 1083
    if (status == PARSE_OK && length(expr))
1084
	PROTECT( newval = eval(VECTOR_ELT(expr, 0), R_BaseEnv) );
1085
    else
1086
	PROTECT( newval = R_NilValue );  /* protect just so the count doesn't change */
1087
    UNPROTECT(10);
1088
    return newval;
1089
}
1090
 
13974 hornik 1091
/* close up the entry to a cell, put the value that has been entered
1092
   into the correct place and as the correct type */
1093
 
40759 ripley 1094
static void closerect(DEstruct DE)
13974 hornik 1095
{
24274 ripley 1096
    SEXP cvec;
40759 ripley 1097
    int i, wcol = DE->ccol + DE->colmin - 1,
1098
	wrow = DE->rowmin + DE->crow - 1, wrow0;
24274 ripley 1099
    char clab[25];
40747 ripley 1100
    Rboolean newcol;
13974 hornik 1101
 
1102
    *bufp = '\0';
1103
 
1104
    /* first check to see if anything has been entered */
1105
    if (CellModified) {
40759 ripley 1106
	if (DE->crow == 0) {
13974 hornik 1107
	    if (clength != 0) {
1108
		/* then we are entering a new column name */
40759 ripley 1109
		if (DE->xmaxused < wcol) {
24274 ripley 1110
		    /* extend work, names and lens */
40759 ripley 1111
		    REPROTECT(DE->work = lengthgets(DE->work, wcol), DE->wpi);
1112
		    REPROTECT(DE->names = lengthgets(DE->names, wcol),
1113
			      DE->npi);
1114
		    for (i = DE->xmaxused; i < wcol - 1; i++) {
24274 ripley 1115
			sprintf(clab, "var%d", i + 1);
40759 ripley 1116
			SET_STRING_ELT(DE->names, i, mkChar(clab));
24274 ripley 1117
		    }
40759 ripley 1118
		    REPROTECT(DE->lens = lengthgets(DE->lens, wcol), DE->lpi);
1119
		    DE->xmaxused = wcol;
24274 ripley 1120
		}
40759 ripley 1121
		SET_STRING_ELT(DE->names, wcol - 1, mkChar(buf));
59764 ripley 1122
		printstring(DE ,buf, (int) strlen(buf), 0, wcol, 0);
13974 hornik 1123
	    } else {
40759 ripley 1124
		sprintf(buf, "var%d", DE->ccol);
59764 ripley 1125
		printstring(DE ,buf, (int) strlen(buf), 0, wcol, 0);
13974 hornik 1126
	    }
1127
	} else {
40759 ripley 1128
	    newcol = getccol(DE);
1129
	    cvec = VECTOR_ELT(DE->work, wcol - 1);
1130
	    wrow0 = INTEGER(DE->lens)[wcol - 1];
1131
	    if (wrow > wrow0) INTEGER(DE->lens)[wcol - 1] = wrow;
1132
	    DE->ymaxused = max(DE->ymaxused, wrow);
24274 ripley 1133
	    if (clength != 0) {
1134
		/* do it this way to ensure NA, Inf, ...  can get set */
1135
		char *endp;
1136
		double new = R_strtod(buf, &endp);
1137
		Rboolean warn = !isBlankString(endp);
46045 murdoch 1138
		if (TYPEOF(cvec) == STRSXP) {
1139
		    SEXP newval;
1140
		    PROTECT( newval = mkString(buf) );
1141
		    PROTECT( newval = processEscapes(newval) );
1142
		    if (TYPEOF(newval) == STRSXP && length(newval) == 1)
1143
			SET_STRING_ELT(cvec, wrow - 1, STRING_ELT(newval, 0));
1144
		    else
1145
			warning("dataentry: parse error on string");
1146
		    UNPROTECT(2);
1147
		} else
24274 ripley 1148
		    REAL(cvec)[wrow - 1] = new;
40747 ripley 1149
		if (newcol && warn) {
24274 ripley 1150
		    /* change mode to character */
40747 ripley 1151
		    SEXP tmp = coerceVector(cvec, STRSXP);
1152
		    SET_STRING_ELT(tmp, wrow - 1, mkChar(buf));
40759 ripley 1153
		    SET_VECTOR_ELT(DE->work, wcol - 1, tmp);
24274 ripley 1154
		}
1155
	    } else {
1156
		if (TYPEOF(cvec) == STRSXP)
1157
		    SET_STRING_ELT(cvec, wrow - 1, NA_STRING);
1158
		else
1159
		    REAL(cvec)[wrow - 1] = NA_REAL;
24255 ripley 1160
	    }
40759 ripley 1161
	    drawelt(DE, DE->crow, DE->ccol); /* to get the cell scrolling right */
1162
	    if(wrow > wrow0) drawcol(DE, wcol); /* to fill in NAs */
24255 ripley 1163
	}
13974 hornik 1164
    }
1165
    CellModified = FALSE;
1166
 
40759 ripley 1167
    downlightrect(DE);
13974 hornik 1168
 
1169
    ndecimal = 0;
1170
    nneg = 0;
1171
    ne = 0;
1172
    currentexp = 0;
1173
    clength = 0;
40747 ripley 1174
    inSpecial = 0;
13974 hornik 1175
    bufp = buf;
1176
}
1177
 
1178
/* print a null terminated string, check to see if it is longer than
1179
   the print area and print it, left adjusted if necessary; clear the
1180
   area of previous text; */
1181
 
1182
/* This version will only display 200 chars, but the maximum col width
1183
   will not allow that many */
41831 rgentlem 1184
static void printstring(DEstruct DE, const char *ibuf, int buflen, int row,
45475 ripley 1185
			int col, int left)
13974 hornik 1186
{
1187
    int i, x_pos, y_pos, bw, bufw;
34639 ripley 1188
    char pbuf[BOOSTED_BUF_SIZE];
1189
    int wcsbufw,j;
1190
    wchar_t wcspbuf[BOOSTED_BUF_SIZE], *wcspc = wcspbuf;
1191
    wchar_t wcs[BOOSTED_BUF_SIZE];
1192
    char    s[BOOSTED_BUF_SIZE];
1193
    wchar_t *w_p;
1194
    char    *p;
1195
    int cnt;
13974 hornik 1196
 
40759 ripley 1197
    find_coords(DE, row, col, &x_pos, &y_pos);
1198
    if (col == 0) bw = DE->boxw[0]; else bw = BOXW(col+DE->colmin-1);
1199
    cleararea(DE, x_pos + 2, y_pos + 2, bw - 3, DE->box_h - 3);
34639 ripley 1200
    bufw = (buflen > BOOSTED_BUF_SIZE-1) ? BOOSTED_BUF_SIZE-1 : buflen;
1201
    strncpy(pbuf, ibuf, bufw);
1202
    pbuf[bufw] = '\0';
1203
 
1204
    p = pbuf;
62295 ripley 1205
    wcsbufw = (int) mbsrtowcs(wcspbuf, (const char **)&p, bufw, NULL);
34639 ripley 1206
    wcspbuf[wcsbufw]=L'\0';
1207
    if(left) {
45475 ripley 1208
	for (i = wcsbufw; i > 1; i--) {
34639 ripley 1209
	    for(j=0;*(wcspc+j)!=L'\0';j++)wcs[j]=*(wcspc+j);
1210
	    wcs[j]=L'\0';
1211
	    w_p=wcs;
62295 ripley 1212
	    cnt = (int) wcsrtombs(s,(const wchar_t **)&w_p,sizeof(s)-1,NULL);
34639 ripley 1213
	    s[cnt]='\0';
59764 ripley 1214
	    if (textwidth(DE, s, (int) strlen(s)) < (bw - DE->text_offset)) break;
45475 ripley 1215
	    *(++wcspc) = L'<';
1216
	}
34639 ripley 1217
    } else {
45475 ripley 1218
	for (i = wcsbufw; i > 1; i--) {
34639 ripley 1219
	    for(j=0;*(wcspc+j)!=L'\0';j++)wcs[j]=*(wcspc+j);
1220
	    wcs[j]=L'\0';
1221
	    w_p=wcs;
62314 ripley 1222
	    cnt = (int) wcsrtombs(s,(const wchar_t **)&w_p,sizeof(s)-1,NULL);
34639 ripley 1223
	    s[cnt]='\0';
59764 ripley 1224
	    if (textwidth(DE, s, (int) strlen(s)) < (bw - DE->text_offset)) break;
45475 ripley 1225
	    *(wcspbuf + i - 2) = L'>';
1226
	    *(wcspbuf + i - 1) = L'\0';
1227
	}
34639 ripley 1228
    }
1229
    for(j=0;*(wcspc+j)!=L'\0';j++) wcs[j]=*(wcspc+j);
1230
    wcs[j]=L'\0';
1231
    w_p=wcs;
62295 ripley 1232
    cnt = (int) wcsrtombs(s,(const wchar_t **)&w_p,sizeof(s)-1,NULL);
34639 ripley 1233
 
40759 ripley 1234
    drawtext(DE, x_pos + DE->text_offset, y_pos + DE->box_h - DE->text_offset,
1235
	     s, cnt);
34639 ripley 1236
 
40759 ripley 1237
    Rsync(DE);
13974 hornik 1238
}
1239
 
40759 ripley 1240
static void clearrect(DEstruct DE)
13974 hornik 1241
{
1242
    int x_pos, y_pos;
1243
 
40759 ripley 1244
    find_coords(DE, DE->crow, DE->ccol, &x_pos, &y_pos);
1245
    cleararea(DE, x_pos, y_pos, BOXW(DE->ccol+DE->colmin-1), DE->box_h);
1246
    Rsync(DE);
13974 hornik 1247
}
1248
 
1249
/* handlechar has to be able to parse decimal numbers and strings,
1250
   depending on the current column type, only printing characters
1251
   should get this far */
1252
 
1253
/* --- Not true! E.g. ESC ends up in here... */
1254
 
60260 ripley 1255
#include <rlocale.h>
1256
 
34639 ripley 1257
/* <FIXME> This is not correct for stateful MBCSs, but that's hard to
32677 ripley 1258
   do as we get a char at a time */
40759 ripley 1259
static void handlechar(DEstruct DE, char *text)
13974 hornik 1260
{
44186 ripley 1261
    int c = text[0], j;
34639 ripley 1262
    wchar_t wcs[BOOSTED_BUF_SIZE];
13974 hornik 1263
 
34639 ripley 1264
    memset(wcs,0,sizeof(wcs));
1265
 
32432 ripley 1266
    if ( c == '\033' ) { /* ESC */
13974 hornik 1267
	CellModified = FALSE;
1268
	clength = 0;
45475 ripley 1269
	bufp = buf;
40759 ripley 1270
	drawelt(DE, DE->crow, DE->ccol);
1271
	cell_cursor_init(DE);
13974 hornik 1272
	return;
1273
    } else
1274
	CellModified = TRUE;
1275
 
1276
    if (clength == 0) {
1277
 
40759 ripley 1278
	if (DE->crow == 0)	                        /* variable name */
13974 hornik 1279
	    currentexp = 3;
1280
	else
40759 ripley 1281
	    switch(get_col_type(DE, DE->ccol + DE->colmin - 1)) {
13974 hornik 1282
	    case NUMERIC:
1283
		currentexp = 1;
1284
		break;
1285
	    default:
1286
		currentexp = 2;
1287
	    }
40759 ripley 1288
	clearrect(DE);
1289
	highlightrect(DE);
13974 hornik 1290
    }
1291
 
34639 ripley 1292
    /* NA number? */
40759 ripley 1293
    if (get_col_type(DE, DE->ccol + DE->colmin - 1) == NUMERIC) {
40754 ripley 1294
	/* input numeric for NA of buffer , suppress NA etc.*/
1295
	if(strcmp(buf, "NA") == 0 || strcmp(buf, "NaN") == 0 ||
1296
	   strcmp(buf, "Inf") == 0 || strcmp(buf, "-Inf") == 0) {
34639 ripley 1297
	    buf[0] = '\0';
1298
	    clength = 0;
1299
	    bufp = buf;
1300
	}
1301
    }
1302
 
32518 ripley 1303
    if (currentexp == 1) {	/* we are parsing a number */
49591 ripley 1304
	char *mbs = text;
62295 ripley 1305
	int i, cnt = (int)mbsrtowcs(wcs, (const char **)&mbs, (int) strlen(text)+1, NULL);
34639 ripley 1306
 
49591 ripley 1307
	for(i = 0; i < cnt; i++) {
1308
	    switch (wcs[i]) {
1309
	    case L'-':
1310
		if (nneg == 0) nneg++; else goto donehc;
40747 ripley 1311
	    break;
49591 ripley 1312
	    case L'.':
1313
		if (ndecimal == 0) ndecimal++; else goto donehc;
13974 hornik 1314
	    break;
49591 ripley 1315
	    case L'e':
1316
	    case L'E':
1317
		if (ne == 0) {
1318
		    nneg = ndecimal = 0;	/* might have decimal in exponent */
1319
		    ne++;
1320
		} else goto donehc;
13974 hornik 1321
	    break;
49591 ripley 1322
	    case L'N':
1323
		if(nneg) goto donehc;
1324
	    case L'I':
1325
		inSpecial++;
13974 hornik 1326
	    break;
49591 ripley 1327
	    default:
1328
		if (!inSpecial && !iswdigit(wcs[i])) goto donehc;
1329
		break;
1330
	    }
13974 hornik 1331
	}
32518 ripley 1332
    }
13974 hornik 1333
    if (currentexp == 3) {
40747 ripley 1334
	char *mbs = text;
62295 ripley 1335
	int i, cnt = (int) mbsrtowcs(wcs, (const char **)&mbs, (int) strlen(text)+1, NULL);
40747 ripley 1336
	for(i = 0; i < cnt; i++) {
1337
	    if (iswspace(wcs[i])) goto donehc;
40759 ripley 1338
	    if (clength == 0 && wcs[i] != L'.' && !iswalpha(wcs[i]))
1339
		goto donehc;
40747 ripley 1340
	    else if (wcs[i] != L'.' && !iswalnum(wcs[i])) goto donehc;
1341
	}
13974 hornik 1342
    }
1343
 
34639 ripley 1344
    if (clength+strlen(text) > BOOSTED_BUF_SIZE - MB_CUR_MAX - 1) {
13974 hornik 1345
	warning("dataentry: expression too long");
1346
	goto donehc;
1347
    }
1348
 
42804 maechler 1349
    /* as originally written, this left an undefined byte at
1350
       the end of bufp, followed by a zero byte; luckily, the storage
1351
       pointed to by bufp had already been zeroed, so the undefined
1352
       byte was in fact zero.  */
1353
    strcpy(bufp, text);
59764 ripley 1354
    bufp += (j = (int) strlen(text));
42804 maechler 1355
    clength += j;
40759 ripley 1356
    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
13974 hornik 1357
    return;
1358
 
1359
 donehc:
1360
    bell();
1361
}
1362
 
40759 ripley 1363
static void printlabs(DEstruct DE)
13974 hornik 1364
{
41831 rgentlem 1365
    char clab[15];
1366
    const char *p;
13974 hornik 1367
    int i;
1368
 
40759 ripley 1369
    for (i = DE->colmin; i <= DE->colmax; i++) {
1370
	p = get_col_name(DE, i);
59764 ripley 1371
	printstring(DE, p, (int) strlen(p), 0, i - DE->colmin + 1, 0);
13974 hornik 1372
    }
40759 ripley 1373
    for (i = DE->rowmin; i <= DE->rowmax; i++) {
1374
	sprintf(clab, DE->labform, i);
59764 ripley 1375
	printstring(DE, clab, (int) strlen(clab), i - DE->rowmin + 1, 0, 0);
13974 hornik 1376
    }
1377
}
1378
 
45475 ripley 1379
	       /* ================ X11-specific ================ */
13974 hornik 1380
 
1381
/* find out whether the button click was in the quit box */
1382
static int checkquit(int xw)
1383
{
1384
    if (xw > box_coords[1] && xw < box_coords[0]) return 1;
1385
    if (xw > box_coords[3] && xw < box_coords[2]) return 2;
1386
    if (xw > box_coords[5] && xw < box_coords[4]) return 3;
1387
    return 0;
1388
}
1389
 
1390
/* when a buttonpress event happens find the square that is being
1391
   pointed to if the pointer is in the header we need to see if the
1392
   quit button was pressed and if so quit. This is done by having
32432 ripley 1393
   findcell return an int which is one if we should quit and zero
13974 hornik 1394
   otherwise */
1395
 
40759 ripley 1396
static int findcell(DEstruct DE)
13974 hornik 1397
{
1398
 
1399
    int xw, yw, xr, yr, wcol=0, wrow, i, w;
1400
    unsigned int keys;
1401
    Window root, child;
1402
 
40759 ripley 1403
    closerect(DE);
1404
    XQueryPointer(iodisplay, DE->iowindow, &root, &child,
13974 hornik 1405
		  &xr, &yr, &xw, &yw, &keys);
1406
 
1407
    if (keys & Button1Mask) { /* left click */
1408
 
1409
	/* check to see if the click was in the header */
1410
 
40759 ripley 1411
	if (yw < DE->hht + DE->bwidth) {
13974 hornik 1412
	    i =  checkquit(xw);
1413
	    if (i == 1) return 1;
40759 ripley 1414
	    else if (i == 2) copycell(DE);
1415
	    else if (i == 3) pastecell(DE, DE->crow, DE->ccol);
13974 hornik 1416
	    return 0;
1417
	}
1418
 
32424 ripley 1419
 
13974 hornik 1420
	/* see if it is in the row labels */
40759 ripley 1421
	if (xw < DE->bwidth + DE->boxw[0]) {
13974 hornik 1422
	    bell();
40759 ripley 1423
	    highlightrect(DE);
13974 hornik 1424
	    return 0;
1425
	}
1426
	/* translate to box coordinates */
40759 ripley 1427
	wrow = (yw - DE->bwidth - DE->hht) / DE->box_h;
1428
	w = DE->bwidth + DE->boxw[0];
1429
	for (i = 1; i <= DE->nwide; i++)
1430
	    if((w += BOXW(i+DE->colmin-1)) > xw) {
13974 hornik 1431
		wcol = i;
1432
		break;
1433
	    }
1434
 
1435
	/* next check to see if it is in the column labels */
1436
 
40759 ripley 1437
	if (yw < DE->hht + DE->bwidth + DE->box_h) {
1438
	    if (xw > DE->bwidth + DE->boxw[0])
1439
		popupmenu(DE, xr, yr, wcol, wrow);
13974 hornik 1440
	    else {
40759 ripley 1441
		highlightrect(DE);
13974 hornik 1442
		bell();
1443
	    }
40759 ripley 1444
	} else if (wrow > DE->nhigh - 1 || wcol > DE->nwide -1) {
13974 hornik 1445
		/* off the grid */
40759 ripley 1446
		highlightrect(DE);
13974 hornik 1447
		bell();
40759 ripley 1448
	} else if (wcol != DE->ccol || wrow != DE->crow) {
1449
	    DE->ccol = wcol;
1450
	    DE->crow = wrow;
13974 hornik 1451
	}
1452
    }
1453
    if (keys & Button2Mask) { /* Paste */
1454
	int row, col = 0;
32424 ripley 1455
 
40759 ripley 1456
	if (yw < DE->hht + DE->bwidth || xw < DE->bwidth + DE->boxw[0])
1457
	    return 0;
13974 hornik 1458
 
1459
	/* translate to box coordinates */
40759 ripley 1460
	row = (yw - DE->bwidth - DE->hht) / DE->box_h;
1461
	w = DE->bwidth + DE->boxw[0];
1462
	for (i = 1; i <= DE->nwide; i++)
1463
	    if ((w += BOXW(i+DE->colmin-1)) > xw) {
13974 hornik 1464
		col = i;
1465
		break;
1466
	    }
40759 ripley 1467
	pastecell(DE, row, col);
13974 hornik 1468
    }
40759 ripley 1469
    highlightrect(DE);
13974 hornik 1470
    return 0;
1471
}
1472
 
1473
 
1474
/* Event Loop Functions */
45475 ripley 1475
#define mouseDown	ButtonPress
40756 ripley 1476
#define keyDown		KeyPress
1477
#define activateEvt	MapNotify
1478
#define updateEvt	Expose
13974 hornik 1479
 
40759 ripley 1480
static void eventloop(DEstruct DE)
13974 hornik 1481
{
1482
    int done;
1483
    DEEvent ioevent;
46169 ripley 1484
    caddr_t temp;
13974 hornik 1485
 
1486
    done = 0;
1487
    while (done == 0) {
45475 ripley 1488
	XNextEvent(iodisplay, &ioevent);
46169 ripley 1489
	XFindContext(iodisplay, ioevent.xany.window, deContext, &temp);
1490
	if ((DEstruct) temp != DE) { /* so a View window */
1491
	    if (WhichEvent(ioevent) == Expose)
1492
		drawwindow((DEstruct) temp);
1493
	} else {
45475 ripley 1494
	    if (XFilterEvent(&ioevent, None)){
40754 ripley 1495
		if(ioic){
1496
		    XSetICFocus(ioic);
1497
		    if (ioim_style & XIMPreeditPosition)
40759 ripley 1498
			calc_pre_edit_pos(DE);
40754 ripley 1499
		}
1500
		continue;
34639 ripley 1501
	    }
1502
 
13974 hornik 1503
	    switch (WhichEvent(ioevent)) {
34639 ripley 1504
	    case keyDown:/* KeyPress */
40759 ripley 1505
		doSpreadKey(DE, 0, &ioevent);
34639 ripley 1506
		break;
45475 ripley 1507
	    case Expose:
40759 ripley 1508
		while(XCheckTypedEvent(iodisplay, Expose, &ioevent))
1509
		    ;
40754 ripley 1510
		/*
1511
		 * XIM on  - KeyPress - Expose
1512
		 * XIM off - KeyPress - KeyRelease
1513
		 * colname change XIM on mode. type Backspace.
1514
		 */
45475 ripley 1515
		if(DE->crow == 0){
40759 ripley 1516
		    drawwindow(DE);
1517
		    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
40747 ripley 1518
		} else {
40759 ripley 1519
		    closerect(DE);
1520
		    drawwindow(DE);
1521
		    cell_cursor_init(DE);
34639 ripley 1522
		}
1523
		break;
1524
	    case activateEvt:/* MapNotify */
45475 ripley 1525
		closerect(DE);
40759 ripley 1526
		drawwindow(DE);
1527
		cell_cursor_init(DE);
45475 ripley 1528
		break;
34639 ripley 1529
	    case mouseDown:/* ButtonPress */
40759 ripley 1530
		if(DE->isEditor) {
1531
		    done  = doMouseDown(DE, &ioevent);
1532
		    cell_cursor_init(DE);
40755 ripley 1533
		}
13974 hornik 1534
		break;
1535
	    case MappingNotify:
1536
		RefreshKeyboardMapping(&ioevent);
1537
		break;
1538
	    case ConfigureNotify:
40759 ripley 1539
		while(XCheckTypedEvent(iodisplay, ConfigureNotify, &ioevent))
1540
		    ;
1541
		doConfigure(DE, &ioevent);
1542
		cell_cursor_init(DE);
13974 hornik 1543
		break;
1544
	    case ClientMessage:
1545
		if(ioevent.xclient.message_type == _XA_WM_PROTOCOLS
40759 ripley 1546
		   && ioevent.xclient.data.l[0] == DE->prot) {
13974 hornik 1547
		    /* user clicked on `close' aka `destroy' */
40754 ripley 1548
		    done = 1;
13974 hornik 1549
		}
1550
		break;
1551
	    }
1552
	}
1553
    }
1554
}
1555
 
40756 ripley 1556
static void R_ProcessX11Events(void *data)
1557
{
40759 ripley 1558
    caddr_t temp;
1559
    DEstruct DE = NULL;
40756 ripley 1560
    DEEvent ioevent;
1561
    int done = 0;
1562
 
46169 ripley 1563
    while (nView && XPending(iodisplay)) {
45475 ripley 1564
	XNextEvent(iodisplay, &ioevent);
40759 ripley 1565
	XFindContext(iodisplay, ioevent.xany.window, deContext, &temp);
1566
	DE = (DEstruct) temp;
40756 ripley 1567
	switch (WhichEvent(ioevent)) {
1568
	case keyDown:/* KeyPress */
40759 ripley 1569
	    doSpreadKey(DE, 0, &ioevent);
40756 ripley 1570
	    break;
1571
	case Expose:
40759 ripley 1572
	    while(XCheckTypedEvent(iodisplay, Expose, &ioevent))
1573
		;
1574
	    drawwindow(DE);
40756 ripley 1575
	    break;
1576
	case MappingNotify:
1577
	    RefreshKeyboardMapping(&ioevent);
1578
	    break;
1579
	case ConfigureNotify:
40759 ripley 1580
	    while(XCheckTypedEvent(iodisplay, ConfigureNotify, &ioevent))
1581
		;
1582
	    doConfigure(DE, &ioevent);
1583
	    cell_cursor_init(DE);
40756 ripley 1584
	    break;
1585
	case activateEvt:/* MapNotify */
1586
	    break;
1587
	case ClientMessage:
1588
	    if(ioevent.xclient.message_type == _XA_WM_PROTOCOLS
40759 ripley 1589
	       && ioevent.xclient.data.l[0] == DE->prot) {
40756 ripley 1590
		/* user clicked on `close' aka `destroy' */
1591
		done = 1;
1592
	    }
1593
	    break;
1594
	}
1595
    }
1596
    if(done) {
40759 ripley 1597
	R_ReleaseObject(DE->lens);
1598
	R_ReleaseObject(DE->work);
1599
	closewin(DE);
1600
	free(DE);
1601
	nView--;
1602
	if(nView == 0) {
46169 ripley 1603
	    /* NB: this is removing the handler that is currently
1604
	       being used: only OK to free here in R > 2.8.0 */
40759 ripley 1605
	    removeInputHandler(&R_InputHandlers,
1606
			       getInputHandler(R_InputHandlers,fdView));
1607
	    fdView = -1;
46169 ripley 1608
	    if(font_set) {
1609
		XFreeFontSet(iodisplay, font_set);
1610
		font_set = NULL;
1611
	    }
40759 ripley 1612
	    XCloseDisplay(iodisplay);
1613
	    iodisplay = NULL;
1614
	}
45475 ripley 1615
 
40756 ripley 1616
    }
1617
}
1618
 
40759 ripley 1619
static int doMouseDown(DEstruct DE, DEEvent * event)
13974 hornik 1620
{
40759 ripley 1621
    return findcell(DE);
13974 hornik 1622
}
1623
 
40759 ripley 1624
static void doSpreadKey(DEstruct DE, int key, DEEvent * event)
13974 hornik 1625
{
1626
    KeySym iokey;
49591 ripley 1627
    char *text = "";
13974 hornik 1628
 
1629
    iokey = GetKey(event);
48544 ripley 1630
    if(DE->isEditor) text = GetCharP(event);
13974 hornik 1631
 
1632
    if (CheckControl(event))
40759 ripley 1633
	doControl(DE, event);
32424 ripley 1634
    else if ((iokey == XK_Return)  || (iokey == XK_KP_Enter) ||
13974 hornik 1635
	     (iokey == XK_Linefeed)|| (iokey == XK_Down))
40759 ripley 1636
	advancerect(DE, DOWN);
13974 hornik 1637
    else if (iokey == XK_Left)
40759 ripley 1638
	advancerect(DE, LEFT);
13974 hornik 1639
    else if (iokey == XK_Right)
40759 ripley 1640
	advancerect(DE, RIGHT);
13974 hornik 1641
    else if (iokey == XK_Up)
40759 ripley 1642
	advancerect(DE, UP);
22718 ripley 1643
#ifdef XK_Page_Up
1644
    else if (iokey == XK_Page_Up) {
40759 ripley 1645
	int i = DE->rowmin - DE->nhigh + 2;
1646
	jumpwin(DE, DE->colmin, max(1, i));
1647
	cell_cursor_init(DE);
13974 hornik 1648
    }
22718 ripley 1649
#elif defined(XK_Prior)
1650
    else if (iokey == XK_Prior) {
40759 ripley 1651
	int i = DE->rowmin - DE->nhigh + 2;
1652
	jumpwin(DE, DE->colmin, max(1, i));
1653
	cell_cursor_init(DE);
13974 hornik 1654
    }
22718 ripley 1655
#endif
1656
#ifdef XK_Page_Down
34639 ripley 1657
    else if (iokey == XK_Page_Down) {
40759 ripley 1658
	if(DE->isEditor)
48544 ripley 1659
	    jumpwin(DE, DE->colmin, DE->rowmax);
40755 ripley 1660
	else {
40759 ripley 1661
	    int i = DE->ymaxused - DE->nhigh + 2;
51659 maechler 1662
            jumpwin(DE, DE->colmin, min(i, DE->rowmax));
40755 ripley 1663
	}
40759 ripley 1664
	cell_cursor_init(DE);
34639 ripley 1665
    }
22718 ripley 1666
#elif defined(XK_Next)
34639 ripley 1667
    else if (iokey == XK_Next) {
48544 ripley 1668
	if(DE->isEditor)
1669
	    jumpwin(DE, DE->colmin, DE->rowmax);
1670
	else {
1671
	    int i = DE->ymaxused - DE->nhigh + 2;
51659 maechler 1672
            jumpwin(DE, DE->colmin, min(i, DE->rowmax));
48544 ripley 1673
	}
40759 ripley 1674
	cell_cursor_init(DE);
34639 ripley 1675
    }
13974 hornik 1676
#endif
40759 ripley 1677
    else if (DE->isEditor && (iokey == XK_BackSpace || iokey == XK_Delete)) {
13974 hornik 1678
	if (clength > 0) {
34639 ripley 1679
	    int last_w ;
1680
	    last_w = last_wchar_bytes(NULL);
1681
	    clength -= last_w;
1682
	    bufp -= last_w;
1683
	    *bufp = '\0';
1684
	    CellModified = TRUE;
40759 ripley 1685
	    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
13974 hornik 1686
	} else bell();
1687
    }
1688
    else if (iokey == XK_Tab) {
40759 ripley 1689
	if(CheckShift(event)) advancerect(DE, LEFT);
1690
	else advancerect(DE, RIGHT);
13974 hornik 1691
    }
1692
    else if (iokey == XK_Home) {
40759 ripley 1693
	jumpwin(DE, 1, 1);
1694
	downlightrect(DE);
1695
	DE->crow = DE->ccol = 1;
1696
	highlightrect(DE);
1697
	cell_cursor_init(DE);
13974 hornik 1698
    }
1699
    else if (iokey == XK_End) {
40759 ripley 1700
	int i = DE->ymaxused - DE->nhigh + 2, j, w = 0 ;
1701
	/* Try to work out which cols we can fit in */
1702
	for(j = DE->xmaxused;j >= 0; j--) {
1703
	    w += BOXW(j);
1704
	    if(w > DE->fullwindowWidth) break;
1705
	}
44407 ripley 1706
	jumpwin(DE, min(1 + max(j, 0), DE->xmaxused), max(i, 1));
40759 ripley 1707
	downlightrect(DE);
1708
	DE->crow = DE->ymaxused - DE->rowmin + 1;
1709
	DE->ccol = DE->xmaxused - DE->colmin + 1;
1710
	highlightrect(DE);
1711
	cell_cursor_init(DE);
13974 hornik 1712
    }
1713
    else if (IsModifierKey(iokey)) {
1714
    }
40759 ripley 1715
    else if(DE->isEditor) {
1716
	handlechar(DE, text);
1717
    }
13974 hornik 1718
}
1719
 
1720
 
1721
static int WhichEvent(DEEvent ioevent)
1722
{
1723
    return ioevent.type;
1724
}
1725
 
1726
static KeySym GetKey(DEEvent * event)
1727
{
1728
    char text[1];
1729
    KeySym iokey;
1730
 
31990 ripley 1731
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1732
    return iokey;
1733
}
1734
 
32432 ripley 1735
static char *GetCharP(DEEvent * event)
13974 hornik 1736
{
34639 ripley 1737
    static char text[BOOSTED_BUF_SIZE];
13974 hornik 1738
    KeySym iokey;
1739
 
34639 ripley 1740
    memset(text,0,sizeof(text));
1741
 
32677 ripley 1742
    if(mbcslocale) {
32471 ripley 1743
#ifdef HAVE_XUTF8LOOKUPSTRING
45475 ripley 1744
	if(utf8locale)
34639 ripley 1745
	    Xutf8LookupString(ioic, (XKeyEvent *)event,
1746
			      text, sizeof(text) - clength,
1747
			      &iokey, &status);
1748
	else
32471 ripley 1749
#endif
34639 ripley 1750
	    XmbLookupString(ioic, (XKeyEvent *)event,
1751
			    text, sizeof(text) - clength,
1752
			    &iokey, &status);
32432 ripley 1753
	/* FIXME check the return code */
34639 ripley 1754
	if(status == XBufferOverflow)
1755
	    warning("dataentry: expression too long");
32432 ripley 1756
    } else
34639 ripley 1757
	XLookupString((XKeyEvent *)event,
1758
		      text, sizeof(text) - clength,
1759
		      &iokey, NULL);
32432 ripley 1760
    return text;
13974 hornik 1761
}
1762
 
1763
static int CheckControl(DEEvent * event)
1764
{
1765
    return (*event).xkey.state & ControlMask;
1766
}
1767
 
1768
static int CheckShift(DEEvent * event)
1769
{
1770
    return (*event).xkey.state & ShiftMask;
1771
}
1772
 
40759 ripley 1773
static void doControl(DEstruct DE, DEEvent * event)
13974 hornik 1774
{
1775
    int i;
1776
    char text[1];
1777
    KeySym iokey;
1778
 
1779
    (*event).xkey.state = 0;
31990 ripley 1780
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1781
    /* one row overlap when scrolling: top line <--> bottom line */
1782
    switch (text[0]) {
1783
	case 'b':
40759 ripley 1784
	    i = DE->rowmin - DE->nhigh + 2;
1785
	    jumpwin(DE, DE->colmin, max(1, i));
13974 hornik 1786
	    break;
1787
	case 'f':
40759 ripley 1788
	    jumpwin(DE, DE->colmin, DE->rowmax);
13974 hornik 1789
	    break;
1790
	case 'l':
40759 ripley 1791
	    closerect(DE);
1792
	    for (i = 1 ; i <= min(100, DE->xmaxused); i++)
1793
		DE->boxw[i] = get_col_width(DE, i);
1794
	    closerect(DE);
1795
	    drawwindow(DE);
13974 hornik 1796
	    break;
1797
    }
40759 ripley 1798
    cell_cursor_init(DE);
13974 hornik 1799
}
1800
 
1801
 
40759 ripley 1802
static void doConfigure(DEstruct DE, DEEvent * event)
13974 hornik 1803
{
40759 ripley 1804
    if ((DE->fullwindowWidth != (*event).xconfigure.width) ||
1805
	(DE->fullwindowHeight != (*event).xconfigure.height)) {
1806
	closerect(DE);
1807
	drawwindow(DE);
34639 ripley 1808
    }
13974 hornik 1809
}
1810
 
1811
static void RefreshKeyboardMapping(DEEvent * event)
1812
{
28840 ripley 1813
    XRefreshKeyboardMapping((XMappingEvent *)event);
13974 hornik 1814
}
1815
 
1816
/* Initialize/Close Windows */
1817
 
40759 ripley 1818
void closewin(DEstruct DE)
13974 hornik 1819
{
40759 ripley 1820
    XFreeGC(iodisplay, DE->iogc);
1821
    if(mbcslocale  && DE->isEditor) {
32518 ripley 1822
	XDestroyIC(ioic);
1823
	XCloseIM(ioim);
1824
    }
40759 ripley 1825
    XDestroyWindow(iodisplay, DE->iowindow);
41345 ripley 1826
    /* XCloseDisplay(iodisplay); */
46161 ripley 1827
    Rsync(DE);
13974 hornik 1828
}
1829
 
36044 ripley 1830
#define USE_Xt 1
1831
 
1832
#ifdef USE_Xt
1833
#include <X11/StringDefs.h>
1834
#include <X11/Intrinsic.h>
1835
#include <X11/Shell.h>
1836
typedef struct gx_device_X_s {
1837
    Pixel background, foreground, borderColor;
1838
    Dimension borderWidth;
1839
    String geometry;
1840
} gx_device_X;
1841
 
1842
/* (String) casts are here to suppress warnings about discarding `const' */
1843
#define RINIT(a,b,t,s,o,it,n)\
1844
  {(String)(a), (String)(b), (String)t, sizeof(s),\
1845
   XtOffsetOf(gx_device_X, o), (String)it, (n)}
1846
#define rpix(a,b,o,n)\
1847
  RINIT(a,b,XtRPixel,Pixel,o,XtRString,(XtPointer)(n))
1848
#define rdim(a,b,o,n)\
1849
  RINIT(a,b,XtRDimension,Dimension,o,XtRImmediate,(XtPointer)(n))
1850
#define rstr(a,b,o,n)\
1851
  RINIT(a,b,XtRString,String,o,XtRString,(char*)(n))
1852
 
1853
static XtResource x_resources[] = {
1854
    rpix(XtNforeground, XtCForeground, foreground, "XtDefaultForeground"),
1855
    rpix(XtNbackground, XtCBackground, background, "XtDefaultBackground"),
1856
    rstr(XtNgeometry, XtCGeometry, geometry, NULL),
1857
};
1858
 
1859
static const int x_resource_count = XtNumber(x_resources);
1860
static gx_device_X xdev;
1861
#endif
1862
 
59332 pd 1863
/* NB: Keep this in sync with similar handler in devX11.c */
13974 hornik 1864
static int R_X11Err(Display *dsp, XErrorEvent *event)
1865
{
1866
    char buff[1000];
59332 pd 1867
    /* for tcl/tk */
1868
    if (event->error_code == BadWindow) return 0;
1869
 
13974 hornik 1870
    XGetErrorText(dsp, event->error_code, buff, 1000);
59332 pd 1871
    warning(_("X11 protocol error: %s"), buff);
13974 hornik 1872
    return 0;
1873
}
1874
 
59332 pd 1875
 
13974 hornik 1876
static int R_X11IOErr(Display *dsp)
1877
{
1878
    error("X11 fatal IO error: please save work and shut down R");
1879
    return 0; /* but should never get here */
1880
}
1881
 
1882
/* set up the window, print the grid and column/row labels */
1883
 
41831 rgentlem 1884
static Rboolean initwin(DEstruct DE, const char *title) /* TRUE = Error */
13974 hornik 1885
{
40747 ripley 1886
    int i, twidth, w, minwidth, labdigs;
13974 hornik 1887
    int ioscreen;
1888
    unsigned long iowhite, ioblack;
1889
    char digits[] = "123456789.0";
40756 ripley 1890
    char             *font_name="9x15";
13974 hornik 1891
    Window root;
1892
    XEvent ioevent;
1893
    XSetWindowAttributes winattr;
1894
    XWindowAttributes attribs;
34639 ripley 1895
    XSizeHints *hint;
35415 ripley 1896
    unsigned long fevent=0UL;
34639 ripley 1897
    int j,k;
1898
    XVaNestedList   xva_nlist;
1899
    XPoint xpoint;
13974 hornik 1900
 
32424 ripley 1901
    strcpy(copycontents, "");
1902
 
34639 ripley 1903
    if (!XSupportsLocale ())
32424 ripley 1904
	warning("locale not supported by Xlib: some X ops will operate in C locale");
1905
    if (!XSetLocaleModifiers ("")) warning("X cannot set locale modifiers");
1906
 
40759 ripley 1907
    if(!iodisplay) {
1908
	if ((iodisplay = XOpenDisplay(NULL)) == NULL) {
1909
	    warning("unable to open display");
1910
	    return TRUE;
1911
	}
1912
	deContext = XUniqueContext();
1913
	XSetErrorHandler(R_X11Err);
1914
	XSetIOErrorHandler(R_X11IOErr);
32424 ripley 1915
    }
13974 hornik 1916
 
45475 ripley 1917
 
13974 hornik 1918
    /* Get Font Loaded if we can */
1919
 
32677 ripley 1920
    if(mbcslocale) {
32424 ripley 1921
	int  missing_charset_count;
1922
	char **missing_charset_list;
1923
	char *def_string;
34639 ripley 1924
	char opt_fontset_name[512];
1925
 
44345 ripley 1926
	/* options("X11fonts")[1] read font name */
54049 ripley 1927
	SEXP opt = GetOption1(install("X11fonts"));
44345 ripley 1928
	if(isString(opt)) {
1929
	    const char *s = CHAR(STRING_ELT(opt, 0));
1930
	    sprintf(opt_fontset_name, s, "medium", "r", 12);
1931
	} else strcpy(opt_fontset_name, fontset_name);
34639 ripley 1932
 
46169 ripley 1933
	if(font_set == NULL) {
1934
	    font_set = XCreateFontSet(iodisplay, opt_fontset_name,
1935
				      &missing_charset_list,
1936
				      &missing_charset_count, &def_string);
1937
	    if (missing_charset_count) XFreeStringList(missing_charset_list);
1938
	}
32424 ripley 1939
	if (font_set == NULL) {
44345 ripley 1940
	    warning("unable to create fontset %s", opt_fontset_name);
32424 ripley 1941
	    return TRUE; /* ERROR */
1942
	}
49591 ripley 1943
    } else {
40759 ripley 1944
	DE->font_info = XLoadQueryFont(iodisplay, font_name);
1945
	if (DE->font_info == NULL) {
32424 ripley 1946
	    warning("unable to losd font %s", font_name);
1947
	    return TRUE; /* ERROR */
1948
	}
1949
    }
13974 hornik 1950
 
1951
    /* find out how wide the input boxes should be and set up the
1952
       window size defaults */
1953
 
54049 ripley 1954
    DE->nboxchars = asInteger(GetOption1(install("de.cellwidth")));
40759 ripley 1955
    if (DE->nboxchars == NA_INTEGER || DE->nboxchars < 0) DE->nboxchars = 0;
13974 hornik 1956
 
59764 ripley 1957
    twidth = textwidth(DE, digits, (int) strlen(digits));
34639 ripley 1958
 
40759 ripley 1959
    if (DE->nboxchars > 0) twidth = (twidth * DE->nboxchars)/10;
1960
    DE->box_w = twidth + 4;
32677 ripley 1961
    if(mbcslocale) {
32424 ripley 1962
	XFontSetExtents *extent = XExtentsOfFontSet(font_set);
1963
	char **ml;
40759 ripley 1964
	DE->box_h = (extent->max_logical_extent.height)
32424 ripley 1965
	    + (extent->max_logical_extent.height / 5) + 4;
1966
	font_set_cnt = XFontsOfFontSet(font_set, &fs_list, &ml);
40759 ripley 1967
	DE->text_offset = 2 + fs_list[0]->max_bounds.descent;
49591 ripley 1968
    } else {
40759 ripley 1969
	DE->box_h = DE->font_info->max_bounds.ascent
1970
	    + DE->font_info->max_bounds.descent + 4;
1971
	DE->text_offset = 2 + DE->font_info->max_bounds.descent;
32424 ripley 1972
    }
40759 ripley 1973
    DE->windowHeight = 26 * DE->box_h + DE->hht + 2;
24271 ripley 1974
    /* this used to presume 4 chars sufficed for row numbering */
59764 ripley 1975
    labdigs = max(3, 1+ (int) floor(log10((double)DE->ymaxused)));
40759 ripley 1976
    sprintf(DE->labform, "%%%dd", labdigs);
59764 ripley 1977
    DE->boxw[0] = (int)( 0.1*labdigs*textwidth(DE, "0123456789", 10)) +
40759 ripley 1978
	textwidth(DE, " ", 1) + 8;
1979
    for(i = 1; i < 100; i++) DE->boxw[i] = get_col_width(DE, i);
34639 ripley 1980
 
13974 hornik 1981
    /* try for a window width that covers all the columns, or is around
1982
       800 pixels */
40759 ripley 1983
    w = DE->windowWidth = 0;
1984
    for(i = 0; i <= DE->xmaxused; i++) {
1985
	w += DE->boxw[i];
13974 hornik 1986
	if(w > 800) {
40759 ripley 1987
	    DE->windowWidth = w - DE->boxw[i];
13974 hornik 1988
	    break;
1989
	}
1990
    }
40759 ripley 1991
    if(DE->windowWidth == 0) DE->windowWidth = w;
1992
    DE->windowWidth += 2;
13974 hornik 1993
    /* allow enough width for buttons */
62295 ripley 1994
    minwidth = (int)(7.5 * textwidth(DE, "Paste", 5));
40759 ripley 1995
    if(DE->windowWidth < minwidth) DE->windowWidth = minwidth;
13974 hornik 1996
 
1997
    ioscreen = DefaultScreen(iodisplay);
1998
    iowhite = WhitePixel(iodisplay, ioscreen);
1999
    ioblack = BlackPixel(iodisplay, ioscreen);
2000
 
2001
 
36044 ripley 2002
    hint = XAllocSizeHints();
34639 ripley 2003
 
2004
    hint->x = 0;
2005
    hint->y = 0;
40759 ripley 2006
    hint->width = DE->windowWidth;
2007
    hint->height = DE->windowHeight;
34639 ripley 2008
    hint->flags = PPosition | PSize;
2009
    /*
2010
     * not necessary?
32518 ripley 2011
    hints.flags = InputHint;
2012
    hints.input = True;
34639 ripley 2013
    */
13974 hornik 2014
    root = DefaultRootWindow(iodisplay);
2015
 
36044 ripley 2016
#ifdef USE_Xt
2017
    {
2018
	XtAppContext app_con;
2019
	Widget toplevel;
2020
	Display *xtdpy;
45475 ripley 2021
	int zero = 0;
36044 ripley 2022
 
2023
	XtToolkitInitialize();
2024
	app_con = XtCreateApplicationContext();
2025
	/* XtAppSetFallbackResources(app_con, x_fallback_resources);*/
2026
	xtdpy = XtOpenDisplay(app_con, NULL, "r_dataentry", "R_dataentry",
2027
			      NULL, 0, &zero, NULL);
2028
	toplevel = XtAppCreateShell(NULL, "R_dataentry",
40759 ripley 2029
				    applicationShellWidgetClass,
36044 ripley 2030
				    xtdpy, NULL, 0);
2031
	XtGetApplicationResources(toplevel, (XtPointer) &xdev,
40759 ripley 2032
				  x_resources,
36044 ripley 2033
				  x_resource_count,
2034
				  NULL, 0);
2035
	XtDestroyWidget(toplevel);
2036
	XtCloseDisplay(xtdpy);
2037
	XtDestroyApplicationContext(app_con);
2038
	if (xdev.geometry != NULL) {
2039
	    char gstr[40];
2040
	    int bitmask;
40759 ripley 2041
 
36044 ripley 2042
	    sprintf(gstr, "%dx%d+%d+%d", hint->width,
2043
		    hint->height, hint->x, hint->y);
2044
	    bitmask = XWMGeometry(iodisplay, DefaultScreen(iodisplay),
40759 ripley 2045
				  xdev.geometry, gstr,
36044 ripley 2046
				  1,
2047
				  hint,
2048
				  &hint->x, &hint->y,
2049
				  &hint->width, &hint->height,
2050
				  &hint->win_gravity);
40759 ripley 2051
 
36044 ripley 2052
	    if (bitmask & (XValue | YValue))
2053
		hint->flags |= USPosition;
40759 ripley 2054
	    if (bitmask & (WidthValue | HeightValue))
36044 ripley 2055
		hint->flags |= USSize;
2056
	}
2057
	ioblack = xdev.foreground;
2058
	iowhite = xdev.background;
2059
    }
2060
#endif
40759 ripley 2061
    if ((DE->iowindow = XCreateSimpleWindow(
32518 ripley 2062
	     iodisplay,
2063
	     root,
34639 ripley 2064
	     hint->x,
2065
	     hint->y,
2066
	     hint->width,
2067
	     hint->height,
40759 ripley 2068
	     DE->bwidth,
32518 ripley 2069
	     ioblack,
2070
	     iowhite)) == 0) {
32424 ripley 2071
	warning("unable to open window for data editor");
13974 hornik 2072
	return TRUE;
32424 ripley 2073
    }
13974 hornik 2074
 
34639 ripley 2075
    /*
40759 ripley 2076
    XSetStandardProperties(iodisplay, DE->iowindow, ioname, ioname, None,
34639 ripley 2077
			   (char **)NULL, 0, iohint);
2078
    */
40759 ripley 2079
    XSetWMNormalHints(iodisplay, DE->iowindow, hint);
34639 ripley 2080
    XFree(hint);
13974 hornik 2081
 
34639 ripley 2082
 
2083
    winattr.backing_store = WhenMapped;
40759 ripley 2084
    XChangeWindowAttributes(iodisplay, DE->iowindow, CWBackingStore,
2085
			    &winattr);
13974 hornik 2086
 
2087
    /* set up protocols so that window manager sends */
2088
    /* me an event when user "destroys" window */
40756 ripley 2089
    if(!_XA_WM_PROTOCOLS)
2090
	_XA_WM_PROTOCOLS = XInternAtom(iodisplay, "WM_PROTOCOLS", 0);
40759 ripley 2091
    DE->prot = XInternAtom(iodisplay, "WM_DELETE_WINDOW", 0);
2092
    XSetWMProtocols(iodisplay, DE->iowindow, &DE->prot, 1);
34639 ripley 2093
    /*
2094
     * not necessary
40759 ripley 2095
    XSetWMHints(iodisplay, DE->iowindow, &hints);
34639 ripley 2096
     */
2097
 
40759 ripley 2098
    DE->iogc = XCreateGC(iodisplay, DE->iowindow, 0, 0);
34639 ripley 2099
 
46169 ripley 2100
    if(mbcslocale && DE->isEditor) {
32518 ripley 2101
	ioim = XOpenIM(iodisplay, NULL, NULL, NULL);
32527 ripley 2102
	if(!ioim) {
40759 ripley 2103
	    XDestroyWindow(iodisplay, DE->iowindow);
32527 ripley 2104
	    XCloseDisplay(iodisplay);
34639 ripley 2105
	    warning("unable to open X Input Method");
2106
	    return TRUE;
32527 ripley 2107
	}
32555 ripley 2108
 
34639 ripley 2109
	/* search supported input style */
2110
	XGetIMValues(ioim, XNQueryInputStyle, &ioim_styles,NULL);
2111
	for(i = 0; i < ioim_styles->count_styles; i++) {
2112
	    for(j = 0; preedit_styles[j]; j++){
2113
		for(k = 0; status_styles[k]; k++){
2114
		    ioim_style = (preedit_styles[j] | status_styles[k]);
2115
		    if( ioim_styles->supported_styles[i] == ioim_style) {
2116
			goto loop_out;
2117
		    }
2118
		}
2119
	    }
2120
	}
2121
    loop_out:
2122
 
2123
	/* create input context */
2124
	xpoint.x = 0; xpoint.y=0;
2125
	xva_nlist = XVaCreateNestedList(0, XNFontSet, font_set,
2126
					XNSpotLocation, &xpoint, NULL);
2127
 
2128
	ioic = XCreateIC(ioim,
45475 ripley 2129
			 XNInputStyle, ioim_style,
40759 ripley 2130
			 XNClientWindow,DE->iowindow,
2131
			 XNFocusWindow,DE->iowindow,
34639 ripley 2132
			 XNPreeditAttributes, xva_nlist,
2133
			 XNStatusAttributes, xva_nlist,
32518 ripley 2134
			 NULL);
34639 ripley 2135
	XFree(xva_nlist);
32518 ripley 2136
	if(!ioic) {
2137
	    XCloseIM(ioim);
40759 ripley 2138
	    XDestroyWindow(iodisplay, DE->iowindow);
32518 ripley 2139
	    XCloseDisplay(iodisplay);
34639 ripley 2140
	    warning("unable to open X Input Context");
2141
	    return TRUE;
32518 ripley 2142
	}
34639 ripley 2143
 
2144
	/* get XIM processes event. */
2145
	XGetICValues(ioic, XNFilterEvents, &fevent, NULL);
32518 ripley 2146
    }
13974 hornik 2147
 
32677 ripley 2148
    if(!mbcslocale)
40759 ripley 2149
	XSetFont(iodisplay, DE->iogc, DE->font_info->fid);
49591 ripley 2150
 
40759 ripley 2151
    XSetBackground(iodisplay, DE->iogc, iowhite);
2152
    XSetForeground(iodisplay, DE->iogc, ioblack);
2153
    XSetLineAttributes(iodisplay, DE->iogc, 1, LineSolid, CapRound,
2154
		       JoinRound);
32555 ripley 2155
 
34639 ripley 2156
    /*
40759 ripley 2157
    XSelectInput(iodisplay, DE->iowindow,
32555 ripley 2158
		 ButtonPressMask | KeyPressMask
34639 ripley 2159
		 | ExposureMask | StructureNotifyMask | fevent);
2160
    */
2161
 
40759 ripley 2162
    XSelectInput(iodisplay, DE->iowindow,
34639 ripley 2163
		 ButtonPressMask
2164
		 | KeyPressMask
2165
		 | StructureNotifyMask
2166
		 | ExposureMask
2167
		 | EnterWindowMask
2168
		 | LeaveWindowMask
2169
		 | fevent);
40759 ripley 2170
    XMapRaised(iodisplay, DE->iowindow);
32555 ripley 2171
 
13974 hornik 2172
    /* now set up the menu-window, for now use the same text
2173
       dimensions as above */
2174
 
34639 ripley 2175
    /* font size consideration */
2176
    for(i = 0; i < (sizeof(menu_label)/sizeof(char *)); i++)
59764 ripley 2177
	twidth = (twidth<textwidth(DE, menu_label[i],(int) strlen(menu_label[i]))) ?
2178
	    textwidth(DE, menu_label[i],(int) strlen(menu_label[i])) : twidth;
34639 ripley 2179
 
13974 hornik 2180
    menuwindow = XCreateSimpleWindow(iodisplay, root, 0, 0, twidth,
40759 ripley 2181
				     4 * DE->box_h, 2, ioblack, iowhite);
13974 hornik 2182
    for (i = 0; i < 4; i++) {
2183
	menupanes[i] = XCreateSimpleWindow(iodisplay, menuwindow, 0,
40759 ripley 2184
					   DE->box_h * i, twidth, DE->box_h,
13974 hornik 2185
					   1, ioblack, iowhite);
2186
	XSelectInput(iodisplay, menupanes[i],
34639 ripley 2187
		     ButtonPressMask | ButtonReleaseMask | ExposureMask
2188
		     );
13974 hornik 2189
    }
2190
 
2191
    /* XMapSubwindows(iodisplay, menuwindow); */
2192
 
2193
 
40759 ripley 2194
    XStoreName(iodisplay, DE->iowindow, title);
13974 hornik 2195
    winattr.override_redirect = True;
2196
    XChangeWindowAttributes(iodisplay, menuwindow,
2197
			    CWBackingStore | CWOverrideRedirect, &winattr);
40759 ripley 2198
    Rsync(DE);
13974 hornik 2199
 
2200
    /* this next sequence makes sure the window is up and ready before
2201
       you start drawing in it */
2202
 
2203
    XNextEvent(iodisplay, &ioevent);
2204
    if (ioevent.xany.type == Expose) {
2205
	while (ioevent.xexpose.count)
2206
	    XNextEvent(iodisplay, &ioevent);
2207
    }
40759 ripley 2208
    XGetWindowAttributes(iodisplay, DE->iowindow, &attribs);
2209
    DE->bwidth = attribs.border_width;
2210
    DE->fullwindowWidth = attribs.width;
2211
    DE->fullwindowHeight = attribs.height;
13974 hornik 2212
 
2213
 
2214
    /* set the active rectangle to be the upper left one */
40759 ripley 2215
    DE->crow = 1;
2216
    DE->ccol = 1;
13974 hornik 2217
    CellModified = FALSE;
40759 ripley 2218
    XSaveContext(iodisplay, DE->iowindow, deContext, (caddr_t) DE);
13974 hornik 2219
    return FALSE;/* success */
2220
}
2221
 
2222
/* MAC/X11 BASICS */
2223
 
40759 ripley 2224
static void bell()
13974 hornik 2225
{
2226
    XBell(iodisplay, 20);
2227
}
2228
 
40759 ripley 2229
static void cleararea(DEstruct DE, int xpos, int ypos, int width, int height)
13974 hornik 2230
{
40759 ripley 2231
    XClearArea(iodisplay, DE->iowindow, xpos, ypos, width, height, 0);
13974 hornik 2232
}
2233
 
40759 ripley 2234
static void clearwindow(DEstruct DE)
13974 hornik 2235
{
40759 ripley 2236
    XClearWindow(iodisplay, DE->iowindow);
13974 hornik 2237
}
2238
 
40759 ripley 2239
static void copyarea(DEstruct DE, int src_x, int src_y, int dest_x, int dest_y)
13974 hornik 2240
{
2241
    int mx = max(src_x, dest_x), my = max(src_y, dest_y);
40759 ripley 2242
    XCopyArea(iodisplay, DE->iowindow, DE->iowindow, DE->iogc,
2243
	      src_x, src_y,
2244
	      DE->fullwindowWidth - mx, DE->fullwindowHeight - my,
13974 hornik 2245
	      dest_x, dest_y);
40759 ripley 2246
    Rsync(DE);
13974 hornik 2247
}
2248
 
40759 ripley 2249
static void copyH(DEstruct DE, int src_x, int dest_x, int width)
13974 hornik 2250
{
40759 ripley 2251
    XCopyArea(iodisplay, DE->iowindow, DE->iowindow, DE->iogc,
2252
	      src_x+DE->bwidth, DE->hht,
2253
	      width, DE->windowHeight+1, dest_x+DE->bwidth, DE->hht);
13974 hornik 2254
}
2255
 
40759 ripley 2256
static void drawrectangle(DEstruct DE,
2257
			  int xpos, int ypos, int width, int height,
13974 hornik 2258
			  int lwd, int fore)
2259
{
36044 ripley 2260
#ifdef USE_Xt
13974 hornik 2261
    if (fore == 0)
40759 ripley 2262
	XSetForeground(iodisplay, DE->iogc, xdev.background);
36044 ripley 2263
    else
40759 ripley 2264
	XSetForeground(iodisplay, DE->iogc, xdev.foreground);
36044 ripley 2265
#else
2266
    if (fore == 0)
40759 ripley 2267
	XSetForeground(iodisplay, DE->iogc,
2268
		       WhitePixel(iodisplay, DefaultScreen(iodisplay)));
13974 hornik 2269
    else
40759 ripley 2270
	XSetForeground(iodisplay, DE->iogc,
2271
		       BlackPixel(iodisplay, DefaultScreen(iodisplay)));
36044 ripley 2272
#endif
40759 ripley 2273
    XSetLineAttributes(iodisplay, DE->iogc, lwd, LineSolid,
2274
		       CapRound, JoinRound);
2275
    XDrawRectangle(iodisplay, DE->iowindow, DE->iogc, xpos, ypos,
2276
		   width, height);
13974 hornik 2277
}
2278
 
40759 ripley 2279
static void drawtext(DEstruct DE, int xpos, int ypos, char *text, int len)
13974 hornik 2280
{
32677 ripley 2281
    if(mbcslocale)
32471 ripley 2282
#ifdef HAVE_XUTF8DRAWIMAGESTRING
45475 ripley 2283
	if(utf8locale)
40759 ripley 2284
	    Xutf8DrawImageString(iodisplay, DE->iowindow, font_set,
2285
				 DE->iogc, xpos, ypos,text, len);
45475 ripley 2286
	else
32471 ripley 2287
#endif
40759 ripley 2288
	    XmbDrawImageString(iodisplay, DE->iowindow, font_set,
2289
			       DE->iogc, xpos, ypos,text, len);
32424 ripley 2290
    else
40759 ripley 2291
	XDrawImageString(iodisplay, DE->iowindow, DE->iogc,
2292
			 xpos, ypos, text, len);
2293
    Rsync(DE);
13974 hornik 2294
}
2295
 
40759 ripley 2296
static void Rsync(DEstruct DE)
13974 hornik 2297
{
2298
    XSync(iodisplay, 0);
2299
}
2300
 
41831 rgentlem 2301
static int textwidth(DEstruct DE, const char *text, int nchar)
13974 hornik 2302
{
41831 rgentlem 2303
    int ans;
2304
    char *buf = CallocCharBuf(nchar);
2305
    strncpy(buf, text, nchar);
35844 ripley 2306
    if(mbcslocale) {
32471 ripley 2307
#ifdef HAVE_XUTF8TEXTESCAPEMENT
45475 ripley 2308
	if (utf8locale)
41831 rgentlem 2309
	    ans = Xutf8TextEscapement(font_set, buf, nchar);
45475 ripley 2310
	else
32424 ripley 2311
#endif
41831 rgentlem 2312
	    ans = XmbTextEscapement(font_set, buf, nchar);
45475 ripley 2313
	Free(buf);
2314
	return ans;
35844 ripley 2315
    }
41831 rgentlem 2316
    ans = XTextWidth(DE->font_info, buf, nchar);
2317
    Free(buf);
2318
    return ans;
13974 hornik 2319
}
2320
 
2321
/* Menus */
2322
 
40759 ripley 2323
void popupmenu(DEstruct DE, int x_pos, int y_pos, int col, int row)
13974 hornik 2324
{
40759 ripley 2325
    int i, button, popupcol = col + DE->colmin - 1;
41831 rgentlem 2326
    const char *name;
2327
    char clab[20];
13974 hornik 2328
    XEvent event;
2329
    Window selected_pane;
2330
    SEXP tvec;
2331
 
34639 ripley 2332
    XMoveWindow(iodisplay, menuwindow, x_pos, y_pos);
13974 hornik 2333
    XMapSubwindows(iodisplay, menuwindow);
2334
    XMapRaised(iodisplay, menuwindow);
2335
 
2336
    /* now fill in the menu panes with the correct information */
2337
 
40759 ripley 2338
    if (popupcol > DE->xmaxused) {
24274 ripley 2339
	/* extend work, names and lens */
40759 ripley 2340
	REPROTECT(DE->work = lengthgets(DE->work, popupcol), DE->wpi);
2341
	REPROTECT(DE->names = lengthgets(DE->names, popupcol), DE->npi);
2342
	for (i = DE->xmaxused+1; i < popupcol; i++) {
24274 ripley 2343
	    sprintf(clab, "var%d", i + 1);
40759 ripley 2344
	    SET_STRING_ELT(DE->names, i, mkChar(clab));
24274 ripley 2345
	}
40759 ripley 2346
	REPROTECT(DE->lens = lengthgets(DE->lens, popupcol), DE->lpi);
2347
	DE->xmaxused = popupcol;
24274 ripley 2348
    }
40759 ripley 2349
    tvec = VECTOR_ELT(DE->work, popupcol - 1);
2350
    name = CHAR(STRING_ELT(DE->names, popupcol - 1));
34639 ripley 2351
    if(mbcslocale)
2352
#ifdef HAVE_XUTF8DRAWSTRING
45475 ripley 2353
	if(utf8locale)
34639 ripley 2354
	    Xutf8DrawString(iodisplay,
2355
			    menupanes[0],
40759 ripley 2356
			    font_set, DE->iogc, 3, DE->box_h - 3, name,
59764 ripley 2357
			    (int) strlen(name));
34639 ripley 2358
	else
2359
#endif
2360
	    XmbDrawString(iodisplay,
2361
			  menupanes[0],
40759 ripley 2362
			  font_set, DE->iogc, 3, DE->box_h - 3, name,
59764 ripley 2363
			  (int) strlen(name));
34639 ripley 2364
    else
45475 ripley 2365
	XDrawString(iodisplay,
40759 ripley 2366
		    menupanes[0], DE->iogc, 3, DE->box_h - 3, name,
59764 ripley 2367
		    (int) strlen(name));
13974 hornik 2368
    for (i = 1; i < 4; i++)
49591 ripley 2369
	if(mbcslocale)
34639 ripley 2370
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2371
	    if(utf8locale)
2372
		Xutf8DrawString(iodisplay,
2373
				menupanes[i],
2374
				font_set, DE->iogc, 3, DE->box_h - 3,
59764 ripley 2375
				menu_label[i - 1], (int) strlen(menu_label[i - 1]));
49591 ripley 2376
	    else
2377
#endif
2378
		XmbDrawString(iodisplay,
2379
			      menupanes[i],
2380
			      font_set, DE->iogc, 3, DE->box_h - 3,
59764 ripley 2381
			      menu_label[i - 1], (int) strlen(menu_label[i - 1]));
34639 ripley 2382
	else
49591 ripley 2383
	    XDrawString(iodisplay,
2384
			menupanes[i], DE->iogc, 3, DE->box_h - 3,
59764 ripley 2385
			menu_label[i - 1], (int) strlen(menu_label[i - 1]));
34639 ripley 2386
 
24274 ripley 2387
    if (isNull(tvec) || TYPEOF(tvec) == REALSXP)
49591 ripley 2388
	if(mbcslocale)
34639 ripley 2389
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2390
	    if(utf8locale)
2391
		Xutf8DrawString(iodisplay,
2392
				menupanes[1],
2393
				font_set, DE->iogc, 0, DE->box_h - 3,
2394
				"*", 1);
2395
	    else
2396
#endif
2397
		XmbDrawString(iodisplay,
2398
			      menupanes[1],
2399
			      font_set, DE->iogc, 0, DE->box_h - 3,
2400
			      "*", 1);
34639 ripley 2401
	else
49591 ripley 2402
	    XDrawString(iodisplay, menupanes[1], DE->iogc, 0, DE->box_h - 3,
34639 ripley 2403
			"*", 1);
13974 hornik 2404
    else
49591 ripley 2405
	if(mbcslocale)
34639 ripley 2406
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2407
	    if(utf8locale)
2408
		Xutf8DrawString(iodisplay,
2409
				menupanes[2],
2410
				font_set, DE->iogc, 0, DE->box_h - 3,
2411
				"*", 1);
2412
	    else
2413
#endif
2414
		XmbDrawString(iodisplay,
2415
			      menupanes[2],
2416
			      font_set, DE->iogc, 0, DE->box_h - 3,
2417
			      "*", 1);
34639 ripley 2418
	else
49591 ripley 2419
	    XDrawString(iodisplay, menupanes[2], DE->iogc, 0, DE->box_h - 3,
34639 ripley 2420
			"*", 1);
13974 hornik 2421
 
2422
/*
2423
  start an event loop; we're looking for a button press and a button
2424
  release in the same window
2425
*/
2426
 
2427
    while (1) {
2428
	XNextEvent(iodisplay, &event);
34639 ripley 2429
 
2430
	/* event is processed with input method */
2431
 
13974 hornik 2432
	if (event.type == ButtonPress) {
2433
	    button = event.xbutton.button;
2434
	    selected_pane = event.xbutton.window;
2435
	    for (i = 0; selected_pane != menupanes[i]; i++)
53324 ripley 2436
		if (i >= 3) goto done;
13974 hornik 2437
	    while (1) {
2438
		while (XCheckTypedEvent(iodisplay, ButtonPress, &event));
2439
		XMaskEvent(iodisplay, ButtonReleaseMask, &event);
2440
		if (event.xbutton.button == button)
2441
		    break;
2442
	    }
2443
	    if (selected_pane == event.xbutton.window) {
2444
		for (i = 0; selected_pane != menupanes[i]; i++);
2445
		switch (i) {
2446
		case 0:
2447
		    bell();
2448
		    break;
2449
		case 1:
32424 ripley 2450
		    if (isNull(tvec))
40759 ripley 2451
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2452
				       ssNewVector(REALSXP, 100));
2453
		    else
40759 ripley 2454
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2455
				       coerceVector(tvec, REALSXP));
13974 hornik 2456
		    goto done;
2457
		case 2:
32424 ripley 2458
		    if (isNull(tvec))
40759 ripley 2459
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2460
				       ssNewVector(STRSXP, 100));
40747 ripley 2461
		    else {
40759 ripley 2462
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2463
				       coerceVector(tvec, STRSXP));
40747 ripley 2464
		    }
40759 ripley 2465
 
13974 hornik 2466
		    goto done;
2467
		case 3:
40759 ripley 2468
		    closerect(DE);
2469
		    DE->ccol = col;
2470
		    DE->crow = 0;
2471
		    clearrect(DE);
13974 hornik 2472
		    goto done;
2473
		}
2474
	    }
2475
	}
45475 ripley 2476
	/* this doesn't work and perhaps I should move it up to the
2477
	   main control loop */
13974 hornik 2478
	else if (event.type == Expose) {
2479
	    if (event.xexpose.window == menuwindow) {
40759 ripley 2480
		XDrawString(iodisplay, menupanes[0], DE->iogc, 3,
59764 ripley 2481
			    DE->box_h - 3, name, (int) strlen(name));
13974 hornik 2482
		for (i = 1; i < 4; i++)
40759 ripley 2483
		    XDrawString(iodisplay, menupanes[i], DE->iogc, 3,
2484
				DE->box_h - 3,
59764 ripley 2485
				menu_label[i - 1], (int) strlen(menu_label[i - 1]));
13974 hornik 2486
	    }
2487
	}
2488
    }
49591 ripley 2489
done:
40759 ripley 2490
    popdownmenu(DE);
2491
    highlightrect(DE);
13974 hornik 2492
}
2493
 
40759 ripley 2494
void popdownmenu(DEstruct DE)
13974 hornik 2495
{
2496
    XUnmapWindow(iodisplay, menuwindow);
2497
    XUnmapSubwindows(iodisplay, menuwindow);
2498
}
2499
 
40759 ripley 2500
static void copycell(DEstruct DE)
13974 hornik 2501
{
34639 ripley 2502
  /*
2503
   * whichrow = crow + colmin - 1 => whichrow = crow + rowmin - 1
2504
   *                   ^^^                             ^^^
2505
   */
40759 ripley 2506
    int i, whichrow = DE->crow + DE->rowmin - 1,
2507
	whichcol = DE->ccol + DE->colmin -1;
13974 hornik 2508
    SEXP tmp;
32424 ripley 2509
 
13974 hornik 2510
    if (whichrow == 0) {
2511
	/* won't have  cell here */
2512
    } else {
2513
	strcpy(copycontents, "");
40759 ripley 2514
	if (length(DE->work) >= whichcol) {
2515
	    tmp = VECTOR_ELT(DE->work, whichcol - 1);
13974 hornik 2516
	    if (tmp != R_NilValue &&
28786 ripley 2517
		(i = whichrow - 1) < LENGTH(tmp) ) {
54049 ripley 2518
		PrintDefaults();
45475 ripley 2519
		if (TYPEOF(tmp) == REALSXP) {
34639 ripley 2520
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2521
				BOOSTED_BUF_SIZE-1);
2522
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
45475 ripley 2523
		} else if (TYPEOF(tmp) == STRSXP) {
2524
		    if (STRING_ELT(tmp, i) != ssNA_STRING) {
34639 ripley 2525
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2526
				BOOSTED_BUF_SIZE-1);
2527
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
2528
		    }
13974 hornik 2529
		}
2530
	    }
2531
	}
2532
    }
40759 ripley 2533
    highlightrect(DE);
13974 hornik 2534
}
2535
 
40759 ripley 2536
static void pastecell(DEstruct DE, int row, int col)
13974 hornik 2537
{
40759 ripley 2538
    downlightrect(DE);
2539
    DE->crow = row; DE->ccol = col;
13974 hornik 2540
    if (strlen(copycontents)) {
2541
	strcpy(buf, copycontents);
59764 ripley 2542
	clength = (int) strlen(copycontents);
13974 hornik 2543
	bufp = buf + clength;
2544
	CellModified = TRUE;
2545
    }
40759 ripley 2546
    closerect(DE);
2547
    highlightrect(DE);
13974 hornik 2548
}
34639 ripley 2549
 
40759 ripley 2550
static void calc_pre_edit_pos(DEstruct DE)
34639 ripley 2551
{
2552
    XVaNestedList   xva_nlist;
2553
    XPoint          xpoint;
2554
    int i;
2555
    int w;
2556
 
62314 ripley 2557
    xpoint.x = (short) DE->boxw[0];
40759 ripley 2558
    for (i = 1; i < DE->ccol; i++)
2559
	xpoint.x += BOXW(DE->colmin + i - 1);
34639 ripley 2560
#ifdef HAVE_XUTF8TEXTESCAPEMENT
2561
    if(utf8locale)
2562
	w = Xutf8TextEscapement(font_set, buf, clength);
2563
    else
2564
#endif
2565
	w = XmbTextEscapement(font_set, buf, clength);
40759 ripley 2566
    xpoint.x += (w > BOXW(DE->colmin + DE->ccol - 1)) ?
2567
	BOXW(DE->colmin + DE->ccol - 1) : w;
2568
    xpoint.x += DE->text_offset;
62314 ripley 2569
    xpoint.y = (short)(DE->hht + (DE->crow+1) * DE->box_h - DE->text_offset);
34639 ripley 2570
 
2571
    /*
2572
      <FIXME>
2573
      I may depend on implementation of XIM, but I do not obey,
2574
      setting value, and investigation in various implementation
2575
      system is need.
2576
      It is only a problem in an appearance.
2577
    */
2578
    xva_nlist = XVaCreateNestedList(0,
2579
				    XNSpotLocation, &xpoint,
2580
				    XNFontSet, font_set,
2581
				    NULL);
2582
    XSetICValues(ioic, XNPreeditAttributes, xva_nlist, NULL);
2583
 
2584
    XFree(xva_nlist);
2585
    return;
2586
}
2587
 
2588
/* last character bytes */
2589
static int last_wchar_bytes(char *str)
2590
{
2591
    wchar_t   wcs[BOOSTED_BUF_SIZE];
2592
    mbstate_t mb_st;
2593
    int cnt;
2594
    char last_mbs[8];
2595
    char *mbs;
39658 ripley 2596
    size_t bytes;
34639 ripley 2597
 
2598
    mbs = (str == NULL) ? buf : str;
2599
 
2600
    memset(wcs, 0 ,sizeof(wcs));
2601
    memset(&mb_st,0, sizeof(mbstate_t));
2602
 
62627 ripley 2603
    if((int)-1 == (cnt = (int)mbsrtowcs(wcs, (const char **)&mbs,
2604
					(int) strlen(mbs), &mb_st))) {
45475 ripley 2605
	return 0;
34639 ripley 2606
    }
2607
    if(wcs[0] == L'\0') return 0;
2608
 
2609
    memset(last_mbs, 0, sizeof(last_mbs));
40756 ripley 2610
    bytes = wcrtomb(last_mbs, wcs[cnt-1], &mb_st); /* -Wall */
62295 ripley 2611
    return (int) bytes;
34639 ripley 2612
}
60708 ripley 2613