The R Project SVN R

Rev

Rev 51659 | 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
44345 ripley 4
 *  Copyright (C) 1998--2008  Robert Gentleman, Ross Ihaka and the
13974 hornik 5
 *                            R Development Core Team
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
42307 ripley 18
 *  along with this program; if not, a copy is available at
19
 *  http://www.r-project.org/Licenses/
13974 hornik 20
 */
21
 
34639 ripley 22
/* <UTF8>
32555 ripley 23
   Used XTextWidth and XDrawText, so need to use fontsets
32422 ripley 24
 
32555 ripley 25
   Also needed input context.
32432 ripley 26
*/
27
 
34639 ripley 28
/* The version for R 2.1.0 is partly based on patches by
35930 ripley 29
   Ei-ji Nakama <nakama@ki.rim.or.jp> for use with Japanese fonts. */
32429 ripley 30
 
34639 ripley 31
#define DPRINTS(x) printf(#x "=[%s]\n", x)
32
#define DPRINTX(x) printf(#x "=%x\n", x)
33
#define DPRINTD(x) printf(#x "=%d\n", x)
34
 
13974 hornik 35
#ifdef HAVE_CONFIG_H
36
#include <config.h>
37
#endif
38
 
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) ) {
760
		PrintDefaults(R_NilValue);
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';
773
    clength = strlen(buf);
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";
13974 hornik 805
	PrintDefaults(R_NilValue);
34639 ripley 806
 
40759 ripley 807
	w = textwidth(DE, strp, strlen(strp));
808
	for (i = 0; i < INTEGER(DE->lens)[col - 1]; i++) {
34294 ripley 809
	    strp = EncodeElement(tmp, i, 0, '.');
40759 ripley 810
	    w1 = textwidth(DE, strp, strlen(strp));
13974 hornik 811
	    if (w1 > w) w = w1;
812
	}
40759 ripley 813
	if(w < 0.5*DE->box_w) w = 0.5*DE->box_w;
814
	if(w < 0.8*DE->box_w) w+= 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);
41831 rgentlem 850
    printstring(DE, clab, 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);
876
    printstring(DE, rlab, 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;
13974 hornik 903
    PrintDefaults(R_NilValue);
904
    if (TYPEOF(invec) == REALSXP) {
40747 ripley 905
	strp = EncodeElement(invec, vrow, 0, '.');
40759 ripley 906
	printstring(DE ,strp, 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, '.');
40759 ripley 911
	    printstring(DE ,strp, 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);
927
	printstring(DE ,clab, 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));
1122
		printstring(DE ,buf, strlen(buf), 0, wcol, 0);
13974 hornik 1123
	    } else {
40759 ripley 1124
		sprintf(buf, "var%d", DE->ccol);
1125
		printstring(DE ,buf, 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;
1205
    wcsbufw = mbsrtowcs(wcspbuf, (const char **)&p, bufw, NULL);
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;
39658 ripley 1212
	    cnt=wcsrtombs(s,(const wchar_t **)&w_p,sizeof(s)-1,NULL);
34639 ripley 1213
	    s[cnt]='\0';
45475 ripley 1214
	    if (textwidth(DE, s, strlen(s)) < (bw - DE->text_offset)) break;
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;
39658 ripley 1222
	    cnt=wcsrtombs(s,(const wchar_t **)&w_p,sizeof(s)-1,NULL);
34639 ripley 1223
	    s[cnt]='\0';
45475 ripley 1224
	    if (textwidth(DE, s, strlen(s)) < (bw - DE->text_offset)) break;
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;
39658 ripley 1232
    cnt=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... */
35776 ripley 1254
#include <R_ext/rlocale.h>
13974 hornik 1255
 
34639 ripley 1256
/* <FIXME> This is not correct for stateful MBCSs, but that's hard to
32677 ripley 1257
   do as we get a char at a time */
40759 ripley 1258
static void handlechar(DEstruct DE, char *text)
13974 hornik 1259
{
44186 ripley 1260
    int c = text[0], j;
34639 ripley 1261
    wchar_t wcs[BOOSTED_BUF_SIZE];
13974 hornik 1262
 
34639 ripley 1263
    memset(wcs,0,sizeof(wcs));
1264
 
32432 ripley 1265
    if ( c == '\033' ) { /* ESC */
13974 hornik 1266
	CellModified = FALSE;
1267
	clength = 0;
45475 ripley 1268
	bufp = buf;
40759 ripley 1269
	drawelt(DE, DE->crow, DE->ccol);
1270
	cell_cursor_init(DE);
13974 hornik 1271
	return;
1272
    } else
1273
	CellModified = TRUE;
1274
 
1275
    if (clength == 0) {
1276
 
40759 ripley 1277
	if (DE->crow == 0)	                        /* variable name */
13974 hornik 1278
	    currentexp = 3;
1279
	else
40759 ripley 1280
	    switch(get_col_type(DE, DE->ccol + DE->colmin - 1)) {
13974 hornik 1281
	    case NUMERIC:
1282
		currentexp = 1;
1283
		break;
1284
	    default:
1285
		currentexp = 2;
1286
	    }
40759 ripley 1287
	clearrect(DE);
1288
	highlightrect(DE);
13974 hornik 1289
    }
1290
 
34639 ripley 1291
    /* NA number? */
40759 ripley 1292
    if (get_col_type(DE, DE->ccol + DE->colmin - 1) == NUMERIC) {
40754 ripley 1293
	/* input numeric for NA of buffer , suppress NA etc.*/
1294
	if(strcmp(buf, "NA") == 0 || strcmp(buf, "NaN") == 0 ||
1295
	   strcmp(buf, "Inf") == 0 || strcmp(buf, "-Inf") == 0) {
34639 ripley 1296
	    buf[0] = '\0';
1297
	    clength = 0;
1298
	    bufp = buf;
1299
	}
1300
    }
1301
 
32518 ripley 1302
    if (currentexp == 1) {	/* we are parsing a number */
49591 ripley 1303
	char *mbs = text;
1304
	int i, cnt = mbsrtowcs(wcs, (const char **)&mbs, strlen(text)+1, NULL);
34639 ripley 1305
 
49591 ripley 1306
	for(i = 0; i < cnt; i++) {
1307
	    switch (wcs[i]) {
1308
	    case L'-':
1309
		if (nneg == 0) nneg++; else goto donehc;
40747 ripley 1310
	    break;
49591 ripley 1311
	    case L'.':
1312
		if (ndecimal == 0) ndecimal++; else goto donehc;
13974 hornik 1313
	    break;
49591 ripley 1314
	    case L'e':
1315
	    case L'E':
1316
		if (ne == 0) {
1317
		    nneg = ndecimal = 0;	/* might have decimal in exponent */
1318
		    ne++;
1319
		} else goto donehc;
13974 hornik 1320
	    break;
49591 ripley 1321
	    case L'N':
1322
		if(nneg) goto donehc;
1323
	    case L'I':
1324
		inSpecial++;
13974 hornik 1325
	    break;
49591 ripley 1326
	    default:
1327
		if (!inSpecial && !iswdigit(wcs[i])) goto donehc;
1328
		break;
1329
	    }
13974 hornik 1330
	}
32518 ripley 1331
    }
13974 hornik 1332
    if (currentexp == 3) {
40747 ripley 1333
	char *mbs = text;
44186 ripley 1334
	int i, cnt = mbsrtowcs(wcs, (const char **)&mbs, strlen(text)+1, NULL);
40747 ripley 1335
	for(i = 0; i < cnt; i++) {
1336
	    if (iswspace(wcs[i])) goto donehc;
40759 ripley 1337
	    if (clength == 0 && wcs[i] != L'.' && !iswalpha(wcs[i]))
1338
		goto donehc;
40747 ripley 1339
	    else if (wcs[i] != L'.' && !iswalnum(wcs[i])) goto donehc;
1340
	}
13974 hornik 1341
    }
1342
 
34639 ripley 1343
    if (clength+strlen(text) > BOOSTED_BUF_SIZE - MB_CUR_MAX - 1) {
13974 hornik 1344
	warning("dataentry: expression too long");
1345
	goto donehc;
1346
    }
1347
 
42804 maechler 1348
    /* as originally written, this left an undefined byte at
1349
       the end of bufp, followed by a zero byte; luckily, the storage
1350
       pointed to by bufp had already been zeroed, so the undefined
1351
       byte was in fact zero.  */
1352
    strcpy(bufp, text);
1353
    bufp += (j = strlen(text));
1354
    clength += j;
40759 ripley 1355
    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
13974 hornik 1356
    return;
1357
 
1358
 donehc:
1359
    bell();
1360
}
1361
 
40759 ripley 1362
static void printlabs(DEstruct DE)
13974 hornik 1363
{
41831 rgentlem 1364
    char clab[15];
1365
    const char *p;
13974 hornik 1366
    int i;
1367
 
40759 ripley 1368
    for (i = DE->colmin; i <= DE->colmax; i++) {
1369
	p = get_col_name(DE, i);
1370
	printstring(DE, p, strlen(p), 0, i - DE->colmin + 1, 0);
13974 hornik 1371
    }
40759 ripley 1372
    for (i = DE->rowmin; i <= DE->rowmax; i++) {
1373
	sprintf(clab, DE->labform, i);
1374
	printstring(DE, clab, strlen(clab), i - DE->rowmin + 1, 0, 0);
13974 hornik 1375
    }
1376
}
1377
 
45475 ripley 1378
	       /* ================ X11-specific ================ */
13974 hornik 1379
 
1380
/* find out whether the button click was in the quit box */
1381
static int checkquit(int xw)
1382
{
1383
    if (xw > box_coords[1] && xw < box_coords[0]) return 1;
1384
    if (xw > box_coords[3] && xw < box_coords[2]) return 2;
1385
    if (xw > box_coords[5] && xw < box_coords[4]) return 3;
1386
    return 0;
1387
}
1388
 
1389
/* when a buttonpress event happens find the square that is being
1390
   pointed to if the pointer is in the header we need to see if the
1391
   quit button was pressed and if so quit. This is done by having
32432 ripley 1392
   findcell return an int which is one if we should quit and zero
13974 hornik 1393
   otherwise */
1394
 
40759 ripley 1395
static int findcell(DEstruct DE)
13974 hornik 1396
{
1397
 
1398
    int xw, yw, xr, yr, wcol=0, wrow, i, w;
1399
    unsigned int keys;
1400
    Window root, child;
1401
 
40759 ripley 1402
    closerect(DE);
1403
    XQueryPointer(iodisplay, DE->iowindow, &root, &child,
13974 hornik 1404
		  &xr, &yr, &xw, &yw, &keys);
1405
 
1406
    if (keys & Button1Mask) { /* left click */
1407
 
1408
	/* check to see if the click was in the header */
1409
 
40759 ripley 1410
	if (yw < DE->hht + DE->bwidth) {
13974 hornik 1411
	    i =  checkquit(xw);
1412
	    if (i == 1) return 1;
40759 ripley 1413
	    else if (i == 2) copycell(DE);
1414
	    else if (i == 3) pastecell(DE, DE->crow, DE->ccol);
13974 hornik 1415
	    return 0;
1416
	}
1417
 
32424 ripley 1418
 
13974 hornik 1419
	/* see if it is in the row labels */
40759 ripley 1420
	if (xw < DE->bwidth + DE->boxw[0]) {
13974 hornik 1421
	    bell();
40759 ripley 1422
	    highlightrect(DE);
13974 hornik 1423
	    return 0;
1424
	}
1425
	/* translate to box coordinates */
40759 ripley 1426
	wrow = (yw - DE->bwidth - DE->hht) / DE->box_h;
1427
	w = DE->bwidth + DE->boxw[0];
1428
	for (i = 1; i <= DE->nwide; i++)
1429
	    if((w += BOXW(i+DE->colmin-1)) > xw) {
13974 hornik 1430
		wcol = i;
1431
		break;
1432
	    }
1433
 
1434
	/* next check to see if it is in the column labels */
1435
 
40759 ripley 1436
	if (yw < DE->hht + DE->bwidth + DE->box_h) {
1437
	    if (xw > DE->bwidth + DE->boxw[0])
1438
		popupmenu(DE, xr, yr, wcol, wrow);
13974 hornik 1439
	    else {
40759 ripley 1440
		highlightrect(DE);
13974 hornik 1441
		bell();
1442
	    }
40759 ripley 1443
	} else if (wrow > DE->nhigh - 1 || wcol > DE->nwide -1) {
13974 hornik 1444
		/* off the grid */
40759 ripley 1445
		highlightrect(DE);
13974 hornik 1446
		bell();
40759 ripley 1447
	} else if (wcol != DE->ccol || wrow != DE->crow) {
1448
	    DE->ccol = wcol;
1449
	    DE->crow = wrow;
13974 hornik 1450
	}
1451
    }
1452
    if (keys & Button2Mask) { /* Paste */
1453
	int row, col = 0;
32424 ripley 1454
 
40759 ripley 1455
	if (yw < DE->hht + DE->bwidth || xw < DE->bwidth + DE->boxw[0])
1456
	    return 0;
13974 hornik 1457
 
1458
	/* translate to box coordinates */
40759 ripley 1459
	row = (yw - DE->bwidth - DE->hht) / DE->box_h;
1460
	w = DE->bwidth + DE->boxw[0];
1461
	for (i = 1; i <= DE->nwide; i++)
1462
	    if ((w += BOXW(i+DE->colmin-1)) > xw) {
13974 hornik 1463
		col = i;
1464
		break;
1465
	    }
40759 ripley 1466
	pastecell(DE, row, col);
13974 hornik 1467
    }
40759 ripley 1468
    highlightrect(DE);
13974 hornik 1469
    return 0;
1470
}
1471
 
1472
 
1473
/* Event Loop Functions */
45475 ripley 1474
#define mouseDown	ButtonPress
40756 ripley 1475
#define keyDown		KeyPress
1476
#define activateEvt	MapNotify
1477
#define updateEvt	Expose
13974 hornik 1478
 
40759 ripley 1479
static void eventloop(DEstruct DE)
13974 hornik 1480
{
1481
    int done;
1482
    DEEvent ioevent;
46169 ripley 1483
    caddr_t temp;
13974 hornik 1484
 
1485
    done = 0;
1486
    while (done == 0) {
45475 ripley 1487
	XNextEvent(iodisplay, &ioevent);
46169 ripley 1488
	XFindContext(iodisplay, ioevent.xany.window, deContext, &temp);
1489
	if ((DEstruct) temp != DE) { /* so a View window */
1490
	    if (WhichEvent(ioevent) == Expose)
1491
		drawwindow((DEstruct) temp);
1492
	} else {
45475 ripley 1493
	    if (XFilterEvent(&ioevent, None)){
40754 ripley 1494
		if(ioic){
1495
		    XSetICFocus(ioic);
1496
		    if (ioim_style & XIMPreeditPosition)
40759 ripley 1497
			calc_pre_edit_pos(DE);
40754 ripley 1498
		}
1499
		continue;
34639 ripley 1500
	    }
1501
 
13974 hornik 1502
	    switch (WhichEvent(ioevent)) {
34639 ripley 1503
	    case keyDown:/* KeyPress */
40759 ripley 1504
		doSpreadKey(DE, 0, &ioevent);
34639 ripley 1505
		break;
45475 ripley 1506
	    case Expose:
40759 ripley 1507
		while(XCheckTypedEvent(iodisplay, Expose, &ioevent))
1508
		    ;
40754 ripley 1509
		/*
1510
		 * XIM on  - KeyPress - Expose
1511
		 * XIM off - KeyPress - KeyRelease
1512
		 * colname change XIM on mode. type Backspace.
1513
		 */
45475 ripley 1514
		if(DE->crow == 0){
40759 ripley 1515
		    drawwindow(DE);
1516
		    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
40747 ripley 1517
		} else {
40759 ripley 1518
		    closerect(DE);
1519
		    drawwindow(DE);
1520
		    cell_cursor_init(DE);
34639 ripley 1521
		}
1522
		break;
1523
	    case activateEvt:/* MapNotify */
45475 ripley 1524
		closerect(DE);
40759 ripley 1525
		drawwindow(DE);
1526
		cell_cursor_init(DE);
45475 ripley 1527
		break;
34639 ripley 1528
	    case mouseDown:/* ButtonPress */
40759 ripley 1529
		if(DE->isEditor) {
1530
		    done  = doMouseDown(DE, &ioevent);
1531
		    cell_cursor_init(DE);
40755 ripley 1532
		}
13974 hornik 1533
		break;
1534
	    case MappingNotify:
1535
		RefreshKeyboardMapping(&ioevent);
1536
		break;
1537
	    case ConfigureNotify:
40759 ripley 1538
		while(XCheckTypedEvent(iodisplay, ConfigureNotify, &ioevent))
1539
		    ;
1540
		doConfigure(DE, &ioevent);
1541
		cell_cursor_init(DE);
13974 hornik 1542
		break;
1543
	    case ClientMessage:
1544
		if(ioevent.xclient.message_type == _XA_WM_PROTOCOLS
40759 ripley 1545
		   && ioevent.xclient.data.l[0] == DE->prot) {
13974 hornik 1546
		    /* user clicked on `close' aka `destroy' */
40754 ripley 1547
		    done = 1;
13974 hornik 1548
		}
1549
		break;
1550
	    }
1551
	}
1552
    }
1553
}
1554
 
40756 ripley 1555
static void R_ProcessX11Events(void *data)
1556
{
40759 ripley 1557
    caddr_t temp;
1558
    DEstruct DE = NULL;
40756 ripley 1559
    DEEvent ioevent;
1560
    int done = 0;
1561
 
46169 ripley 1562
    while (nView && XPending(iodisplay)) {
45475 ripley 1563
	XNextEvent(iodisplay, &ioevent);
40759 ripley 1564
	XFindContext(iodisplay, ioevent.xany.window, deContext, &temp);
1565
	DE = (DEstruct) temp;
40756 ripley 1566
	switch (WhichEvent(ioevent)) {
1567
	case keyDown:/* KeyPress */
40759 ripley 1568
	    doSpreadKey(DE, 0, &ioevent);
40756 ripley 1569
	    break;
1570
	case Expose:
40759 ripley 1571
	    while(XCheckTypedEvent(iodisplay, Expose, &ioevent))
1572
		;
1573
	    drawwindow(DE);
40756 ripley 1574
	    break;
1575
	case MappingNotify:
1576
	    RefreshKeyboardMapping(&ioevent);
1577
	    break;
1578
	case ConfigureNotify:
40759 ripley 1579
	    while(XCheckTypedEvent(iodisplay, ConfigureNotify, &ioevent))
1580
		;
1581
	    doConfigure(DE, &ioevent);
1582
	    cell_cursor_init(DE);
40756 ripley 1583
	    break;
1584
	case activateEvt:/* MapNotify */
1585
	    break;
1586
	case ClientMessage:
1587
	    if(ioevent.xclient.message_type == _XA_WM_PROTOCOLS
40759 ripley 1588
	       && ioevent.xclient.data.l[0] == DE->prot) {
40756 ripley 1589
		/* user clicked on `close' aka `destroy' */
1590
		done = 1;
1591
	    }
1592
	    break;
1593
	}
1594
    }
1595
    if(done) {
40759 ripley 1596
	R_ReleaseObject(DE->lens);
1597
	R_ReleaseObject(DE->work);
1598
	closewin(DE);
1599
	free(DE);
1600
	nView--;
1601
	if(nView == 0) {
46169 ripley 1602
	    /* NB: this is removing the handler that is currently
1603
	       being used: only OK to free here in R > 2.8.0 */
40759 ripley 1604
	    removeInputHandler(&R_InputHandlers,
1605
			       getInputHandler(R_InputHandlers,fdView));
1606
	    fdView = -1;
46169 ripley 1607
	    if(font_set) {
1608
		XFreeFontSet(iodisplay, font_set);
1609
		font_set = NULL;
1610
	    }
40759 ripley 1611
	    XCloseDisplay(iodisplay);
1612
	    iodisplay = NULL;
1613
	}
45475 ripley 1614
 
40756 ripley 1615
    }
1616
}
1617
 
40759 ripley 1618
static int doMouseDown(DEstruct DE, DEEvent * event)
13974 hornik 1619
{
40759 ripley 1620
    return findcell(DE);
13974 hornik 1621
}
1622
 
40759 ripley 1623
static void doSpreadKey(DEstruct DE, int key, DEEvent * event)
13974 hornik 1624
{
1625
    KeySym iokey;
49591 ripley 1626
    char *text = "";
13974 hornik 1627
 
1628
    iokey = GetKey(event);
48544 ripley 1629
    if(DE->isEditor) text = GetCharP(event);
13974 hornik 1630
 
1631
    if (CheckControl(event))
40759 ripley 1632
	doControl(DE, event);
32424 ripley 1633
    else if ((iokey == XK_Return)  || (iokey == XK_KP_Enter) ||
13974 hornik 1634
	     (iokey == XK_Linefeed)|| (iokey == XK_Down))
40759 ripley 1635
	advancerect(DE, DOWN);
13974 hornik 1636
    else if (iokey == XK_Left)
40759 ripley 1637
	advancerect(DE, LEFT);
13974 hornik 1638
    else if (iokey == XK_Right)
40759 ripley 1639
	advancerect(DE, RIGHT);
13974 hornik 1640
    else if (iokey == XK_Up)
40759 ripley 1641
	advancerect(DE, UP);
22718 ripley 1642
#ifdef XK_Page_Up
1643
    else if (iokey == XK_Page_Up) {
40759 ripley 1644
	int i = DE->rowmin - DE->nhigh + 2;
1645
	jumpwin(DE, DE->colmin, max(1, i));
1646
	cell_cursor_init(DE);
13974 hornik 1647
    }
22718 ripley 1648
#elif defined(XK_Prior)
1649
    else if (iokey == XK_Prior) {
40759 ripley 1650
	int i = DE->rowmin - DE->nhigh + 2;
1651
	jumpwin(DE, DE->colmin, max(1, i));
1652
	cell_cursor_init(DE);
13974 hornik 1653
    }
22718 ripley 1654
#endif
1655
#ifdef XK_Page_Down
34639 ripley 1656
    else if (iokey == XK_Page_Down) {
40759 ripley 1657
	if(DE->isEditor)
48544 ripley 1658
	    jumpwin(DE, DE->colmin, DE->rowmax);
40755 ripley 1659
	else {
40759 ripley 1660
	    int i = DE->ymaxused - DE->nhigh + 2;
51659 maechler 1661
            jumpwin(DE, DE->colmin, min(i, DE->rowmax));
40755 ripley 1662
	}
40759 ripley 1663
	cell_cursor_init(DE);
34639 ripley 1664
    }
22718 ripley 1665
#elif defined(XK_Next)
34639 ripley 1666
    else if (iokey == XK_Next) {
48544 ripley 1667
	if(DE->isEditor)
1668
	    jumpwin(DE, DE->colmin, DE->rowmax);
1669
	else {
1670
	    int i = DE->ymaxused - DE->nhigh + 2;
51659 maechler 1671
            jumpwin(DE, DE->colmin, min(i, DE->rowmax));
48544 ripley 1672
	}
40759 ripley 1673
	cell_cursor_init(DE);
34639 ripley 1674
    }
13974 hornik 1675
#endif
40759 ripley 1676
    else if (DE->isEditor && (iokey == XK_BackSpace || iokey == XK_Delete)) {
13974 hornik 1677
	if (clength > 0) {
34639 ripley 1678
	    int last_w ;
1679
	    last_w = last_wchar_bytes(NULL);
1680
	    clength -= last_w;
1681
	    bufp -= last_w;
1682
	    *bufp = '\0';
1683
	    CellModified = TRUE;
40759 ripley 1684
	    printstring(DE, buf, clength, DE->crow, DE->ccol, 1);
13974 hornik 1685
	} else bell();
1686
    }
1687
    else if (iokey == XK_Tab) {
40759 ripley 1688
	if(CheckShift(event)) advancerect(DE, LEFT);
1689
	else advancerect(DE, RIGHT);
13974 hornik 1690
    }
1691
    else if (iokey == XK_Home) {
40759 ripley 1692
	jumpwin(DE, 1, 1);
1693
	downlightrect(DE);
1694
	DE->crow = DE->ccol = 1;
1695
	highlightrect(DE);
1696
	cell_cursor_init(DE);
13974 hornik 1697
    }
1698
    else if (iokey == XK_End) {
40759 ripley 1699
	int i = DE->ymaxused - DE->nhigh + 2, j, w = 0 ;
1700
	/* Try to work out which cols we can fit in */
1701
	for(j = DE->xmaxused;j >= 0; j--) {
1702
	    w += BOXW(j);
1703
	    if(w > DE->fullwindowWidth) break;
1704
	}
44407 ripley 1705
	jumpwin(DE, min(1 + max(j, 0), DE->xmaxused), max(i, 1));
40759 ripley 1706
	downlightrect(DE);
1707
	DE->crow = DE->ymaxused - DE->rowmin + 1;
1708
	DE->ccol = DE->xmaxused - DE->colmin + 1;
1709
	highlightrect(DE);
1710
	cell_cursor_init(DE);
13974 hornik 1711
    }
1712
    else if (IsModifierKey(iokey)) {
1713
    }
40759 ripley 1714
    else if(DE->isEditor) {
1715
	handlechar(DE, text);
1716
    }
13974 hornik 1717
}
1718
 
1719
 
1720
static int WhichEvent(DEEvent ioevent)
1721
{
1722
    return ioevent.type;
1723
}
1724
 
1725
static KeySym GetKey(DEEvent * event)
1726
{
1727
    char text[1];
1728
    KeySym iokey;
1729
 
31990 ripley 1730
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1731
    return iokey;
1732
}
1733
 
32432 ripley 1734
static char *GetCharP(DEEvent * event)
13974 hornik 1735
{
34639 ripley 1736
    static char text[BOOSTED_BUF_SIZE];
13974 hornik 1737
    KeySym iokey;
1738
 
34639 ripley 1739
    memset(text,0,sizeof(text));
1740
 
32677 ripley 1741
    if(mbcslocale) {
32471 ripley 1742
#ifdef HAVE_XUTF8LOOKUPSTRING
45475 ripley 1743
	if(utf8locale)
34639 ripley 1744
	    Xutf8LookupString(ioic, (XKeyEvent *)event,
1745
			      text, sizeof(text) - clength,
1746
			      &iokey, &status);
1747
	else
32471 ripley 1748
#endif
34639 ripley 1749
	    XmbLookupString(ioic, (XKeyEvent *)event,
1750
			    text, sizeof(text) - clength,
1751
			    &iokey, &status);
32432 ripley 1752
	/* FIXME check the return code */
34639 ripley 1753
	if(status == XBufferOverflow)
1754
	    warning("dataentry: expression too long");
32432 ripley 1755
    } else
34639 ripley 1756
	XLookupString((XKeyEvent *)event,
1757
		      text, sizeof(text) - clength,
1758
		      &iokey, NULL);
32432 ripley 1759
    return text;
13974 hornik 1760
}
1761
 
1762
static int CheckControl(DEEvent * event)
1763
{
1764
    return (*event).xkey.state & ControlMask;
1765
}
1766
 
1767
static int CheckShift(DEEvent * event)
1768
{
1769
    return (*event).xkey.state & ShiftMask;
1770
}
1771
 
40759 ripley 1772
static void doControl(DEstruct DE, DEEvent * event)
13974 hornik 1773
{
1774
    int i;
1775
    char text[1];
1776
    KeySym iokey;
1777
 
1778
    (*event).xkey.state = 0;
31990 ripley 1779
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1780
    /* one row overlap when scrolling: top line <--> bottom line */
1781
    switch (text[0]) {
1782
	case 'b':
40759 ripley 1783
	    i = DE->rowmin - DE->nhigh + 2;
1784
	    jumpwin(DE, DE->colmin, max(1, i));
13974 hornik 1785
	    break;
1786
	case 'f':
40759 ripley 1787
	    jumpwin(DE, DE->colmin, DE->rowmax);
13974 hornik 1788
	    break;
1789
	case 'l':
40759 ripley 1790
	    closerect(DE);
1791
	    for (i = 1 ; i <= min(100, DE->xmaxused); i++)
1792
		DE->boxw[i] = get_col_width(DE, i);
1793
	    closerect(DE);
1794
	    drawwindow(DE);
13974 hornik 1795
	    break;
1796
    }
40759 ripley 1797
    cell_cursor_init(DE);
13974 hornik 1798
}
1799
 
1800
 
40759 ripley 1801
static void doConfigure(DEstruct DE, DEEvent * event)
13974 hornik 1802
{
40759 ripley 1803
    if ((DE->fullwindowWidth != (*event).xconfigure.width) ||
1804
	(DE->fullwindowHeight != (*event).xconfigure.height)) {
1805
	closerect(DE);
1806
	drawwindow(DE);
34639 ripley 1807
    }
13974 hornik 1808
}
1809
 
1810
static void RefreshKeyboardMapping(DEEvent * event)
1811
{
28840 ripley 1812
    XRefreshKeyboardMapping((XMappingEvent *)event);
13974 hornik 1813
}
1814
 
1815
/* Initialize/Close Windows */
1816
 
40759 ripley 1817
void closewin(DEstruct DE)
13974 hornik 1818
{
40759 ripley 1819
    XFreeGC(iodisplay, DE->iogc);
1820
    if(mbcslocale  && DE->isEditor) {
32518 ripley 1821
	XDestroyIC(ioic);
1822
	XCloseIM(ioim);
1823
    }
40759 ripley 1824
    XDestroyWindow(iodisplay, DE->iowindow);
41345 ripley 1825
    /* XCloseDisplay(iodisplay); */
46161 ripley 1826
    Rsync(DE);
13974 hornik 1827
}
1828
 
36044 ripley 1829
#define USE_Xt 1
1830
 
1831
#ifdef USE_Xt
1832
#include <X11/StringDefs.h>
1833
#include <X11/Intrinsic.h>
1834
#include <X11/Shell.h>
1835
typedef struct gx_device_X_s {
1836
    Pixel background, foreground, borderColor;
1837
    Dimension borderWidth;
1838
    String geometry;
1839
} gx_device_X;
1840
 
1841
/* (String) casts are here to suppress warnings about discarding `const' */
1842
#define RINIT(a,b,t,s,o,it,n)\
1843
  {(String)(a), (String)(b), (String)t, sizeof(s),\
1844
   XtOffsetOf(gx_device_X, o), (String)it, (n)}
1845
#define rpix(a,b,o,n)\
1846
  RINIT(a,b,XtRPixel,Pixel,o,XtRString,(XtPointer)(n))
1847
#define rdim(a,b,o,n)\
1848
  RINIT(a,b,XtRDimension,Dimension,o,XtRImmediate,(XtPointer)(n))
1849
#define rstr(a,b,o,n)\
1850
  RINIT(a,b,XtRString,String,o,XtRString,(char*)(n))
1851
 
1852
static XtResource x_resources[] = {
1853
    rpix(XtNforeground, XtCForeground, foreground, "XtDefaultForeground"),
1854
    rpix(XtNbackground, XtCBackground, background, "XtDefaultBackground"),
1855
    rstr(XtNgeometry, XtCGeometry, geometry, NULL),
1856
};
1857
 
1858
static const int x_resource_count = XtNumber(x_resources);
1859
static gx_device_X xdev;
1860
#endif
1861
 
13974 hornik 1862
static int R_X11Err(Display *dsp, XErrorEvent *event)
1863
{
1864
    char buff[1000];
1865
    XGetErrorText(dsp, event->error_code, buff, 1000);
1866
    warning("X11 protocol error: %s", buff);
1867
    return 0;
1868
}
1869
 
1870
static int R_X11IOErr(Display *dsp)
1871
{
1872
    error("X11 fatal IO error: please save work and shut down R");
1873
    return 0; /* but should never get here */
1874
}
1875
 
1876
/* set up the window, print the grid and column/row labels */
1877
 
41831 rgentlem 1878
static Rboolean initwin(DEstruct DE, const char *title) /* TRUE = Error */
13974 hornik 1879
{
40747 ripley 1880
    int i, twidth, w, minwidth, labdigs;
13974 hornik 1881
    int ioscreen;
1882
    unsigned long iowhite, ioblack;
1883
    char digits[] = "123456789.0";
40756 ripley 1884
    char             *font_name="9x15";
13974 hornik 1885
    Window root;
1886
    XEvent ioevent;
1887
    XSetWindowAttributes winattr;
1888
    XWindowAttributes attribs;
34639 ripley 1889
    XSizeHints *hint;
35415 ripley 1890
    unsigned long fevent=0UL;
34639 ripley 1891
    int j,k;
1892
    XVaNestedList   xva_nlist;
1893
    XPoint xpoint;
13974 hornik 1894
 
32424 ripley 1895
    strcpy(copycontents, "");
1896
 
34639 ripley 1897
    if (!XSupportsLocale ())
32424 ripley 1898
	warning("locale not supported by Xlib: some X ops will operate in C locale");
1899
    if (!XSetLocaleModifiers ("")) warning("X cannot set locale modifiers");
1900
 
40759 ripley 1901
    if(!iodisplay) {
1902
	if ((iodisplay = XOpenDisplay(NULL)) == NULL) {
1903
	    warning("unable to open display");
1904
	    return TRUE;
1905
	}
1906
	deContext = XUniqueContext();
1907
	XSetErrorHandler(R_X11Err);
1908
	XSetIOErrorHandler(R_X11IOErr);
32424 ripley 1909
    }
13974 hornik 1910
 
45475 ripley 1911
 
13974 hornik 1912
    /* Get Font Loaded if we can */
1913
 
32677 ripley 1914
    if(mbcslocale) {
32424 ripley 1915
	int  missing_charset_count;
1916
	char **missing_charset_list;
1917
	char *def_string;
34639 ripley 1918
	char opt_fontset_name[512];
1919
 
44345 ripley 1920
	/* options("X11fonts")[1] read font name */
1921
	SEXP opt = GetOption(install("X11fonts"), R_NilValue);
1922
	if(isString(opt)) {
1923
	    const char *s = CHAR(STRING_ELT(opt, 0));
1924
	    sprintf(opt_fontset_name, s, "medium", "r", 12);
1925
	} else strcpy(opt_fontset_name, fontset_name);
34639 ripley 1926
 
46169 ripley 1927
	if(font_set == NULL) {
1928
	    font_set = XCreateFontSet(iodisplay, opt_fontset_name,
1929
				      &missing_charset_list,
1930
				      &missing_charset_count, &def_string);
1931
	    if (missing_charset_count) XFreeStringList(missing_charset_list);
1932
	}
32424 ripley 1933
	if (font_set == NULL) {
44345 ripley 1934
	    warning("unable to create fontset %s", opt_fontset_name);
32424 ripley 1935
	    return TRUE; /* ERROR */
1936
	}
49591 ripley 1937
    } else {
40759 ripley 1938
	DE->font_info = XLoadQueryFont(iodisplay, font_name);
1939
	if (DE->font_info == NULL) {
32424 ripley 1940
	    warning("unable to losd font %s", font_name);
1941
	    return TRUE; /* ERROR */
1942
	}
1943
    }
13974 hornik 1944
 
1945
    /* find out how wide the input boxes should be and set up the
1946
       window size defaults */
1947
 
40759 ripley 1948
    DE->nboxchars = asInteger(GetOption(install("de.cellwidth"), R_GlobalEnv));
1949
    if (DE->nboxchars == NA_INTEGER || DE->nboxchars < 0) DE->nboxchars = 0;
13974 hornik 1950
 
40759 ripley 1951
    twidth = textwidth(DE, digits, strlen(digits));
34639 ripley 1952
 
40759 ripley 1953
    if (DE->nboxchars > 0) twidth = (twidth * DE->nboxchars)/10;
1954
    DE->box_w = twidth + 4;
32677 ripley 1955
    if(mbcslocale) {
32424 ripley 1956
	XFontSetExtents *extent = XExtentsOfFontSet(font_set);
1957
	char **ml;
40759 ripley 1958
	DE->box_h = (extent->max_logical_extent.height)
32424 ripley 1959
	    + (extent->max_logical_extent.height / 5) + 4;
1960
	font_set_cnt = XFontsOfFontSet(font_set, &fs_list, &ml);
40759 ripley 1961
	DE->text_offset = 2 + fs_list[0]->max_bounds.descent;
49591 ripley 1962
    } else {
40759 ripley 1963
	DE->box_h = DE->font_info->max_bounds.ascent
1964
	    + DE->font_info->max_bounds.descent + 4;
1965
	DE->text_offset = 2 + DE->font_info->max_bounds.descent;
32424 ripley 1966
    }
40759 ripley 1967
    DE->windowHeight = 26 * DE->box_h + DE->hht + 2;
24271 ripley 1968
    /* this used to presume 4 chars sufficed for row numbering */
40759 ripley 1969
    labdigs = max(3, 1+floor(log10((double)DE->ymaxused)));
1970
    sprintf(DE->labform, "%%%dd", labdigs);
1971
    DE->boxw[0] = 0.1*labdigs*textwidth(DE, "0123456789", 10) +
1972
	textwidth(DE, " ", 1) + 8;
1973
    for(i = 1; i < 100; i++) DE->boxw[i] = get_col_width(DE, i);
34639 ripley 1974
 
13974 hornik 1975
    /* try for a window width that covers all the columns, or is around
1976
       800 pixels */
40759 ripley 1977
    w = DE->windowWidth = 0;
1978
    for(i = 0; i <= DE->xmaxused; i++) {
1979
	w += DE->boxw[i];
13974 hornik 1980
	if(w > 800) {
40759 ripley 1981
	    DE->windowWidth = w - DE->boxw[i];
13974 hornik 1982
	    break;
1983
	}
1984
    }
40759 ripley 1985
    if(DE->windowWidth == 0) DE->windowWidth = w;
1986
    DE->windowWidth += 2;
13974 hornik 1987
    /* allow enough width for buttons */
40759 ripley 1988
    minwidth = 7.5 * textwidth(DE, "Paste", 5);
1989
    if(DE->windowWidth < minwidth) DE->windowWidth = minwidth;
13974 hornik 1990
 
1991
    ioscreen = DefaultScreen(iodisplay);
1992
    iowhite = WhitePixel(iodisplay, ioscreen);
1993
    ioblack = BlackPixel(iodisplay, ioscreen);
1994
 
1995
 
36044 ripley 1996
    hint = XAllocSizeHints();
34639 ripley 1997
 
1998
    hint->x = 0;
1999
    hint->y = 0;
40759 ripley 2000
    hint->width = DE->windowWidth;
2001
    hint->height = DE->windowHeight;
34639 ripley 2002
    hint->flags = PPosition | PSize;
2003
    /*
2004
     * not necessary?
32518 ripley 2005
    hints.flags = InputHint;
2006
    hints.input = True;
34639 ripley 2007
    */
13974 hornik 2008
    root = DefaultRootWindow(iodisplay);
2009
 
36044 ripley 2010
#ifdef USE_Xt
2011
    {
2012
	XtAppContext app_con;
2013
	Widget toplevel;
2014
	Display *xtdpy;
45475 ripley 2015
	int zero = 0;
36044 ripley 2016
 
2017
	XtToolkitInitialize();
2018
	app_con = XtCreateApplicationContext();
2019
	/* XtAppSetFallbackResources(app_con, x_fallback_resources);*/
2020
	xtdpy = XtOpenDisplay(app_con, NULL, "r_dataentry", "R_dataentry",
2021
			      NULL, 0, &zero, NULL);
2022
	toplevel = XtAppCreateShell(NULL, "R_dataentry",
40759 ripley 2023
				    applicationShellWidgetClass,
36044 ripley 2024
				    xtdpy, NULL, 0);
2025
	XtGetApplicationResources(toplevel, (XtPointer) &xdev,
40759 ripley 2026
				  x_resources,
36044 ripley 2027
				  x_resource_count,
2028
				  NULL, 0);
2029
	XtDestroyWidget(toplevel);
2030
	XtCloseDisplay(xtdpy);
2031
	XtDestroyApplicationContext(app_con);
2032
	if (xdev.geometry != NULL) {
2033
	    char gstr[40];
2034
	    int bitmask;
40759 ripley 2035
 
36044 ripley 2036
	    sprintf(gstr, "%dx%d+%d+%d", hint->width,
2037
		    hint->height, hint->x, hint->y);
2038
	    bitmask = XWMGeometry(iodisplay, DefaultScreen(iodisplay),
40759 ripley 2039
				  xdev.geometry, gstr,
36044 ripley 2040
				  1,
2041
				  hint,
2042
				  &hint->x, &hint->y,
2043
				  &hint->width, &hint->height,
2044
				  &hint->win_gravity);
40759 ripley 2045
 
36044 ripley 2046
	    if (bitmask & (XValue | YValue))
2047
		hint->flags |= USPosition;
40759 ripley 2048
	    if (bitmask & (WidthValue | HeightValue))
36044 ripley 2049
		hint->flags |= USSize;
2050
	}
2051
	ioblack = xdev.foreground;
2052
	iowhite = xdev.background;
2053
    }
2054
#endif
40759 ripley 2055
    if ((DE->iowindow = XCreateSimpleWindow(
32518 ripley 2056
	     iodisplay,
2057
	     root,
34639 ripley 2058
	     hint->x,
2059
	     hint->y,
2060
	     hint->width,
2061
	     hint->height,
40759 ripley 2062
	     DE->bwidth,
32518 ripley 2063
	     ioblack,
2064
	     iowhite)) == 0) {
32424 ripley 2065
	warning("unable to open window for data editor");
13974 hornik 2066
	return TRUE;
32424 ripley 2067
    }
13974 hornik 2068
 
34639 ripley 2069
    /*
40759 ripley 2070
    XSetStandardProperties(iodisplay, DE->iowindow, ioname, ioname, None,
34639 ripley 2071
			   (char **)NULL, 0, iohint);
2072
    */
40759 ripley 2073
    XSetWMNormalHints(iodisplay, DE->iowindow, hint);
34639 ripley 2074
    XFree(hint);
13974 hornik 2075
 
34639 ripley 2076
 
2077
    winattr.backing_store = WhenMapped;
40759 ripley 2078
    XChangeWindowAttributes(iodisplay, DE->iowindow, CWBackingStore,
2079
			    &winattr);
13974 hornik 2080
 
2081
    /* set up protocols so that window manager sends */
2082
    /* me an event when user "destroys" window */
40756 ripley 2083
    if(!_XA_WM_PROTOCOLS)
2084
	_XA_WM_PROTOCOLS = XInternAtom(iodisplay, "WM_PROTOCOLS", 0);
40759 ripley 2085
    DE->prot = XInternAtom(iodisplay, "WM_DELETE_WINDOW", 0);
2086
    XSetWMProtocols(iodisplay, DE->iowindow, &DE->prot, 1);
34639 ripley 2087
    /*
2088
     * not necessary
40759 ripley 2089
    XSetWMHints(iodisplay, DE->iowindow, &hints);
34639 ripley 2090
     */
2091
 
40759 ripley 2092
    DE->iogc = XCreateGC(iodisplay, DE->iowindow, 0, 0);
34639 ripley 2093
 
46169 ripley 2094
    if(mbcslocale && DE->isEditor) {
32518 ripley 2095
	ioim = XOpenIM(iodisplay, NULL, NULL, NULL);
32527 ripley 2096
	if(!ioim) {
40759 ripley 2097
	    XDestroyWindow(iodisplay, DE->iowindow);
32527 ripley 2098
	    XCloseDisplay(iodisplay);
34639 ripley 2099
	    warning("unable to open X Input Method");
2100
	    return TRUE;
32527 ripley 2101
	}
32555 ripley 2102
 
34639 ripley 2103
	/* search supported input style */
2104
	XGetIMValues(ioim, XNQueryInputStyle, &ioim_styles,NULL);
2105
	for(i = 0; i < ioim_styles->count_styles; i++) {
2106
	    for(j = 0; preedit_styles[j]; j++){
2107
		for(k = 0; status_styles[k]; k++){
2108
		    ioim_style = (preedit_styles[j] | status_styles[k]);
2109
		    if( ioim_styles->supported_styles[i] == ioim_style) {
2110
			goto loop_out;
2111
		    }
2112
		}
2113
	    }
2114
	}
2115
    loop_out:
2116
 
2117
	/* create input context */
2118
	xpoint.x = 0; xpoint.y=0;
2119
	xva_nlist = XVaCreateNestedList(0, XNFontSet, font_set,
2120
					XNSpotLocation, &xpoint, NULL);
2121
 
2122
	ioic = XCreateIC(ioim,
45475 ripley 2123
			 XNInputStyle, ioim_style,
40759 ripley 2124
			 XNClientWindow,DE->iowindow,
2125
			 XNFocusWindow,DE->iowindow,
34639 ripley 2126
			 XNPreeditAttributes, xva_nlist,
2127
			 XNStatusAttributes, xva_nlist,
32518 ripley 2128
			 NULL);
34639 ripley 2129
	XFree(xva_nlist);
32518 ripley 2130
	if(!ioic) {
2131
	    XCloseIM(ioim);
40759 ripley 2132
	    XDestroyWindow(iodisplay, DE->iowindow);
32518 ripley 2133
	    XCloseDisplay(iodisplay);
34639 ripley 2134
	    warning("unable to open X Input Context");
2135
	    return TRUE;
32518 ripley 2136
	}
34639 ripley 2137
 
2138
	/* get XIM processes event. */
2139
	XGetICValues(ioic, XNFilterEvents, &fevent, NULL);
32518 ripley 2140
    }
13974 hornik 2141
 
32677 ripley 2142
    if(!mbcslocale)
40759 ripley 2143
	XSetFont(iodisplay, DE->iogc, DE->font_info->fid);
49591 ripley 2144
 
40759 ripley 2145
    XSetBackground(iodisplay, DE->iogc, iowhite);
2146
    XSetForeground(iodisplay, DE->iogc, ioblack);
2147
    XSetLineAttributes(iodisplay, DE->iogc, 1, LineSolid, CapRound,
2148
		       JoinRound);
32555 ripley 2149
 
34639 ripley 2150
    /*
40759 ripley 2151
    XSelectInput(iodisplay, DE->iowindow,
32555 ripley 2152
		 ButtonPressMask | KeyPressMask
34639 ripley 2153
		 | ExposureMask | StructureNotifyMask | fevent);
2154
    */
2155
 
40759 ripley 2156
    XSelectInput(iodisplay, DE->iowindow,
34639 ripley 2157
		 ButtonPressMask
2158
		 | KeyPressMask
2159
		 | StructureNotifyMask
2160
		 | ExposureMask
2161
		 | EnterWindowMask
2162
		 | LeaveWindowMask
2163
		 | fevent);
40759 ripley 2164
    XMapRaised(iodisplay, DE->iowindow);
32555 ripley 2165
 
13974 hornik 2166
    /* now set up the menu-window, for now use the same text
2167
       dimensions as above */
2168
 
34639 ripley 2169
    /* font size consideration */
2170
    for(i = 0; i < (sizeof(menu_label)/sizeof(char *)); i++)
40759 ripley 2171
	twidth = (twidth<textwidth(DE, menu_label[i],strlen(menu_label[i]))) ?
2172
	    textwidth(DE, menu_label[i],strlen(menu_label[i])) : twidth;
34639 ripley 2173
 
13974 hornik 2174
    menuwindow = XCreateSimpleWindow(iodisplay, root, 0, 0, twidth,
40759 ripley 2175
				     4 * DE->box_h, 2, ioblack, iowhite);
13974 hornik 2176
    for (i = 0; i < 4; i++) {
2177
	menupanes[i] = XCreateSimpleWindow(iodisplay, menuwindow, 0,
40759 ripley 2178
					   DE->box_h * i, twidth, DE->box_h,
13974 hornik 2179
					   1, ioblack, iowhite);
2180
	XSelectInput(iodisplay, menupanes[i],
34639 ripley 2181
		     ButtonPressMask | ButtonReleaseMask | ExposureMask
2182
		     );
13974 hornik 2183
    }
2184
 
2185
    /* XMapSubwindows(iodisplay, menuwindow); */
2186
 
2187
 
40759 ripley 2188
    XStoreName(iodisplay, DE->iowindow, title);
13974 hornik 2189
    winattr.override_redirect = True;
2190
    XChangeWindowAttributes(iodisplay, menuwindow,
2191
			    CWBackingStore | CWOverrideRedirect, &winattr);
40759 ripley 2192
    Rsync(DE);
13974 hornik 2193
 
2194
    /* this next sequence makes sure the window is up and ready before
2195
       you start drawing in it */
2196
 
2197
    XNextEvent(iodisplay, &ioevent);
2198
    if (ioevent.xany.type == Expose) {
2199
	while (ioevent.xexpose.count)
2200
	    XNextEvent(iodisplay, &ioevent);
2201
    }
40759 ripley 2202
    XGetWindowAttributes(iodisplay, DE->iowindow, &attribs);
2203
    DE->bwidth = attribs.border_width;
2204
    DE->fullwindowWidth = attribs.width;
2205
    DE->fullwindowHeight = attribs.height;
13974 hornik 2206
 
2207
 
2208
    /* set the active rectangle to be the upper left one */
40759 ripley 2209
    DE->crow = 1;
2210
    DE->ccol = 1;
13974 hornik 2211
    CellModified = FALSE;
40759 ripley 2212
    XSaveContext(iodisplay, DE->iowindow, deContext, (caddr_t) DE);
13974 hornik 2213
    return FALSE;/* success */
2214
}
2215
 
2216
/* MAC/X11 BASICS */
2217
 
40759 ripley 2218
static void bell()
13974 hornik 2219
{
2220
    XBell(iodisplay, 20);
2221
}
2222
 
40759 ripley 2223
static void cleararea(DEstruct DE, int xpos, int ypos, int width, int height)
13974 hornik 2224
{
40759 ripley 2225
    XClearArea(iodisplay, DE->iowindow, xpos, ypos, width, height, 0);
13974 hornik 2226
}
2227
 
40759 ripley 2228
static void clearwindow(DEstruct DE)
13974 hornik 2229
{
40759 ripley 2230
    XClearWindow(iodisplay, DE->iowindow);
13974 hornik 2231
}
2232
 
40759 ripley 2233
static void copyarea(DEstruct DE, int src_x, int src_y, int dest_x, int dest_y)
13974 hornik 2234
{
2235
    int mx = max(src_x, dest_x), my = max(src_y, dest_y);
40759 ripley 2236
    XCopyArea(iodisplay, DE->iowindow, DE->iowindow, DE->iogc,
2237
	      src_x, src_y,
2238
	      DE->fullwindowWidth - mx, DE->fullwindowHeight - my,
13974 hornik 2239
	      dest_x, dest_y);
40759 ripley 2240
    Rsync(DE);
13974 hornik 2241
}
2242
 
40759 ripley 2243
static void copyH(DEstruct DE, int src_x, int dest_x, int width)
13974 hornik 2244
{
40759 ripley 2245
    XCopyArea(iodisplay, DE->iowindow, DE->iowindow, DE->iogc,
2246
	      src_x+DE->bwidth, DE->hht,
2247
	      width, DE->windowHeight+1, dest_x+DE->bwidth, DE->hht);
13974 hornik 2248
}
2249
 
40759 ripley 2250
static void drawrectangle(DEstruct DE,
2251
			  int xpos, int ypos, int width, int height,
13974 hornik 2252
			  int lwd, int fore)
2253
{
36044 ripley 2254
#ifdef USE_Xt
13974 hornik 2255
    if (fore == 0)
40759 ripley 2256
	XSetForeground(iodisplay, DE->iogc, xdev.background);
36044 ripley 2257
    else
40759 ripley 2258
	XSetForeground(iodisplay, DE->iogc, xdev.foreground);
36044 ripley 2259
#else
2260
    if (fore == 0)
40759 ripley 2261
	XSetForeground(iodisplay, DE->iogc,
2262
		       WhitePixel(iodisplay, DefaultScreen(iodisplay)));
13974 hornik 2263
    else
40759 ripley 2264
	XSetForeground(iodisplay, DE->iogc,
2265
		       BlackPixel(iodisplay, DefaultScreen(iodisplay)));
36044 ripley 2266
#endif
40759 ripley 2267
    XSetLineAttributes(iodisplay, DE->iogc, lwd, LineSolid,
2268
		       CapRound, JoinRound);
2269
    XDrawRectangle(iodisplay, DE->iowindow, DE->iogc, xpos, ypos,
2270
		   width, height);
13974 hornik 2271
}
2272
 
40759 ripley 2273
static void drawtext(DEstruct DE, int xpos, int ypos, char *text, int len)
13974 hornik 2274
{
32677 ripley 2275
    if(mbcslocale)
32471 ripley 2276
#ifdef HAVE_XUTF8DRAWIMAGESTRING
45475 ripley 2277
	if(utf8locale)
40759 ripley 2278
	    Xutf8DrawImageString(iodisplay, DE->iowindow, font_set,
2279
				 DE->iogc, xpos, ypos,text, len);
45475 ripley 2280
	else
32471 ripley 2281
#endif
40759 ripley 2282
	    XmbDrawImageString(iodisplay, DE->iowindow, font_set,
2283
			       DE->iogc, xpos, ypos,text, len);
32424 ripley 2284
    else
40759 ripley 2285
	XDrawImageString(iodisplay, DE->iowindow, DE->iogc,
2286
			 xpos, ypos, text, len);
2287
    Rsync(DE);
13974 hornik 2288
}
2289
 
40759 ripley 2290
static void Rsync(DEstruct DE)
13974 hornik 2291
{
2292
    XSync(iodisplay, 0);
2293
}
2294
 
41831 rgentlem 2295
static int textwidth(DEstruct DE, const char *text, int nchar)
13974 hornik 2296
{
41831 rgentlem 2297
    int ans;
2298
    char *buf = CallocCharBuf(nchar);
2299
    strncpy(buf, text, nchar);
35844 ripley 2300
    if(mbcslocale) {
32471 ripley 2301
#ifdef HAVE_XUTF8TEXTESCAPEMENT
45475 ripley 2302
	if (utf8locale)
41831 rgentlem 2303
	    ans = Xutf8TextEscapement(font_set, buf, nchar);
45475 ripley 2304
	else
32424 ripley 2305
#endif
41831 rgentlem 2306
	    ans = XmbTextEscapement(font_set, buf, nchar);
45475 ripley 2307
	Free(buf);
2308
	return ans;
35844 ripley 2309
    }
41831 rgentlem 2310
    ans = XTextWidth(DE->font_info, buf, nchar);
2311
    Free(buf);
2312
    return ans;
13974 hornik 2313
}
2314
 
2315
/* Menus */
2316
 
40759 ripley 2317
void popupmenu(DEstruct DE, int x_pos, int y_pos, int col, int row)
13974 hornik 2318
{
40759 ripley 2319
    int i, button, popupcol = col + DE->colmin - 1;
41831 rgentlem 2320
    const char *name;
2321
    char clab[20];
13974 hornik 2322
    XEvent event;
2323
    Window selected_pane;
2324
    SEXP tvec;
2325
 
34639 ripley 2326
    XMoveWindow(iodisplay, menuwindow, x_pos, y_pos);
13974 hornik 2327
    XMapSubwindows(iodisplay, menuwindow);
2328
    XMapRaised(iodisplay, menuwindow);
2329
 
2330
    /* now fill in the menu panes with the correct information */
2331
 
40759 ripley 2332
    if (popupcol > DE->xmaxused) {
24274 ripley 2333
	/* extend work, names and lens */
40759 ripley 2334
	REPROTECT(DE->work = lengthgets(DE->work, popupcol), DE->wpi);
2335
	REPROTECT(DE->names = lengthgets(DE->names, popupcol), DE->npi);
2336
	for (i = DE->xmaxused+1; i < popupcol; i++) {
24274 ripley 2337
	    sprintf(clab, "var%d", i + 1);
40759 ripley 2338
	    SET_STRING_ELT(DE->names, i, mkChar(clab));
24274 ripley 2339
	}
40759 ripley 2340
	REPROTECT(DE->lens = lengthgets(DE->lens, popupcol), DE->lpi);
2341
	DE->xmaxused = popupcol;
24274 ripley 2342
    }
40759 ripley 2343
    tvec = VECTOR_ELT(DE->work, popupcol - 1);
2344
    name = CHAR(STRING_ELT(DE->names, popupcol - 1));
34639 ripley 2345
    if(mbcslocale)
2346
#ifdef HAVE_XUTF8DRAWSTRING
45475 ripley 2347
	if(utf8locale)
34639 ripley 2348
	    Xutf8DrawString(iodisplay,
2349
			    menupanes[0],
40759 ripley 2350
			    font_set, DE->iogc, 3, DE->box_h - 3, name,
2351
			    strlen(name));
34639 ripley 2352
	else
2353
#endif
2354
	    XmbDrawString(iodisplay,
2355
			  menupanes[0],
40759 ripley 2356
			  font_set, DE->iogc, 3, DE->box_h - 3, name,
2357
			  strlen(name));
34639 ripley 2358
    else
45475 ripley 2359
	XDrawString(iodisplay,
40759 ripley 2360
		    menupanes[0], DE->iogc, 3, DE->box_h - 3, name,
2361
		    strlen(name));
13974 hornik 2362
    for (i = 1; i < 4; i++)
49591 ripley 2363
	if(mbcslocale)
34639 ripley 2364
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2365
	    if(utf8locale)
2366
		Xutf8DrawString(iodisplay,
2367
				menupanes[i],
2368
				font_set, DE->iogc, 3, DE->box_h - 3,
2369
				menu_label[i - 1], strlen(menu_label[i - 1]));
2370
	    else
2371
#endif
2372
		XmbDrawString(iodisplay,
2373
			      menupanes[i],
2374
			      font_set, DE->iogc, 3, DE->box_h - 3,
2375
			      menu_label[i - 1], strlen(menu_label[i - 1]));
34639 ripley 2376
	else
49591 ripley 2377
	    XDrawString(iodisplay,
2378
			menupanes[i], DE->iogc, 3, DE->box_h - 3,
34639 ripley 2379
			menu_label[i - 1], strlen(menu_label[i - 1]));
2380
 
24274 ripley 2381
    if (isNull(tvec) || TYPEOF(tvec) == REALSXP)
49591 ripley 2382
	if(mbcslocale)
34639 ripley 2383
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2384
	    if(utf8locale)
2385
		Xutf8DrawString(iodisplay,
2386
				menupanes[1],
2387
				font_set, DE->iogc, 0, DE->box_h - 3,
2388
				"*", 1);
2389
	    else
2390
#endif
2391
		XmbDrawString(iodisplay,
2392
			      menupanes[1],
2393
			      font_set, DE->iogc, 0, DE->box_h - 3,
2394
			      "*", 1);
34639 ripley 2395
	else
49591 ripley 2396
	    XDrawString(iodisplay, menupanes[1], DE->iogc, 0, DE->box_h - 3,
34639 ripley 2397
			"*", 1);
13974 hornik 2398
    else
49591 ripley 2399
	if(mbcslocale)
34639 ripley 2400
#ifdef HAVE_XUTF8DRAWSTRING
49591 ripley 2401
	    if(utf8locale)
2402
		Xutf8DrawString(iodisplay,
2403
				menupanes[2],
2404
				font_set, DE->iogc, 0, DE->box_h - 3,
2405
				"*", 1);
2406
	    else
2407
#endif
2408
		XmbDrawString(iodisplay,
2409
			      menupanes[2],
2410
			      font_set, DE->iogc, 0, DE->box_h - 3,
2411
			      "*", 1);
34639 ripley 2412
	else
49591 ripley 2413
	    XDrawString(iodisplay, menupanes[2], DE->iogc, 0, DE->box_h - 3,
34639 ripley 2414
			"*", 1);
13974 hornik 2415
 
2416
/*
2417
  start an event loop; we're looking for a button press and a button
2418
  release in the same window
2419
*/
2420
 
2421
    while (1) {
2422
	XNextEvent(iodisplay, &event);
34639 ripley 2423
 
2424
	/* event is processed with input method */
2425
 
13974 hornik 2426
	if (event.type == ButtonPress) {
2427
	    button = event.xbutton.button;
2428
	    selected_pane = event.xbutton.window;
2429
	    for (i = 0; selected_pane != menupanes[i]; i++)
2430
		if (i >= 4) goto done;
2431
	    while (1) {
2432
		while (XCheckTypedEvent(iodisplay, ButtonPress, &event));
2433
		XMaskEvent(iodisplay, ButtonReleaseMask, &event);
2434
		if (event.xbutton.button == button)
2435
		    break;
2436
	    }
2437
	    if (selected_pane == event.xbutton.window) {
2438
		for (i = 0; selected_pane != menupanes[i]; i++);
2439
		switch (i) {
2440
		case 0:
2441
		    bell();
2442
		    break;
2443
		case 1:
32424 ripley 2444
		    if (isNull(tvec))
40759 ripley 2445
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2446
				       ssNewVector(REALSXP, 100));
2447
		    else
40759 ripley 2448
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2449
				       coerceVector(tvec, REALSXP));
13974 hornik 2450
		    goto done;
2451
		case 2:
32424 ripley 2452
		    if (isNull(tvec))
40759 ripley 2453
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2454
				       ssNewVector(STRSXP, 100));
40747 ripley 2455
		    else {
40759 ripley 2456
			SET_VECTOR_ELT(DE->work, popupcol - 1,
24274 ripley 2457
				       coerceVector(tvec, STRSXP));
40747 ripley 2458
		    }
40759 ripley 2459
 
13974 hornik 2460
		    goto done;
2461
		case 3:
40759 ripley 2462
		    closerect(DE);
2463
		    DE->ccol = col;
2464
		    DE->crow = 0;
2465
		    clearrect(DE);
13974 hornik 2466
		    goto done;
2467
		}
2468
	    }
2469
	}
45475 ripley 2470
	/* this doesn't work and perhaps I should move it up to the
2471
	   main control loop */
13974 hornik 2472
	else if (event.type == Expose) {
2473
	    if (event.xexpose.window == menuwindow) {
40759 ripley 2474
		XDrawString(iodisplay, menupanes[0], DE->iogc, 3,
2475
			    DE->box_h - 3, name, strlen(name));
13974 hornik 2476
		for (i = 1; i < 4; i++)
40759 ripley 2477
		    XDrawString(iodisplay, menupanes[i], DE->iogc, 3,
2478
				DE->box_h - 3,
13974 hornik 2479
				menu_label[i - 1], strlen(menu_label[i - 1]));
2480
	    }
2481
	}
2482
    }
49591 ripley 2483
done:
40759 ripley 2484
    popdownmenu(DE);
2485
    highlightrect(DE);
13974 hornik 2486
}
2487
 
40759 ripley 2488
void popdownmenu(DEstruct DE)
13974 hornik 2489
{
2490
    XUnmapWindow(iodisplay, menuwindow);
2491
    XUnmapSubwindows(iodisplay, menuwindow);
2492
}
2493
 
40759 ripley 2494
static void copycell(DEstruct DE)
13974 hornik 2495
{
34639 ripley 2496
  /*
2497
   * whichrow = crow + colmin - 1 => whichrow = crow + rowmin - 1
2498
   *                   ^^^                             ^^^
2499
   */
40759 ripley 2500
    int i, whichrow = DE->crow + DE->rowmin - 1,
2501
	whichcol = DE->ccol + DE->colmin -1;
13974 hornik 2502
    SEXP tmp;
32424 ripley 2503
 
13974 hornik 2504
    if (whichrow == 0) {
2505
	/* won't have  cell here */
2506
    } else {
2507
	strcpy(copycontents, "");
40759 ripley 2508
	if (length(DE->work) >= whichcol) {
2509
	    tmp = VECTOR_ELT(DE->work, whichcol - 1);
13974 hornik 2510
	    if (tmp != R_NilValue &&
28786 ripley 2511
		(i = whichrow - 1) < LENGTH(tmp) ) {
13974 hornik 2512
		PrintDefaults(R_NilValue);
45475 ripley 2513
		if (TYPEOF(tmp) == REALSXP) {
34639 ripley 2514
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2515
				BOOSTED_BUF_SIZE-1);
2516
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
45475 ripley 2517
		} else if (TYPEOF(tmp) == STRSXP) {
2518
		    if (STRING_ELT(tmp, i) != ssNA_STRING) {
34639 ripley 2519
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2520
				BOOSTED_BUF_SIZE-1);
2521
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
2522
		    }
13974 hornik 2523
		}
2524
	    }
2525
	}
2526
    }
40759 ripley 2527
    highlightrect(DE);
13974 hornik 2528
}
2529
 
40759 ripley 2530
static void pastecell(DEstruct DE, int row, int col)
13974 hornik 2531
{
40759 ripley 2532
    downlightrect(DE);
2533
    DE->crow = row; DE->ccol = col;
13974 hornik 2534
    if (strlen(copycontents)) {
2535
	strcpy(buf, copycontents);
2536
	clength = strlen(copycontents);
2537
	bufp = buf + clength;
2538
	CellModified = TRUE;
2539
    }
40759 ripley 2540
    closerect(DE);
2541
    highlightrect(DE);
13974 hornik 2542
}
34639 ripley 2543
 
40759 ripley 2544
static void calc_pre_edit_pos(DEstruct DE)
34639 ripley 2545
{
2546
    XVaNestedList   xva_nlist;
2547
    XPoint          xpoint;
2548
    int i;
2549
    int w;
2550
 
40759 ripley 2551
    xpoint.x = DE->boxw[0];
2552
    for (i = 1; i < DE->ccol; i++)
2553
	xpoint.x += BOXW(DE->colmin + i - 1);
34639 ripley 2554
#ifdef HAVE_XUTF8TEXTESCAPEMENT
2555
    if(utf8locale)
2556
	w = Xutf8TextEscapement(font_set, buf, clength);
2557
    else
2558
#endif
2559
	w = XmbTextEscapement(font_set, buf, clength);
40759 ripley 2560
    xpoint.x += (w > BOXW(DE->colmin + DE->ccol - 1)) ?
2561
	BOXW(DE->colmin + DE->ccol - 1) : w;
2562
    xpoint.x += DE->text_offset;
2563
    xpoint.y = DE->hht + (DE->crow+1) * DE->box_h - DE->text_offset;
34639 ripley 2564
 
2565
    /*
2566
      <FIXME>
2567
      I may depend on implementation of XIM, but I do not obey,
2568
      setting value, and investigation in various implementation
2569
      system is need.
2570
      It is only a problem in an appearance.
2571
    */
2572
    xva_nlist = XVaCreateNestedList(0,
2573
				    XNSpotLocation, &xpoint,
2574
				    XNFontSet, font_set,
2575
				    NULL);
2576
    XSetICValues(ioic, XNPreeditAttributes, xva_nlist, NULL);
2577
 
2578
    XFree(xva_nlist);
2579
    return;
2580
}
2581
 
2582
/* last character bytes */
2583
static int last_wchar_bytes(char *str)
2584
{
2585
    wchar_t   wcs[BOOSTED_BUF_SIZE];
2586
    mbstate_t mb_st;
2587
    int cnt;
2588
    char last_mbs[8];
2589
    char *mbs;
39658 ripley 2590
    size_t bytes;
34639 ripley 2591
 
2592
    mbs = (str == NULL) ? buf : str;
2593
 
2594
    memset(wcs, 0 ,sizeof(wcs));
2595
    memset(&mb_st,0, sizeof(mbstate_t));
2596
 
2597
    if((size_t)-1 == (cnt = mbsrtowcs(wcs, (const char **)&mbs,
2598
				      strlen(mbs), &mb_st))) {
45475 ripley 2599
	return 0;
34639 ripley 2600
    }
2601
    if(wcs[0] == L'\0') return 0;
2602
 
2603
    memset(last_mbs, 0, sizeof(last_mbs));
40756 ripley 2604
    bytes = wcrtomb(last_mbs, wcs[cnt-1], &mb_st); /* -Wall */
39658 ripley 2605
    return(bytes);
34639 ripley 2606
}