~ubuntu-branches/ubuntu/saucy/python-scipy/saucy

« back to all changes in this revision

Viewing changes to scipy/sandbox/xplt/src/gist/xbasic.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondrej Certik
  • Date: 2008-06-16 22:58:01 UTC
  • mfrom: (2.1.24 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080616225801-irdhrpcwiocfbcmt
Tags: 0.6.0-12
* The description updated to match the current SciPy (Closes: #489149).
* Standards-Version bumped to 3.8.0 (no action needed)
* Build-Depends: netcdf-dev changed to libnetcdf-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * XBASIC.C
 
3
 *
 
4
 * $Id: xbasic.c 1210 2005-01-14 00:47:34Z travo $
 
5
 *
 
6
 * Implement the basic X windows engine for GIST.
 
7
 *  
 
8
 * CHANGES:
 
9
 * 12/06/04 mdh Correct bug: Do not set xeng->w in Kill because xeng has 
 
10
 *              already been freed.
 
11
 *
 
12
 */
 
13
/*    Copyright (c) 1994.  The Regents of the University of California.
 
14
                    All rights reserved.  */
 
15
 
 
16
#include "xbasic.h"
 
17
#include "gtext.h"
 
18
#include "pstdlib.h"
 
19
 
 
20
#include <string.h>
 
21
 
 
22
static char *xType= "PLAY Window";
 
23
 
 
24
static int ChangePalette(Engine *engine);
 
25
static GpReal TextWidth(const char *text, int nc, const GpTextAttribs *t);
 
26
static void Kill(Engine *engine);
 
27
static void ShutDown(XEngine *xEngine);
 
28
static int Clear(Engine *engine, int always);
 
29
static int Flush(Engine *engine);
 
30
static void GetXRectangle(GpXYMap *map, GpBox *box,
 
31
                          int *x0, int *y0, int *x1, int *y1);
 
32
static void ClearArea(Engine *engine, GpBox *box);
 
33
static void SetXTransform(GpTransform *trans, int landscape, int dpi);
 
34
static void gx_translate(GpBox *trans_window, int x, int y);
 
35
static GpBox *DamageClip(GpBox *damage);
 
36
static void ChangeMap(Engine *engine);
 
37
static void chk_clipping(XEngine *xeng);
 
38
static int SetupLine(XEngine *xeng, GpLineAttribs *gistAl, int join);
 
39
static int DrawLines(Engine *engine, long n, const GpReal *px,
 
40
                     const GpReal *py, int closed, int smooth);
 
41
static int DrawMarkers(Engine *engine, long n, const GpReal *px,
 
42
                       const GpReal *py);
 
43
static int DrwText(Engine *engine, GpReal x0, GpReal y0, const char *text);
 
44
static int DrawFill(Engine *engine, long n, const GpReal *px,
 
45
                    const GpReal *py);
 
46
static int GetCells(GpMap *map, GpReal xmin, GpReal xmax,
 
47
                    GpReal px, GpReal qx, long width,
 
48
                    int *i0, int *di, int *ncols, int *x0, int *x1);
 
49
static int DrawCells(Engine *engine, GpReal px, GpReal py, GpReal qx,
 
50
                     GpReal qy, long width, long height, long nColumns,
 
51
                     const GpColor *colors);
 
52
static int DrawDisjoint(Engine *engine, long n, const GpReal *px,
 
53
                        const GpReal *py, const GpReal *qx, const GpReal *qy);
 
54
static void GetVisibleNDC(XEngine *xeng,
 
55
                          GpReal *xn, GpReal *xx, GpReal *yn, GpReal *yx);
 
56
 
 
57
/* Hook for hlevel.c error handling.  */
 
58
extern void (*HLevelHook)(Engine *engine);
 
59
 
 
60
 
 
61
extern int GxJustifyText(GpXYMap *map, GpReal x0, GpReal y0, const char *text,
 
62
                         int *ix, int *iy, int xbox[], int ybox[]);
 
63
extern int GxJustifyNext(const char **text, int *ix, int *iy);
 
64
 
 
65
static int gxErrorFlag= 0;
 
66
static void GxErrorHandler(void);
 
67
 
 
68
/* ------------------------------------------------------------------------ */
 
69
 
 
70
static int
 
71
ChangePalette(Engine *engine)
 
72
{
 
73
  XEngine *xeng= (XEngine *)engine;
 
74
  p_scr *s = xeng->s;
 
75
  p_win *win = xeng->win;
 
76
  GpColorCell *palette= engine->palette;  /* requested palette */
 
77
  int nColors= engine->nColors;
 
78
  int width, height, depth;
 
79
 
 
80
  if (!s) return 0;
 
81
  depth = p_sshape(s, &width, &height);
 
82
  if (depth > 8) depth = 8;
 
83
  if (nColors > 256) nColors= 256;
 
84
 
 
85
  p_palette(win, palette, nColors);
 
86
 
 
87
  xeng->e.colorChange= 0;
 
88
 
 
89
  return (1<<depth);
 
90
}
 
91
 
 
92
/* ------------------------------------------------------------------------ */
 
93
 
 
94
static int nChars, lineHeight, textHeight, prevWidth, maxWidth, alignH;
 
95
static int textAscent;
 
96
static int firstTextLine= 0;
 
97
 
 
98
static p_scr *current_scr;
 
99
static p_win *current_win;
 
100
static int current_state, current_fsym, current_fsize;
 
101
static int chunkWidth, nChunk, supersub, dy_super, dy_sub, x_chunks;
 
102
 
 
103
/* ARGSUSED */
 
104
static GpReal
 
105
TextWidth(const char *text, int nc, const GpTextAttribs *t)
 
106
{
 
107
  int width= 0;
 
108
  if (firstTextLine) nChars= nc;
 
109
  if (!gtDoEscapes) {
 
110
    width = p_txwidth(current_scr, text, nc, gistA.t.font, current_fsize);
 
111
    if (firstTextLine) {
 
112
      /* record width of first line */
 
113
      prevWidth= chunkWidth= width;
 
114
      nChunk= nc;
 
115
      firstTextLine= 0;
 
116
    }
 
117
  } else if (nc>0) {
 
118
    int firstChunk= firstTextLine;
 
119
    const char *txt= text;
 
120
    char c;
 
121
    for ( ; nc-- ; text++) {
 
122
      c= text[0];
 
123
      if ((nc && c=='!') || c=='^' || c=='_') {
 
124
        if (txt<text)
 
125
          width += p_txwidth(current_scr, txt, (int)(text-txt),
 
126
                             gistA.t.font, current_fsize);
 
127
        if (firstChunk) {
 
128
          nChunk= (int)(text-txt);
 
129
          chunkWidth= width;
 
130
          firstChunk= 0;
 
131
        }
 
132
        txt= text+1;
 
133
        if (c=='!') {
 
134
          /* process single character escapes immediately */
 
135
          text= txt;
 
136
          nc--;
 
137
          c= txt[0];
 
138
          if (c!='!' && c!='^' && c!='_') {
 
139
            if (c==']') c= '^';
 
140
            width += p_txwidth(current_scr, &c, 1,
 
141
                               current_fsym, current_fsize);
 
142
            txt++;
 
143
          }
 
144
        } else if (c=='^') {
 
145
          supersub|= 1;
 
146
        } else {
 
147
          supersub|= 2;
 
148
        }
 
149
      }
 
150
    }
 
151
    if (txt<text)
 
152
      width += p_txwidth(current_scr, txt, (int)(text-txt),
 
153
                         gistA.t.font, current_fsize);
 
154
    if (firstChunk) {
 
155
      nChunk= (int)(text-txt);
 
156
      chunkWidth= width;
 
157
    }
 
158
    if (firstTextLine) {
 
159
      /* record width of first line */
 
160
      prevWidth= width;  /* this is whole line */
 
161
      firstTextLine= 0;
 
162
    }
 
163
  }
 
164
  return (GpReal)width;
 
165
}
 
166
 
 
167
int
 
168
GxJustifyText(GpXYMap *map, GpReal x0, GpReal y0, const char *text,
 
169
              int *ix, int *iy, int xbox[], int ybox[])
 
170
{
 
171
  int nLines, alignV, dx, dy, xmin, xmax, ymin, ymax, ix0, iy0;
 
172
  GpReal rwidest;
 
173
 
 
174
  /* abort if string screen position is ridiculous */
 
175
  x0 = map->x.scale*x0 + map->x.offset;
 
176
  y0 = map->y.scale*y0 + map->y.offset;
 
177
  if (x0<-16000. || x0>16000. || y0<-16000. || y0>16000.) return -1;
 
178
  current_state = 0;
 
179
 
 
180
  /* call p_font before any calls to TextWidth
 
181
   * - may improve efficiency of p_txwidth, p_txheight */
 
182
  p_font(current_win, gistA.t.font, current_fsize, gistA.t.orient);
 
183
 
 
184
  /* Set nLines, maxWidth, nChars, prevWidth */
 
185
  firstTextLine = 1;
 
186
  nChars = prevWidth = chunkWidth = nChunk = supersub = 0;
 
187
  nLines = GtTextShape(text, &gistA.t, &TextWidth, &rwidest);
 
188
  maxWidth = (int)rwidest;
 
189
 
 
190
  /* state bits:
 
191
     1 - this chunk is superscript
 
192
     2 - this chunk is subscript (1 and 2 together meaningless)
 
193
     4 - this chunk is single symbol char
 
194
   */
 
195
  x_chunks= 0;
 
196
 
 
197
  /* Compute height of one line */
 
198
  textHeight = p_txheight(current_scr, gistA.t.font, current_fsize,
 
199
                          &textAscent);
 
200
  dy_super = (supersub&1)? textAscent/3 : 0;
 
201
  dy_sub = (supersub&2)? textAscent/3 : 0;
 
202
  lineHeight = textHeight+dy_sub+dy_super;
 
203
 
 
204
  /* Compute displacement and bounding box of entire string,
 
205
     relative to specified location */
 
206
  GtGetAlignment(&gistA.t, &alignH, &alignV);
 
207
  /* Note: xmax= xmin+maxWidth  */
 
208
  if (alignH==TH_LEFT) {
 
209
    dx= xmin= 0;
 
210
    xmax= maxWidth;
 
211
  } else if (alignH==TH_CENTER) {
 
212
    xmax= maxWidth/2;
 
213
    xmin= -xmax;
 
214
    dx= -prevWidth/2;
 
215
  } else {
 
216
    xmax= 0;
 
217
    xmin= -maxWidth;
 
218
    dx= -prevWidth;
 
219
  }
 
220
 
 
221
  /* Note: ymax= ymin+nLines*lineHeight  and  ymin= dy-textAscent  */
 
222
  if (alignV<=TV_CAP) {
 
223
    dy= textAscent + dy_super;
 
224
    ymin= 0;
 
225
    ymax= nLines*lineHeight;
 
226
  } else if (alignV==TV_HALF) {
 
227
    ymin= textAscent/2;
 
228
    ymax= nLines*lineHeight;
 
229
    dy= ymin-(ymax-lineHeight)/2;
 
230
    ymin= dy-textAscent-dy_super;
 
231
    ymax+= ymin;
 
232
  } else if (alignV==TV_BASE) {
 
233
    dy= -(nLines-1)*lineHeight;
 
234
    ymin= dy-textAscent-dy_super;
 
235
    ymax= textHeight-textAscent + dy_sub;
 
236
  } else {
 
237
    ymin= dy_sub-nLines*lineHeight;
 
238
    dy= ymin+textAscent+dy_super;
 
239
    ymax= dy_sub;
 
240
  }
 
241
 
 
242
  /* handle orientation (path) of text */
 
243
  if (gistA.t.orient==TX_LEFT) {         /* upside down */
 
244
    int tmp;
 
245
    dx= -dx;  dy= -dy;
 
246
    tmp= xmin;  xmin= -xmax;  xmax= -tmp;
 
247
    tmp= ymin;  ymin= -ymax;  ymax= -tmp;
 
248
  } else if (gistA.t.orient==TX_UP) {    /* reading upwards */
 
249
    int tmp;
 
250
    tmp= dx;  dx= dy;  dy= -tmp;
 
251
    tmp= xmin;  xmin= ymin;  ymin= -xmax;
 
252
                xmax= ymax;  ymax= -tmp;
 
253
  } else if (gistA.t.orient==TX_DOWN) {  /* reading downwards */
 
254
    int tmp;
 
255
    tmp= dx;  dx= -dy;  dy= tmp;
 
256
    tmp= xmin;  xmin= -ymax;  ymax= xmax;
 
257
                xmax= -ymin;  ymin= tmp;
 
258
  }
 
259
 
 
260
  /* get bounding box and adjusted reference point */
 
261
  ix0 = (int)x0;
 
262
  iy0 = (int)y0;
 
263
 
 
264
  xbox[0] = ix0+xmin;   ybox[0] = iy0+ymin;
 
265
  xbox[1] = ix0+xmax;   ybox[1] = iy0+ymax;
 
266
 
 
267
  *ix= dx + ix0;
 
268
  *iy= dy + iy0;
 
269
 
 
270
  if (nChunk) p_font(current_win,
 
271
                     gistA.t.font, current_fsize, gistA.t.orient);
 
272
  return nChunk;
 
273
}
 
274
 
 
275
int
 
276
GxJustifyNext(const char **text, int *ix, int *iy)
 
277
{
 
278
  const char *txt= *text+nChunk;
 
279
  int xadj= 0, yadj= 0;
 
280
  char c;
 
281
 
 
282
  nChars-= nChunk;
 
283
  if (!nChars) {
 
284
    /* last chunk was the last one on a line */
 
285
    txt= GtNextLine(txt, &nChars, 0);
 
286
    if (!txt) return -1;
 
287
 
 
288
    *text= txt;
 
289
 
 
290
    /* scan for end of first chunk */
 
291
    if (gtDoEscapes) {
 
292
      for (nChunk=0 ; nChunk<nChars ; nChunk++) {
 
293
        c= txt[nChunk];
 
294
        if ((nChunk+1<nChars && c=='!') || c=='^' || c=='_') break;
 
295
      }
 
296
    } else {
 
297
      nChunk= nChars;
 
298
    }
 
299
 
 
300
    /* compute width of this chunk if necessary, compute width
 
301
       of whole line if necessary for justification */
 
302
    if (alignH!=TH_LEFT || gistA.t.orient!=TX_RIGHT) {
 
303
      /* need to compute width of entire line */
 
304
      int width= prevWidth;
 
305
      firstTextLine= 1;
 
306
      prevWidth= (int)TextWidth(txt, nChars, &gistA.t);
 
307
      if (alignH==TH_CENTER) xadj= (width-prevWidth)/2;
 
308
      else if (alignH==TH_RIGHT) xadj= width-prevWidth;
 
309
      /* TextWidth sets chunkWidth */
 
310
    } else if (nChunk<nChars) {
 
311
      /* just need width of this chunk */
 
312
      if (nChunk) chunkWidth = p_txwidth(current_scr, txt, nChunk,
 
313
                                         gistA.t.font, current_fsize);
 
314
      else chunkWidth= 0;  /* unused */
 
315
    }
 
316
 
 
317
    /* reset state, adjusting (possibly rotated) x and y as well */
 
318
    xadj-= x_chunks;
 
319
    yadj= lineHeight;
 
320
    if (current_state&1) yadj+= dy_super;
 
321
    else if (current_state&2) yadj-= dy_sub;
 
322
    if (nChunk && (current_state&4))
 
323
      p_font(current_win, gistA.t.font, current_fsize, gistA.t.orient);
 
324
    current_state= 0;
 
325
 
 
326
  } else {
 
327
    /* previous chunk ended with an escape character, or was single
 
328
       escaped symbol character -- can't get here unles gtDoEscapes */
 
329
    char c1= '\0';
 
330
    xadj= chunkWidth;      /* width of previous chunk */
 
331
    x_chunks+= chunkWidth; /* accumulate all chunks except last */
 
332
    yadj= 0;
 
333
    if (!(current_state&4)) {
 
334
      c1= *txt++;
 
335
      nChars--;
 
336
    }
 
337
    *text= txt;
 
338
 
 
339
    if (c1=='!') {
 
340
      /* this chunk begins with escaped character */
 
341
      nChunk= 1;
 
342
      c= txt[0];
 
343
      if (c=='!' || c=='^' || c=='_') {
 
344
        /* chunk is just ordinary text */
 
345
        for ( ; nChunk<nChars ; nChunk++) {
 
346
          c= txt[nChunk];
 
347
          if ((nChunk+1<nChars && c=='!') || c=='^' || c=='_') break;
 
348
        }
 
349
        p_font(current_win, gistA.t.font, current_fsize, gistA.t.orient);
 
350
        current_state&= 3;
 
351
      } else {
 
352
        /* chunk is single symbol char */
 
353
        p_font(current_win, current_fsym, current_fsize, gistA.t.orient);
 
354
        current_state|= 4;
 
355
      }
 
356
 
 
357
    } else {
 
358
      for (nChunk=0 ; nChunk<nChars ; nChunk++) {
 
359
        c= txt[nChunk];
 
360
        if ((nChunk+1<nChars && c=='!') || c=='^' || c=='_') break;
 
361
      }
 
362
      if (nChunk)
 
363
        p_font(current_win, gistA.t.font, current_fsize, gistA.t.orient);
 
364
      if (c1=='^') {
 
365
        if (current_state&1) {
 
366
          yadj+= dy_super;  /* return from super to normal */
 
367
          current_state= 0;
 
368
        } else {
 
369
          if (current_state&2) yadj-= dy_sub;
 
370
          yadj-= dy_super;  /* move to superscript */
 
371
          current_state= 1;
 
372
        }
 
373
      } else if (c1=='_') {
 
374
        if (current_state&2) {
 
375
          yadj-= dy_sub;  /* return from sub to normal */
 
376
          current_state= 0;
 
377
        } else {
 
378
          if (current_state&1) yadj+= dy_super;
 
379
          yadj+= dy_sub;  /* move to subscript */
 
380
          current_state= 2;
 
381
        }
 
382
      } else {
 
383
        /* just finished a symbol char */
 
384
        current_state&= 3;
 
385
      }
 
386
    }
 
387
 
 
388
    if (nChunk &&
 
389
        (nChunk<nChars || alignH!=TH_LEFT || gistA.t.orient!=TX_RIGHT)) {
 
390
      char caret= '^';
 
391
      if (nChunk==1 && (current_state&4) && txt[0]==']') txt= &caret;
 
392
      chunkWidth = p_txwidth(current_scr, txt, nChunk,
 
393
                             (current_state&4)? current_fsym : gistA.t.font,
 
394
                             current_fsize);
 
395
    } else {
 
396
      chunkWidth= 0;  /* unused */
 
397
    }
 
398
  }
 
399
 
 
400
  if (gistA.t.orient==TX_RIGHT) {
 
401
    *iy+= yadj;
 
402
    *ix+= xadj;
 
403
  } else if (gistA.t.orient==TX_LEFT) {
 
404
    *iy-= yadj;
 
405
    *ix-= xadj;
 
406
  } else if (gistA.t.orient==TX_UP) {
 
407
    *ix+= yadj;
 
408
    *iy-= xadj;
 
409
  } else {
 
410
    *ix-= yadj;
 
411
    *iy+= xadj;
 
412
  }
 
413
 
 
414
  return nChunk;
 
415
}
 
416
 
 
417
/* ------------------------------------------------------------------------ */
 
418
 
 
419
/* notes for Kill() and g_on_destroy
 
420
 * (1) Kill() is program-driven (e.g.- winkill)
 
421
 *     g_on_destroy() is event-driven (e.g.- mouse click)
 
422
 * (2) however, the p_destroy() function MIGHT or MIGHT NOT
 
423
 *     result in a call to g_on_destroy()
 
424
 *     under Windows, g_on_destroy() is naturally called
 
425
 *       by the call p_destroy() must make to close the window
 
426
 *     under UNIX/X, the play event handler calls p_destroy()
 
427
 *       after g_on_destroy() returns
 
428
 * (3) therefore g_on_destroy() must not call p_destroy(), since
 
429
 *       this would cause infinite recursion on Windows, and a
 
430
 *       double call on X.
 
431
 * (4) worse, if this is the final window on an X display, gist
 
432
 *       should disconnect from the display, but that can only
 
433
 *       be done after the final p_destroy(), which is after
 
434
 *       the g_on_destroy() in the event-driven case
 
435
 *       -- thus, the p_disconnect must take place on the next
 
436
 *          event, which is during the GhBeforeWait hlevel.c function
 
437
 *       -- unfortunately, in the meantime, a new window could
 
438
 *          have been created on that screen,
 
439
 *          hence the g_test_pending() routine
 
440
 *       -- the mess is further compounded by the fact that there
 
441
 *          could be an unlimited number of different screens with
 
442
 *          pending disconnections, after the 4th one, the current
 
443
 *          code simply gives up and forgets about disconnecting
 
444
 */
 
445
extern void (*g_pending_task)(void);
 
446
void (*g_pending_task)(void) = 0;
 
447
static void g_test_pending(p_scr *s);
 
448
 
 
449
static void
 
450
Kill(Engine *engine)
 
451
{
 
452
  XEngine *xeng= (XEngine *)engine;
 
453
  p_win *w = xeng->win;
 
454
  ShutDown(xeng);
 
455
  if (w) {
 
456
    p_destroy(w);
 
457
  }
 
458
  /* for program-driven Kill(), can take care of p_disconnect immediately */
 
459
  if (g_pending_task) g_pending_task();
 
460
}
 
461
 
 
462
static int
 
463
Clear(Engine *engine, int always)
 
464
{
 
465
  XEngine *xeng = (XEngine *)engine;
 
466
  if (!xeng->w) return 1;
 
467
  if ((always || xeng->e.marked) && xeng->w==xeng->win) {
 
468
    int tm = xeng->topMargin;
 
469
    int lm = xeng->leftMargin;
 
470
    if (tm || lm) {
 
471
      int xmax = (int)xeng->swapped.window.xmax;
 
472
      int ymax = (int)xeng->swapped.window.ymin;
 
473
      if (xmax > lm+xeng->wtop) xmax = lm+xeng->wtop;
 
474
      if (ymax > tm+xeng->htop) ymax = tm+xeng->htop;
 
475
      if (xeng->clipping) {
 
476
        p_clip(xeng->w, 0,0,0,0);
 
477
        xeng->clipping = 0;
 
478
      }
 
479
      p_color(xeng->w, P_BG);
 
480
      p_rect(xeng->w, lm, tm, xmax, ymax, 0);
 
481
    } else {
 
482
      p_clear(xeng->w);
 
483
    }
 
484
  }
 
485
  if (xeng->e.colorChange) ChangePalette(engine);
 
486
  xeng->e.marked = 0;
 
487
  return 0;
 
488
}
 
489
 
 
490
static int
 
491
Flush(Engine *engine)
 
492
{
 
493
  XEngine *xeng = (XEngine *)engine;
 
494
  if (!xeng->w) return 1;
 
495
  p_flush(xeng->w);
 
496
  /* test whether an X error has been reported */
 
497
  if (gxErrorFlag) GxErrorHandler();
 
498
  return 0;
 
499
}
 
500
 
 
501
static void
 
502
GetXRectangle(GpXYMap *map, GpBox *box,
 
503
              int *x0, int *y0, int *x1, int *y1)
 
504
{
 
505
  /* get corners of clip rectangle in pixel coordinates */
 
506
  int wmin= (int)(map->x.scale*box->xmin+map->x.offset);
 
507
  int wmax= (int)(map->x.scale*box->xmax+map->x.offset);
 
508
  if (wmax>=wmin) {
 
509
    *x0 = wmin;
 
510
    *x1 = wmax+1;
 
511
  } else {
 
512
    *x0 = wmax;
 
513
    *x1 = wmin+1;
 
514
  }
 
515
  wmin= (int)(map->y.scale*box->ymin+map->y.offset);
 
516
  wmax= (int)(map->y.scale*box->ymax+map->y.offset);
 
517
  if (wmax>=wmin) {
 
518
    *y0 = wmin;
 
519
    *y1 = wmax+1;
 
520
  } else {
 
521
    *y0 = wmax;
 
522
    *y1 = wmin+1;
 
523
  }
 
524
}
 
525
 
 
526
static void
 
527
ClearArea(Engine *engine, GpBox *box)
 
528
{
 
529
  XEngine *xeng= (XEngine *)engine;
 
530
  p_win *w = xeng->w;
 
531
  int x0, y0, x1, y1;
 
532
  if (!w) return;
 
533
  /* if this is animation mode, do not try to clear window */
 
534
  if (w==xeng->win) {
 
535
    int lm = xeng->leftMargin;
 
536
    int tm = xeng->topMargin;
 
537
    GetXRectangle(&engine->devMap, box, &x0, &y0, &x1, &y1);
 
538
    if (x0 < lm) x0 = lm;
 
539
    if (x1 > lm+xeng->wtop) x1 = lm+xeng->wtop;
 
540
    if (y0 < tm) y0 = tm;
 
541
    if (y1 > tm+xeng->htop) y1 = tm+xeng->htop;
 
542
    p_color(w, P_BG);
 
543
    p_rect(w, x0, y0, x1, y1, 0);
 
544
  }
 
545
}
 
546
 
 
547
static void
 
548
SetXTransform(GpTransform *trans, int landscape, int dpi)
 
549
{
 
550
  trans->viewport= landscape? gLandscape : gPortrait;
 
551
  trans->window.xmin= 0.0;
 
552
  trans->window.xmax= PixelsPerNDC(dpi)*trans->viewport.xmax;
 
553
  trans->window.ymin= PixelsPerNDC(dpi)*trans->viewport.ymax;
 
554
  trans->window.ymax= 0.0;
 
555
}
 
556
 
 
557
static void
 
558
gx_translate(GpBox *trans_window, int x, int y)
 
559
{
 
560
  trans_window->xmax += x - trans_window->xmin;
 
561
  trans_window->xmin = x;
 
562
  trans_window->ymin += y - trans_window->ymax;
 
563
  trans_window->ymax = y;
 
564
}
 
565
 
 
566
static GpBox cPort;
 
567
 
 
568
static GpBox *
 
569
DamageClip(GpBox *damage)
 
570
{
 
571
  cPort= gistT.viewport;
 
572
  if (cPort.xmin>cPort.xmax)
 
573
    { GpReal tmp= cPort.xmin; cPort.xmin= cPort.xmax; cPort.xmax= tmp; }
 
574
  if (cPort.ymin>cPort.ymax)
 
575
    { GpReal tmp= cPort.ymin; cPort.ymin= cPort.ymax; cPort.ymax= tmp; }
 
576
  /* (assume damage box is properly ordered) */
 
577
  if (damage->xmin>cPort.xmin) cPort.xmin= damage->xmin;
 
578
  if (damage->xmax<cPort.xmax) cPort.xmax= damage->xmax;
 
579
  if (damage->ymin>cPort.ymin) cPort.ymin= damage->ymin;
 
580
  if (damage->ymax<cPort.ymax) cPort.ymax= damage->ymax;
 
581
  if (cPort.xmin>cPort.xmax || cPort.ymin>cPort.ymax) return 0;
 
582
  else return &cPort;
 
583
}
 
584
 
 
585
static void
 
586
ChangeMap(Engine *engine)
 
587
{
 
588
  XEngine *xeng = (XEngine *)engine;
 
589
  p_win *w = xeng->w;
 
590
  int landscape = xeng->width > xeng->height;
 
591
  int x0, y0, x1, y1;
 
592
  GpBox *clipport;
 
593
  if (!w) return;
 
594
 
 
595
  /* check to be sure that landscape/portrait mode hasn't changed */
 
596
  if (landscape!=xeng->e.landscape) {
 
597
    /* this is probably insane if in animation mode... */
 
598
    SetXTransform(&xeng->e.transform, xeng->e.landscape, xeng->dpi);
 
599
    xeng->width = (int)xeng->e.transform.window.xmax;
 
600
    xeng->height = (int)xeng->e.transform.window.ymin;
 
601
    xeng->swapped = xeng->e.transform;
 
602
    /* make adjustments to allow for SetXTransform, then recenter */
 
603
    if (xeng->w != xeng->win) {
 
604
      xeng->a_x += xeng->x+1;
 
605
      xeng->a_y += xeng->y+1;
 
606
    }
 
607
    xeng->x = xeng->y = -1;
 
608
    GxRecenter(xeng, xeng->wtop+xeng->leftMargin, xeng->htop+xeng->topMargin);
 
609
  }
 
610
 
 
611
  /* do generic change map */
 
612
  GpComposeMap(engine);
 
613
 
 
614
  /* get current clip window */
 
615
  if (xeng->e.damaged) clipport = DamageClip(&xeng->e.damage);
 
616
  else clipport = &gistT.viewport;
 
617
  if (clipport) {
 
618
    /* set clipping rectangle for this XEngine */
 
619
    GetXRectangle(&engine->devMap, clipport, &x0, &y0, &x1, &y1);
 
620
    if (xeng->w == xeng->win) {
 
621
      /* additional restriction for vignetting by window borders */
 
622
      int lm = xeng->leftMargin;
 
623
      int tm = xeng->topMargin;
 
624
      if (x0 < lm) x0 = lm;
 
625
      if (x1 > lm+xeng->wtop) x1 = lm+xeng->wtop;
 
626
      if (y0 < tm) y0 = tm;
 
627
      if (y1 > tm+xeng->htop) y1 = tm+xeng->htop;
 
628
      xeng->clipping = 1;
 
629
    }
 
630
    if (x1<=x0) x1 = x0+1;
 
631
    if (y1<=y0) y1 = y0+1;
 
632
    p_clip(xeng->w, x0, y0, x1, y1);
 
633
  }
 
634
}
 
635
 
 
636
static void
 
637
chk_clipping(XEngine *xeng)
 
638
{
 
639
  p_win *w = xeng->win;
 
640
  if (!xeng->clipping) {
 
641
    int x0, y0, x1, y1;
 
642
    int lm = xeng->leftMargin;
 
643
    int tm = xeng->topMargin;
 
644
    if (xeng->e.damaged) {
 
645
      GpBox *box = DamageClip(&xeng->e.damage);
 
646
      GpXYMap map;
 
647
      if (xeng->w != w)
 
648
        GpSetMap(&xeng->swapped.viewport, &xeng->swapped.window, &map);
 
649
      else
 
650
        map = xeng->e.devMap;
 
651
      GetXRectangle(&map, box, &x0, &y0, &x1, &y1);
 
652
      /* additional restriction for vignetting by window borders */
 
653
      if (x0 < lm) x0 = lm;
 
654
      if (x1 > lm+xeng->wtop) x1 = lm+xeng->wtop;
 
655
      if (y0 < tm) y0 = tm;
 
656
      if (y1 > tm+xeng->htop) y1 = tm+xeng->htop;
 
657
    } else {
 
658
      x0 = lm;
 
659
      x1 = lm+xeng->wtop;
 
660
      y0 = tm;
 
661
      y1 = tm+xeng->htop;
 
662
    }
 
663
    xeng->clipping = 1;
 
664
    if (x1<=x0) x1 = x0+1;
 
665
    if (y1<=y0) y1 = y0+1;
 
666
    p_clip(xeng->w, x0, y0, x1, y1);
 
667
  }
 
668
}
 
669
 
 
670
/* ------------------------------------------------------------------------ */
 
671
 
 
672
static int
 
673
SetupLine(XEngine *xeng, GpLineAttribs *gistAl, int join)
 
674
{
 
675
  GpXYMap *map= &xeng->e.map;
 
676
  double xt[2], yt[2];
 
677
  xt[0] = map->x.scale;
 
678
  xt[1] = map->x.offset;
 
679
  yt[0] = map->y.scale;
 
680
  yt[1] = map->y.offset;
 
681
  p_d_map(xeng->w, xt, yt, 1);
 
682
  chk_clipping(xeng);
 
683
  if (gistAl->type != L_NONE) {
 
684
    int type = gistAl->type-1;
 
685
    int width = (unsigned int)(DEFAULT_LINE_INCHES*xeng->dpi*gistAl->width);
 
686
    if (join) type |= P_SQUARE;
 
687
    p_pen(xeng->w, width, type);
 
688
    p_color(xeng->w, gistAl->color);
 
689
    return 0;
 
690
  } else {
 
691
    return 1;
 
692
  }
 
693
}
 
694
 
 
695
static int
 
696
DrawLines(Engine *engine, long n, const GpReal *px,
 
697
          const GpReal *py, int closed, int smooth)
 
698
{
 
699
  XEngine *xeng = (XEngine *)engine;
 
700
  p_win *w = xeng->w;
 
701
  long i, imax;
 
702
  int npts;
 
703
 
 
704
  if (!w) return 1;
 
705
  if (n<=0 || SetupLine(xeng, &gistA.l, 0)) return 0;
 
706
 
 
707
  closed = (closed && n>1 && (px[0]!=px[n-1] || py[0]!=py[n-1]));
 
708
  for (i=0 ; i<n ; i=imax) {
 
709
    imax = i+2047;
 
710
    npts = (imax<=n)? 2047 : (int)(n-i);
 
711
    p_d_pnts(w, px+i, py+i, npts);
 
712
    if (closed && imax>=n)
 
713
      p_d_pnts(w, px, py, -1);
 
714
    p_lines(w);
 
715
  }
 
716
 
 
717
  xeng->e.marked = 1;
 
718
  return 0;
 
719
}
 
720
 
 
721
/* ------------------------------------------------------------------------ */
 
722
 
 
723
/* play has no polymarker primitive, use GpPseudoMark-- unless
 
724
   user requested tiny points, in which case we use p_dots */
 
725
static int
 
726
DrawMarkers(Engine *engine, long n, const GpReal *px, const GpReal *py)
 
727
{
 
728
  XEngine *xeng = (XEngine *)engine;
 
729
  p_win *w = xeng->w;
 
730
  if (!w || !xeng->mapped) return 1;
 
731
 
 
732
  xeng->e.marked = 1;
 
733
  if (gistA.m.type!=M_POINT || gistA.m.size>1.5) {
 
734
    return GpPseudoMark(engine, n, px, py);
 
735
 
 
736
  } else {
 
737
    long i, imax;
 
738
    int npts;
 
739
    GpXYMap *map= &xeng->e.map;
 
740
    double xt[2], yt[2];
 
741
    xt[0] = map->x.scale;
 
742
    xt[1] = map->x.offset;
 
743
    yt[0] = map->y.scale;
 
744
    yt[1] = map->y.offset;
 
745
    p_d_map(w, xt, yt, 1);
 
746
    chk_clipping(xeng);
 
747
    p_color(w, gistA.m.color);
 
748
 
 
749
    for (i=0 ; i<n ; i=imax) {
 
750
      imax = i+2048;
 
751
      npts = (imax<=n)? 2048 : (int)(n-i);
 
752
      p_d_pnts(w, px+i, py+i, npts);
 
753
      p_dots(w);
 
754
    }
 
755
 
 
756
    return 0;
 
757
  }
 
758
}
 
759
 
 
760
/* ------------------------------------------------------------------------ */
 
761
 
 
762
static int
 
763
DrwText(Engine *engine, GpReal x0, GpReal y0, const char *text)
 
764
{
 
765
  XEngine *xeng = (XEngine *)engine;
 
766
  p_win *w = xeng->w;
 
767
  GpXYMap *map = &xeng->e.map;
 
768
  int ix, iy, len, xbox[2], ybox[2], xn, xx, yn, yx;
 
769
  const char *txt;
 
770
  char *caret= "^";
 
771
 
 
772
  if (!w || !xeng->mapped) return 1;
 
773
  chk_clipping(xeng);
 
774
 
 
775
  current_fsize = (int)((xeng->dpi/ONE_INCH)*gistA.t.height);
 
776
  if (current_fsize<4) current_fsize = 4;     /* totally illegible */
 
777
  if (current_fsize>180) current_fsize = 180; /* way too big */
 
778
  current_fsym = T_SYMBOL | (gistA.t.font&3);
 
779
  current_scr = xeng->s;
 
780
  current_win = w;
 
781
 
 
782
  /* get current window */
 
783
  xn = (int)(gistT.window.xmin*map->x.scale + map->x.offset);
 
784
  xx = (int)(gistT.window.xmax*map->x.scale + map->x.offset);
 
785
  yn = (int)(gistT.window.ymin*map->y.scale + map->y.offset);
 
786
  yx = (int)(gistT.window.ymax*map->y.scale + map->y.offset);
 
787
  if (yn > yx) { int tmp=yn ; yn=yx; yx=tmp ; }
 
788
 
 
789
  /* handle multi-line strings */
 
790
  len = GxJustifyText(map, x0, y0, text, &ix, &iy, xbox, ybox);
 
791
  if (len < 0) return 0;
 
792
 
 
793
  /* consider whether string is completely clipped */
 
794
  if (ybox[0]>yx || ybox[1]<yn || xbox[0]>xx || xbox[1]<xn) return 0;
 
795
 
 
796
  /* erase background if string is opaque */
 
797
  if (gistA.t.opaque) {
 
798
    p_color(w, P_BG);
 
799
    p_rect(w, xbox[0], ybox[0], xbox[1], ybox[1], 0);
 
800
  }
 
801
  p_color(w, gistA.t.color);
 
802
 
 
803
  do {
 
804
    if (len>0) {
 
805
      if (len==1 && (current_state&4) && text[0]==']') txt = caret;
 
806
      else txt = text;
 
807
      p_text(w, ix, iy, txt, len);
 
808
    }
 
809
    len = GxJustifyNext(&text, &ix, &iy);
 
810
  } while (len>=0);
 
811
 
 
812
  xeng->e.marked = 1;
 
813
  return 0;
 
814
}
 
815
 
 
816
/* ------------------------------------------------------------------------ */
 
817
 
 
818
static int
 
819
DrawFill(Engine *engine, long n, const GpReal *px,
 
820
         const GpReal *py)
 
821
{
 
822
  XEngine *xeng = (XEngine *)engine;
 
823
  p_win *w = xeng->w;
 
824
  long i, imax;
 
825
  int npts, has_edge;
 
826
 
 
827
  if (!w || !xeng->mapped) return 1;
 
828
  has_edge = !SetupLine(xeng, &gistA.e, 0); /* but shouldn't set color */
 
829
  p_color(w, gistA.f.color);
 
830
 
 
831
  /* This gives incorrect results if more than one pass through the loop,
 
832
   * but there is no way to give the correct result, so may as well...  */
 
833
  for (i=0 ; i<n ; i=imax) {
 
834
    imax = i+2048;
 
835
    npts = (imax<=n)? 2048 : (int)(n-i);
 
836
    p_d_pnts(w, px+i, py+i, npts);
 
837
    /* Can Nonconvex or Convex be detected? */
 
838
    p_fill(w, 0);
 
839
  }
 
840
 
 
841
  xeng->e.marked = 1;
 
842
  if (has_edge) {
 
843
    p_color(w, gistA.e.color);
 
844
    for (i=0 ; i<n ; i=imax) {
 
845
      imax = i+2047;
 
846
      npts = (imax<=n)? 2047 : (int)(n-i);
 
847
      p_d_pnts(w, px+i, py+i, npts);
 
848
      if (imax>=n)
 
849
        p_d_pnts(w, px, py, -1);
 
850
      p_lines(w);
 
851
    }
 
852
  }
 
853
 
 
854
  return 0;
 
855
}
 
856
 
 
857
/* ------------------------------------------------------------------------ */
 
858
 
 
859
static int
 
860
GetCells(GpMap *map, GpReal xmin, GpReal xmax,
 
861
         GpReal px, GpReal qx, long width,
 
862
         int *i0, int *di, int *ncols, int *x0, int *x1)
 
863
{
 
864
  GpReal scale = map->scale;
 
865
  GpReal offset = map->offset;
 
866
  GpReal x, dx = (qx-px)/width;
 
867
  int imin, imax;
 
868
 
 
869
  if (xmin>xmax) x=xmin, xmin=xmax, xmax=x;
 
870
 
 
871
  if (dx>=0.0) {
 
872
    if (qx<xmin || px>xmax) return 0;
 
873
    if (dx > 0.0) {
 
874
      x = (xmin - px)/dx;
 
875
      if (x < 1.) imin = 0;
 
876
      else imin=(int)x, px+=imin*dx;
 
877
      x = (qx - xmax)/dx;
 
878
      if (x < 1.) imax = 0;
 
879
      else imax=(int)x, qx-=imax*dx;
 
880
      width -= imin + imax;
 
881
      if (width < 3) { /* see comment below */
 
882
        if (qx <= xmax) {
 
883
          if (imin) px = xmin;
 
884
        } else if (px >= xmin) {
 
885
          if (imax) qx = xmax;
 
886
        } else if (width < 2) {
 
887
          px = xmin;
 
888
          qx = xmax;
 
889
        } else if (qx-xmax <= xmin-px) {
 
890
          px += qx - xmax;
 
891
          qx = xmax;
 
892
        } else {
 
893
          qx += qx - xmin;
 
894
          px = xmin;
 
895
        }
 
896
      }
 
897
    } else {
 
898
      imin = width/2;
 
899
      imax = width - imin - 1;
 
900
      width = 1;
 
901
    }
 
902
  } else {
 
903
    if (px<xmin || qx>xmax) return 0;
 
904
    dx = -dx;
 
905
    x = (px - xmax)/dx;
 
906
    if (x < 1.) imin = 0;
 
907
    else imin=(int)x, px-=imin*dx;
 
908
    x = (xmin - qx)/dx;
 
909
    if (x < 1.) imax = 0;
 
910
    else imax=(int)x, qx+=imax*dx;
 
911
    width -= imin + imax;
 
912
    if (width < 3) { /* see comment below */
 
913
      if (px <= xmax) {
 
914
        if (imax) qx = xmin;
 
915
      } else if (qx >= xmin) {
 
916
        if (imin) px = xmax;
 
917
      } else if (width < 2) {
 
918
        qx = xmin;
 
919
        px = xmax;
 
920
      } else if (px-xmax <= xmin-qx) {
 
921
        qx += px - xmax;
 
922
        px = xmax;
 
923
      } else {
 
924
        px += qx - xmin;
 
925
        qx = xmin;
 
926
      }
 
927
    }
 
928
  }
 
929
  /* width<3 logic above guarantees these will not overflow as int */
 
930
  px = px*scale + offset;
 
931
  qx = qx*scale + offset;
 
932
  if (qx >= px) {
 
933
    *i0 = imin;
 
934
    *di = 1;
 
935
    *ncols = width;
 
936
    *x0 = (int)px;
 
937
    *x1 = (int)qx;
 
938
  } else {
 
939
    *i0 = imin + width - 1;
 
940
    *di = -1;
 
941
    *ncols = width;
 
942
    *x0 = (int)qx;
 
943
    *x1 = (int)px;
 
944
  }
 
945
  /* cell array always at least 1 pixel */
 
946
  if (*x1 == *x0) *x1 += 1;
 
947
 
 
948
  return 1;
 
949
}
 
950
 
 
951
static int
 
952
DrawCells(Engine *engine, GpReal px, GpReal py, GpReal qx,
 
953
          GpReal qy, long width, long height, long nColumns,
 
954
          const GpColor *colors)
 
955
{
 
956
  XEngine *xeng = (XEngine *)engine;
 
957
  p_win *w = xeng->w;
 
958
  GpXYMap *map= &xeng->e.map;
 
959
  int i0, j0, di, dj, ncols, nrows, x0, y0, x1, y1;
 
960
 
 
961
  if (!w || !xeng->mapped) return 1;
 
962
  chk_clipping(xeng);
 
963
 
 
964
  if (GetCells(&map->x, gistT.window.xmin, gistT.window.xmax,
 
965
               px, qx, width, &i0, &di, &ncols, &x0, &x1) &&
 
966
      GetCells(&map->y, gistT.window.ymin, gistT.window.ymax,
 
967
               py, qy, height, &j0, &dj, &nrows, &y0, &y1)) {
 
968
    unsigned char *ndxs = (unsigned char *)colors;
 
969
    if (di<0 || dj<0 || ncols!=width || nrows!=height || nColumns!=width) {
 
970
      int r, c, nr, nc, i, j;
 
971
      ndxs = p_malloc(gistA.rgb?3*ncols*nrows:ncols*nrows);
 
972
      j0 *= nColumns;
 
973
      dj *= nColumns;
 
974
      if (gistA.rgb) {
 
975
        for (j=j0,c=0,nr=nrows ; nr-- ; j+=dj,c+=ncols) {
 
976
          nc = ncols;
 
977
          for (i=i0,r=0 ; nc-- ; i+=di,r++) {
 
978
            ndxs[3*(c+r)] = colors[3*(j+i)];
 
979
            ndxs[3*(c+r)+1] = colors[3*(j+i)+1];
 
980
            ndxs[3*(c+r)+2] = colors[3*(j+i)+2];
 
981
          }
 
982
        }
 
983
      } else {
 
984
        for (j=j0,c=0,nr=nrows ; nr-- ; j+=dj,c+=ncols) {
 
985
          nc = ncols;
 
986
          for (i=i0,r=0 ; nc-- ; i+=di,r++)
 
987
            ndxs[c+r] = colors[j+i];
 
988
        }
 
989
      }
 
990
    }
 
991
    if (ncols && nrows) {
 
992
      if (gistA.rgb)
 
993
        p_rgb_cell(w, ndxs, ncols, nrows, x0, y0, x1, y1);
 
994
      else
 
995
        p_ndx_cell(w, ndxs, ncols, nrows, x0, y0, x1, y1);
 
996
    }
 
997
    if (ndxs!=colors) p_free(ndxs);
 
998
  }
 
999
 
 
1000
  xeng->e.marked = 1;
 
1001
  return 0;
 
1002
}
 
1003
 
 
1004
/* ------------------------------------------------------------------------ */
 
1005
 
 
1006
static int
 
1007
DrawDisjoint(Engine *engine, long n, const GpReal *px,
 
1008
             const GpReal *py, const GpReal *qx, const GpReal *qy)
 
1009
{
 
1010
  XEngine *xeng = (XEngine *)engine;
 
1011
  p_win *w = xeng->w;
 
1012
  long i, imax;
 
1013
  int nseg;
 
1014
 
 
1015
  if (!w || !xeng->mapped) return 1;
 
1016
  if (SetupLine(xeng, &gistA.l, 1)) return 0;
 
1017
 
 
1018
  p_d_pnts(w, px, py, 0);
 
1019
  for (i=0 ; i<n ;) {
 
1020
    imax = i+1024;
 
1021
    nseg = (imax<=n)? 1024 : (int)(n-i);
 
1022
    while (nseg--) {
 
1023
      p_d_pnts(w, px+i, py+i, -1);
 
1024
      p_d_pnts(w, qx+i, qy+i, -1);
 
1025
      i++;
 
1026
    }
 
1027
    p_segments(w);
 
1028
  }
 
1029
 
 
1030
  xeng->e.marked = 1;
 
1031
  return 0;
 
1032
}
 
1033
 
 
1034
/* ------------------------------------------------------------------------ */
 
1035
 
 
1036
extern int (*gg_on_expose)(void *c, int *xy);
 
1037
extern int (*gg_on_destroy)(void *c);
 
1038
extern int (*gg_on_resize)(void *c,int w,int h);
 
1039
extern int (*gg_on_focus)(void *c,int in);
 
1040
extern int (*gg_on_key)(void *c,int k,int md);
 
1041
extern int (*gg_on_click)(void *c,int b,int md,int x,int y, unsigned long ms);
 
1042
extern int (*gg_on_motion)(void *c,int md,int x,int y);
 
1043
extern int (*gg_on_deselect)(void *c);
 
1044
int (*gg_on_expose)(void *c, int *xy) = 0;
 
1045
int (*gg_on_destroy)(void *c) = 0;
 
1046
int (*gg_on_resize)(void *c,int w,int h) = 0;
 
1047
int (*gg_on_focus)(void *c,int in) = 0;
 
1048
int (*gg_on_key)(void *c,int k,int md);
 
1049
int (*gg_on_click)(void *c,int b,int md,int x,int y, unsigned long ms) = 0;
 
1050
int (*gg_on_motion)(void *c,int md,int x,int y) = 0;
 
1051
int (*gg_on_deselect)(void *c) = 0;
 
1052
 
 
1053
static void g_on_expose(void *c, int *xy);
 
1054
static void g_on_destroy(void *c);
 
1055
static void g_on_resize(void *c,int w,int h);
 
1056
static void g_on_focus(void *c,int in);
 
1057
static void g_on_key(void *c,int k,int md);
 
1058
static void g_on_click(void *c,int b,int md,int x,int y, unsigned long ms);
 
1059
static void g_on_motion(void *c,int md,int x,int y);
 
1060
static void g_on_deselect(void *c);
 
1061
static void g_on_panic(p_scr *screen);
 
1062
 
 
1063
static Engine *waiting_for = 0;
 
1064
static void (*wait_callback)(void) = 0;
 
1065
 
 
1066
extern int gist_expose_wait(Engine *eng, void (*e_callback)(void));
 
1067
 
 
1068
int
 
1069
gist_expose_wait(Engine *eng, void (*e_callback)(void))
 
1070
{
 
1071
  if (waiting_for) {
 
1072
    waiting_for = 0;
 
1073
    wait_callback = 0;
 
1074
    return 1;
 
1075
  } else {
 
1076
    XEngine *xeng = GisXEngine(eng);
 
1077
    if (!xeng || !xeng->w) return 1;
 
1078
    if (xeng->mapped) return 2;
 
1079
    waiting_for = eng;
 
1080
    wait_callback = e_callback;
 
1081
    return 0;
 
1082
  }
 
1083
}
 
1084
 
 
1085
static void
 
1086
g_on_expose(void *c, int *xy)
 
1087
{
 
1088
  if (!gg_on_expose || gg_on_expose(c,xy)) {
 
1089
    XEngine *xeng = c;
 
1090
    if (c && c == waiting_for) {
 
1091
      waiting_for = 0;
 
1092
      if (wait_callback) wait_callback();
 
1093
      wait_callback = 0;
 
1094
    }
 
1095
    if (!xeng->w) return;
 
1096
    xeng->mapped = 1;
 
1097
    if (xeng->HandleExpose)
 
1098
      /* the alternate handler should probably call GxExpose */
 
1099
      xeng->HandleExpose(&xeng->e, xeng->e.drawing, xy);
 
1100
    else
 
1101
      GxExpose(&xeng->e, xeng->e.drawing, xy);
 
1102
  }
 
1103
}
 
1104
 
 
1105
static void
 
1106
g_on_click(void *c,int b,int md,int x,int y, unsigned long ms)
 
1107
{
 
1108
  if (!gg_on_click || gg_on_click(c,b,md,x,y,ms)) {
 
1109
    XEngine *xeng = c;
 
1110
    if (!xeng->w) return;
 
1111
    if (xeng->HandleClick)
 
1112
      xeng->HandleClick(&xeng->e, b, md, x, y, ms);
 
1113
  }
 
1114
}
 
1115
 
 
1116
static void
 
1117
g_on_motion(void *c,int md,int x,int y)
 
1118
{
 
1119
  if (!gg_on_motion || gg_on_motion(c,md,x,y)) {
 
1120
    XEngine *xeng = c;
 
1121
    if (!xeng->w) return;
 
1122
    if (xeng->HandleMotion)
 
1123
      xeng->HandleMotion(&xeng->e, md, x, y);
 
1124
  }
 
1125
}
 
1126
 
 
1127
static void
 
1128
g_on_destroy(void *c)
 
1129
{
 
1130
  if (!gg_on_destroy || gg_on_destroy(c)) {
 
1131
    XEngine *xeng = c;
 
1132
    /* if xeng->win==0, assume ShutDown already called */
 
1133
    if (xeng->win) ShutDown(xeng);
 
1134
  }
 
1135
}
 
1136
 
 
1137
static void
 
1138
g_on_resize(void *c,int w,int h)
 
1139
{
 
1140
  if (!gg_on_resize || gg_on_resize(c,w,h)) {
 
1141
    XEngine *xeng = c;
 
1142
    if (xeng->w) GxRecenter(xeng, w, h);
 
1143
  }
 
1144
}
 
1145
 
 
1146
static void
 
1147
g_on_focus(void *c,int in)
 
1148
{
 
1149
  if (!gg_on_focus || gg_on_focus(c,in)) {
 
1150
    XEngine *xeng = c;
 
1151
    if (xeng->w && xeng->HandleMotion && in==2)
 
1152
      xeng->HandleMotion(&xeng->e, 0, -1, -1);
 
1153
  }
 
1154
}
 
1155
 
 
1156
static void
 
1157
g_on_key(void *c,int k,int md)
 
1158
{
 
1159
  if (!gg_on_key || gg_on_key(c,k,md)) {
 
1160
    XEngine *xeng = c;
 
1161
    if (xeng->w && xeng->HandleKey)
 
1162
      xeng->HandleKey(&xeng->e, k, md);
 
1163
  }
 
1164
}
 
1165
 
 
1166
static void g_on_deselect(void *c)
 
1167
{
 
1168
  if (!gg_on_deselect || gg_on_deselect(c)) {
 
1169
  }
 
1170
}
 
1171
 
 
1172
void
 
1173
GxExpose(Engine *engine, Drauing *drawing, int *xy)
 
1174
{
 
1175
  XEngine *xeng = (XEngine *)engine;
 
1176
  GpBox damage;
 
1177
  if (!drawing || !xeng->w) return;
 
1178
  /* xy=0 to redraw all, otherwise x0,y0,x1,y1 */
 
1179
  if (xy) {
 
1180
    GpXYMap *map = &engine->devMap;
 
1181
    damage.xmin= (xy[0]-map->x.offset)/map->x.scale;
 
1182
    damage.xmax= (xy[2]-map->x.offset)/map->x.scale;
 
1183
    damage.ymax= (xy[1]-map->y.offset)/map->y.scale;
 
1184
    damage.ymin= (xy[3]-map->y.offset)/map->y.scale;
 
1185
  } else {
 
1186
    damage.xmin = xeng->swapped.viewport.xmin;
 
1187
    damage.xmax = xeng->swapped.viewport.xmax;
 
1188
    damage.ymin = xeng->swapped.viewport.ymin;
 
1189
    damage.ymax = xeng->swapped.viewport.ymax;
 
1190
  }
 
1191
  if (engine->damaged) {
 
1192
    GpSwallow(&engine->damage, &damage);
 
1193
  } else {
 
1194
    engine->damage = damage;
 
1195
    engine->damaged = 1;
 
1196
  }
 
1197
  GdSetDrawing(drawing);
 
1198
  GpPreempt(engine);
 
1199
  GdDraw(1);
 
1200
  GpPreempt(0);        /* not correct if damaged during a preempt... */
 
1201
  GdSetDrawing(0);
 
1202
}
 
1203
 
 
1204
void
 
1205
GxRecenter(XEngine *xeng, int width, int height)
 
1206
{
 
1207
  int x, y;
 
1208
  int eWidth = xeng->width;
 
1209
  int eHeight = xeng->height;
 
1210
  width -= xeng->leftMargin;
 
1211
  height -= xeng->topMargin;
 
1212
  xeng->wtop = width;
 
1213
  xeng->htop = height;
 
1214
  x = (eWidth-width)/2;
 
1215
  /* put center of page at center of landscape window */
 
1216
  if (eWidth>eHeight) y = (eHeight-height)/2;
 
1217
  /* put center of upper square of page at center of portrait window */
 
1218
  else y = (eWidth-height)/2;
 
1219
  /* once either dimension is big enough for whole picture, stop moving it */
 
1220
  if (y<0) y = 0;
 
1221
  if (x<0) x = 0;
 
1222
  if (x!=xeng->x || y!=xeng->y) {
 
1223
    int tmargin = xeng->topMargin;
 
1224
    int lmargin = xeng->leftMargin;
 
1225
    gx_translate(&xeng->swapped.window, -x+lmargin, -y+tmargin);
 
1226
    if (xeng->w == xeng->win) {
 
1227
      gx_translate(&xeng->e.transform.window, -x+lmargin, -y+tmargin);
 
1228
      GpDeviceMap(&xeng->e);
 
1229
    } else {
 
1230
      xeng->a_x -= x - xeng->x;
 
1231
      xeng->a_y -= y - xeng->y;
 
1232
      lmargin = tmargin = 0;
 
1233
    }
 
1234
    xeng->x = x;
 
1235
    xeng->y = y;
 
1236
    if (xeng->wtop>0) x = xeng->wtop+lmargin;
 
1237
    else x = lmargin+1;
 
1238
    if (xeng->htop>0) y = xeng->htop+tmargin;
 
1239
    else y = tmargin+1;
 
1240
    xeng->clipping = 1;
 
1241
    p_clip(xeng->win, lmargin, tmargin, x, y);
 
1242
  }
 
1243
}
 
1244
 
 
1245
/* ------------------------------------------------------------------------ */
 
1246
 
 
1247
typedef struct g_scr g_scr;
 
1248
struct g_scr {
 
1249
  char *name;
 
1250
  int number;
 
1251
  p_scr *s;
 
1252
};
 
1253
static g_scr *g_screens = 0;
 
1254
static int n_screens = 0;
 
1255
 
 
1256
/* ARGSUSED */
 
1257
void
 
1258
g_initializer(int *pargc, char *argv[])
 
1259
{
 
1260
  extern char *g_argv0;
 
1261
  g_argv0 = argv? argv[0] : 0;
 
1262
  p_gui(&g_on_expose, &g_on_destroy, &g_on_resize, &g_on_focus,
 
1263
        &g_on_key, &g_on_click, &g_on_motion, &g_on_deselect,
 
1264
        &g_on_panic);
 
1265
}
 
1266
 
 
1267
p_scr *
 
1268
g_connect(char *displayName)
 
1269
{
 
1270
  p_scr *s = 0;
 
1271
  int i, j, i0=-1, len=0, number=0;
 
1272
 
 
1273
  /* split display into base name and screen number (separated by dot) */
 
1274
  if (displayName) while (displayName[len]) len++;
 
1275
  if (len) {
 
1276
    for (i=len-1 ; i>=0 ; i--) if (displayName[i]=='.') break;
 
1277
    if (i>=0) {
 
1278
      int i0 = i;
 
1279
      for (i++ ; i<len && displayName[i]<='9' && displayName[i]>='0' ; i++)
 
1280
        number = 10*number + (displayName[i]-'0');
 
1281
      if (i == len) len = i0;
 
1282
      else number = 0;
 
1283
    }
 
1284
  }
 
1285
  if (!len) displayName = 0;
 
1286
  if (g_screens) {
 
1287
    for (i=0 ; i<n_screens ; i++) {
 
1288
      j = 0;
 
1289
      if (g_screens[i].name) {
 
1290
        for ( ; j<len ; j++)
 
1291
          if (g_screens[i].s && g_screens[i].name[j]!=displayName[j]) break;
 
1292
      }
 
1293
      if (j==len && (len? (!g_screens[i].name[j]) : !g_screens[i].name)) {
 
1294
        if (number == g_screens[i].number) break;
 
1295
        else if (i0<0) i0 = i;
 
1296
      }
 
1297
    }
 
1298
    if (i<n_screens) s = g_screens[i].s;
 
1299
  }
 
1300
  if (!s) {
 
1301
    if (i0<0) s = p_connect(displayName);
 
1302
    else s = p_multihead(g_screens[i0].s, number);
 
1303
    if (!s) return s;
 
1304
    g_test_pending(s);
 
1305
    for (i=0 ; i<n_screens ; i++) if (!g_screens[i].s) break;
 
1306
    if (i==n_screens && !(i & (i-1))) {
 
1307
      int n = i? 2*i : 1;
 
1308
      g_screens = p_realloc(g_screens, sizeof(g_scr)*n);
 
1309
    }
 
1310
    g_screens[i].number = number;
 
1311
    g_screens[i].name = displayName? p_strncat(0, displayName, len) : 0;
 
1312
    g_screens[i].s = s;
 
1313
    if (i==n_screens) n_screens++;
 
1314
  }
 
1315
 
 
1316
  return s;
 
1317
}
 
1318
 
 
1319
void
 
1320
g_disconnect(p_scr *s)
 
1321
{
 
1322
  if (s) {
 
1323
    int i;
 
1324
    char *name;
 
1325
    for (i=0 ; i<n_screens ; i++) {
 
1326
      if (g_screens[i].s == s) {
 
1327
        name = g_screens[i].name;
 
1328
        g_screens[i].name = 0;
 
1329
        g_screens[i].s = 0;
 
1330
        p_free(name);
 
1331
      }
 
1332
    }
 
1333
    p_disconnect(s);
 
1334
  }
 
1335
}
 
1336
 
 
1337
XEngine *
 
1338
GxEngine(p_scr *s, char *name, GpTransform *toPixels,
 
1339
         int x, int y, int topMargin, int leftMargin, long engineSize)
 
1340
{
 
1341
  XEngine *xEngine;
 
1342
  unsigned int width, height;
 
1343
  GpReal pixels_per_page;
 
1344
  int dpi;
 
1345
 
 
1346
  if (!s) return 0;
 
1347
 
 
1348
  /* Graphics window will have dimensions of toPixels transform window */
 
1349
  if (toPixels->window.xmin<toPixels->window.xmax)
 
1350
    width = (unsigned int)(toPixels->window.xmax - toPixels->window.xmin);
 
1351
  else
 
1352
    width = (unsigned int)(toPixels->window.xmin - toPixels->window.xmax);
 
1353
  if (toPixels->window.ymin<toPixels->window.ymax)
 
1354
    height = (unsigned int)(toPixels->window.ymax - toPixels->window.ymin);
 
1355
  else
 
1356
    height = (unsigned int)(toPixels->window.ymin - toPixels->window.ymax);
 
1357
 
 
1358
  /* Reconstruct dpi (dots per inch) from toPixels transform */
 
1359
  pixels_per_page = toPixels->window.ymin;
 
1360
  if (pixels_per_page < toPixels->window.xmax)
 
1361
    pixels_per_page = toPixels->window.xmax;
 
1362
  dpi = (int)(0.01 + pixels_per_page*ONE_INCH/gPortrait.ymax);
 
1363
 
 
1364
  /* adjust VDC window so GpDeviceMap in GpNewEngine sets proper
 
1365
   * transform, which will have xmin=x<0, ymax=y<0 */
 
1366
  gx_translate(&toPixels->window, x+leftMargin, y+topMargin);
 
1367
 
 
1368
  xEngine =
 
1369
    (XEngine *)GpNewEngine(engineSize, name, xType, toPixels, width>height,
 
1370
                           &Kill, &Clear, &Flush, &ChangeMap,
 
1371
                           &ChangePalette, &DrawLines, &DrawMarkers,
 
1372
                           &DrwText, &DrawFill, &DrawCells,
 
1373
                           &DrawDisjoint);
 
1374
  if (!xEngine) {
 
1375
    strcpy(gistError, "memory manager failed in GxEngine");
 
1376
    return 0;
 
1377
  }
 
1378
 
 
1379
  /* XEngines can repair damage */
 
1380
  xEngine->e.ClearArea = &ClearArea;
 
1381
 
 
1382
  /* Fill in Engine properties specific to XEngine */
 
1383
  xEngine->s = s;
 
1384
  xEngine->win = 0;
 
1385
  xEngine->width = width;
 
1386
  xEngine->height = height;
 
1387
  xEngine->topMargin = topMargin;
 
1388
  xEngine->leftMargin = leftMargin;
 
1389
  xEngine->x = -x;
 
1390
  xEngine->y = -y;
 
1391
  xEngine->mapped = xEngine->clipping = 0;
 
1392
  xEngine->dpi = dpi;
 
1393
 
 
1394
  xEngine->e.colorMode = 0;
 
1395
 
 
1396
  xEngine->w = 0;
 
1397
  xEngine->a_width = xEngine->a_height= 0;
 
1398
  xEngine->a_x = xEngine->a_y= 0;
 
1399
  xEngine->swapped = xEngine->e.transform;
 
1400
 
 
1401
  xEngine->HandleExpose = 0;
 
1402
  xEngine->HandleClick = 0;
 
1403
  xEngine->HandleMotion = 0;
 
1404
  xEngine->HandleKey = 0;
 
1405
 
 
1406
  return xEngine;
 
1407
}
 
1408
 
 
1409
/* default top window represents 6 inch square */
 
1410
int gx75width = 450;
 
1411
int gx100width = 600;
 
1412
int gx75height = 450;
 
1413
int gx100height = 600;
 
1414
 
 
1415
int gist_private_map = 0;
 
1416
int gist_input_hint = 0;
 
1417
int gist_rgb_hint = 0;
 
1418
 
 
1419
Engine *
 
1420
GpBXEngine(char *name, int landscape, int dpi, char *displayName)
 
1421
{
 
1422
  p_scr *s = g_connect(displayName);
 
1423
  int topWidth = DefaultTopWidth(dpi);
 
1424
  int topHeight = DefaultTopHeight(dpi);
 
1425
  GpTransform toPixels;
 
1426
  int x, y, width, height, hints;
 
1427
  XEngine *xeng;
 
1428
 
 
1429
  if (!s) return 0;
 
1430
 
 
1431
  SetXTransform(&toPixels, landscape, dpi);
 
1432
  width = (int)toPixels.window.xmax;
 
1433
  height = (int)toPixels.window.ymin;
 
1434
  x = (width-topWidth)/2;
 
1435
  if (landscape) y = (height-topHeight)/2;
 
1436
  else y = (width-topHeight)/2;
 
1437
  if (y<0) y = 0;
 
1438
  if (x<0) x = 0;
 
1439
  xeng = GxEngine(s, name, &toPixels, -x,-y,0,0, sizeof(XEngine));
 
1440
 
 
1441
  xeng->wtop = topWidth;
 
1442
  xeng->htop = topHeight;
 
1443
  /* possibly want optional P_RGBMODEL as well */
 
1444
  hints = (gist_private_map?P_PRIVMAP:0) | (gist_input_hint?0:P_NOKEY) |
 
1445
    (gist_rgb_hint?P_RGBMODEL:0);
 
1446
  xeng->win = xeng->w =
 
1447
    p_window(s, topWidth, topHeight, name, P_BG, hints, xeng);
 
1448
  if (!xeng->win) {
 
1449
    GpDelEngine(&xeng->e);
 
1450
    return 0;
 
1451
  }
 
1452
 
 
1453
  return &xeng->e;
 
1454
}
 
1455
 
 
1456
int
 
1457
GxInput(Engine *engine,
 
1458
        void (*HandleExpose)(Engine *, Drauing *, int *),
 
1459
        void (*HandleClick)(Engine *,int,int,int,int,unsigned long),
 
1460
        void (*HandleMotion)(Engine *,int,int,int),
 
1461
        void (*HandleKey)(Engine *,int,int))
 
1462
{
 
1463
  XEngine *xeng = GisXEngine(engine);
 
1464
  if (!xeng) return 1;
 
1465
  xeng->HandleExpose = HandleExpose;
 
1466
  xeng->HandleClick = HandleClick;
 
1467
  xeng->HandleMotion = HandleMotion;
 
1468
  xeng->HandleKey = HandleKey;
 
1469
  return 0;
 
1470
}
 
1471
 
 
1472
XEngine *
 
1473
GisXEngine(Engine *engine)
 
1474
{
 
1475
  return (engine && engine->type==xType)? (XEngine *)engine : 0;
 
1476
}
 
1477
 
 
1478
/* ------------------------------------------------------------------------ */
 
1479
 
 
1480
int
 
1481
GxAnimate(Engine *engine, GpBox *viewport)
 
1482
{
 
1483
  XEngine *xeng = GisXEngine(engine);
 
1484
  int x, y, x0, y0, x1, y1;
 
1485
  GpBox *v, *w;
 
1486
  GpReal xmin, xmax, ymin, ymax;
 
1487
  GpReal scalx, offx, scaly, offy;
 
1488
 
 
1489
  if (!xeng || !xeng->w) return 1;
 
1490
  if (xeng->w!=xeng->win) GxDirect(engine);
 
1491
 
 
1492
  v = &xeng->e.transform.viewport;  /* NDC */
 
1493
  w = &xeng->e.transform.window;    /* pixels */
 
1494
 
 
1495
  /* get NDC-->pixel mapping coefficients */
 
1496
  scalx = xeng->e.devMap.x.scale;
 
1497
  offx = xeng->e.devMap.x.offset;
 
1498
  scaly = xeng->e.devMap.y.scale;
 
1499
  offy = xeng->e.devMap.y.offset;
 
1500
 
 
1501
  /* clip given viewport to portion of NDC space which is actually
 
1502
   * visible now -- note that v is either gLandscape or gPortrait,
 
1503
   * so that min<max for v; must also be true for input viewport */
 
1504
  GetVisibleNDC(xeng, &xmin, &xmax, &ymin, &ymax);
 
1505
  if (viewport->xmin>xmin) xmin = viewport->xmin;
 
1506
  if (viewport->xmax<xmax) xmax = viewport->xmax;
 
1507
  if (viewport->ymin>ymin) ymin = viewport->ymin;
 
1508
  if (viewport->ymax<ymax) ymax = viewport->ymax;
 
1509
 
 
1510
  /* install NDC-->pixel transform for animation pixmap */
 
1511
  v->xmin = xmin;
 
1512
  v->xmax = xmax;
 
1513
  v->ymin = ymin;
 
1514
  v->ymax = ymax;
 
1515
 
 
1516
  /* set the engine transform to map the specified viewport into
 
1517
   * offscreen pixels, and get (x,y) offset from full window pixels
 
1518
   * to offscreen pixels */
 
1519
  w->xmin = scalx*xmin+offx;
 
1520
  w->xmax = scalx*xmax+offx;
 
1521
  if (w->xmax > w->xmin) {
 
1522
    x = (int)w->xmin;
 
1523
    w->xmax -= w->xmin;
 
1524
    w->xmin = 0.0;
 
1525
  } else {
 
1526
    x = (int)w->xmax;
 
1527
    w->xmin -= w->xmax;
 
1528
    w->xmax = 0.0;
 
1529
  }
 
1530
  w->ymin = scaly*ymin+offy;
 
1531
  w->ymax = scaly*ymax+offy;
 
1532
  if (w->ymax > w->ymin) {
 
1533
    y = (int)w->ymin;
 
1534
    w->ymax -= w->ymin;
 
1535
    w->ymin = 0.0;
 
1536
  } else {
 
1537
    y = (int)w->ymax;
 
1538
    w->ymin -= w->ymax;
 
1539
    w->ymax = 0.0;
 
1540
  }
 
1541
  GpDeviceMap((Engine *)xeng);
 
1542
  GetXRectangle(&xeng->e.devMap, v, &x0, &y0, &x1, &y1);
 
1543
  x1 -= x0;
 
1544
  y1 -= y0;
 
1545
 
 
1546
  /* create the offscreen pixmap */
 
1547
  xeng->w = p_offscreen(xeng->win, x1, y1);
 
1548
  if (!xeng->w) {
 
1549
    xeng->w = xeng->win;
 
1550
    xeng->e.transform = xeng->swapped;
 
1551
    GpDeviceMap((Engine *)xeng);
 
1552
    return 2;
 
1553
  }
 
1554
  xeng->a_width = x1;
 
1555
  xeng->a_height = y1;
 
1556
  xeng->a_x = x;
 
1557
  xeng->a_y = y;
 
1558
 
 
1559
  /* set coordinate mapping for offscreen */
 
1560
  ChangeMap((Engine *)xeng);
 
1561
 
 
1562
  /* reset mapping clip to whole visible window */
 
1563
  if (xeng->wtop>0) x1 = xeng->wtop+xeng->leftMargin;
 
1564
  else x1 = xeng->leftMargin+1;
 
1565
  if (xeng->htop>0) y1 = xeng->htop+xeng->topMargin;
 
1566
  else y1 = xeng->topMargin+1;
 
1567
  xeng->clipping = 1;
 
1568
  p_clip(xeng->win, xeng->leftMargin, xeng->topMargin, x1, y1);
 
1569
 
 
1570
  p_clear(xeng->w);
 
1571
  return 0;
 
1572
}
 
1573
 
 
1574
static void
 
1575
GetVisibleNDC(XEngine *xeng,
 
1576
              GpReal *xn, GpReal *xx, GpReal *yn, GpReal *yx)
 
1577
{
 
1578
  GpReal scalx = xeng->e.devMap.x.scale;
 
1579
  GpReal offx = xeng->e.devMap.x.offset;
 
1580
  GpReal scaly = xeng->e.devMap.y.scale;
 
1581
  GpReal offy = xeng->e.devMap.y.offset;
 
1582
  int xmin, xmax, ymin, ymax;
 
1583
 
 
1584
  xmin = xeng->leftMargin;
 
1585
  xmax = xmin+xeng->wtop;
 
1586
  ymax = xeng->topMargin;
 
1587
  ymin = ymax+xeng->htop;
 
1588
 
 
1589
  /* Convert pixels to NDC coordinates */
 
1590
  *xn = (xmin-offx)/scalx;
 
1591
  *xx = (xmax-offx)/scalx;
 
1592
  *yn = (ymin-offy)/scaly;
 
1593
  *yx = (ymax-offy)/scaly;
 
1594
}
 
1595
 
 
1596
int
 
1597
GxStrobe(Engine *engine, int clear)
 
1598
{
 
1599
  XEngine *xeng = GisXEngine(engine);
 
1600
 
 
1601
  if (!xeng || !xeng->w || xeng->w==xeng->win) return 1;
 
1602
 
 
1603
  p_bitblt(xeng->win, xeng->a_x, xeng->a_y, xeng->w,
 
1604
           0, 0, xeng->a_width, xeng->a_height);
 
1605
  if (clear) p_clear(xeng->w);
 
1606
 
 
1607
  return 0;
 
1608
}
 
1609
 
 
1610
int
 
1611
GxDirect(Engine *engine)
 
1612
{
 
1613
  XEngine *xeng = GisXEngine(engine);
 
1614
 
 
1615
  if (!xeng || !xeng->w || xeng->w==xeng->win) return 1;
 
1616
 
 
1617
  p_destroy(xeng->w);
 
1618
  xeng->w = xeng->win;
 
1619
 
 
1620
  /* set coordinate map and clipping to values for graphics window */
 
1621
  xeng->e.transform = xeng->swapped;
 
1622
  GpDeviceMap((Engine *)xeng);
 
1623
  ChangeMap((Engine *)xeng);
 
1624
 
 
1625
  return 0;
 
1626
}
 
1627
 
 
1628
/* ------------------------------------------------------------------------ */
 
1629
 
 
1630
void (*HLevelHook)(Engine *engine)= 0;
 
1631
 
 
1632
/* hack to disconnect if last engine destroyed (see GhBeforeWait) */
 
1633
#define G_N_PENDING 4
 
1634
static p_scr *g_pending_scr[G_N_PENDING];
 
1635
static void g_do_disconnect(void);
 
1636
static void
 
1637
g_do_disconnect(void)
 
1638
{
 
1639
  p_scr *s;
 
1640
  int i;
 
1641
  for (i=0 ; i<=G_N_PENDING ; i++) {
 
1642
    s = g_pending_scr[i];
 
1643
    g_pending_scr[i] = 0;
 
1644
    if (s) g_disconnect(s);
 
1645
  }
 
1646
  g_pending_task = 0;
 
1647
}
 
1648
 
 
1649
static void
 
1650
g_test_pending(p_scr *s)
 
1651
{
 
1652
  int i;
 
1653
  if (g_pending_task == g_do_disconnect) {
 
1654
    for (i=0 ; i<=G_N_PENDING ; i++)
 
1655
      if (g_pending_scr[i] == s) {
 
1656
        g_pending_scr[i] = 0;
 
1657
        break;
 
1658
      }
 
1659
  } else {
 
1660
    g_pending_task = 0;
 
1661
    for (i=0 ; i<=G_N_PENDING ; i++) g_pending_scr[i] = 0;
 
1662
  }
 
1663
}
 
1664
 
 
1665
static void
 
1666
ShutDown(XEngine *xeng)
 
1667
{
 
1668
  p_scr *s = xeng->s;
 
1669
  p_win *w = xeng->w;
 
1670
  p_win *win = xeng->win;
 
1671
  xeng->mapped= 0;
 
1672
  /* destroy any hlevel references without further ado */
 
1673
  if (HLevelHook) HLevelHook((Engine *)xeng);
 
1674
  xeng->w = xeng->win = 0;
 
1675
  xeng->s = 0;
 
1676
  if (w && w!=win) p_destroy(w);
 
1677
  GpDelEngine(&xeng->e);
 
1678
  if (s) {
 
1679
    Engine *eng;
 
1680
    XEngine *xe2;
 
1681
    for (eng=GpNextEngine(0) ; eng ; eng=GpNextEngine(eng)) {
 
1682
      xe2 = GisXEngine(eng);
 
1683
      if (xe2 && xe2->s==s) break;
 
1684
    }
 
1685
    if (!eng) {
 
1686
      int i;
 
1687
      if (g_pending_task == g_do_disconnect) {
 
1688
        for (i=0 ; i<=G_N_PENDING ; i++)
 
1689
          if (g_pending_scr[i] == s) break;
 
1690
        if (i >= G_N_PENDING) {
 
1691
          for (i=0 ; i<=G_N_PENDING ; i++)
 
1692
            if (!g_pending_scr[i]) break;
 
1693
          if (i < G_N_PENDING) g_pending_scr[i] = s;
 
1694
        }
 
1695
      } else {
 
1696
        g_pending_scr[0] = s;
 
1697
        for (i=1 ; i<=G_N_PENDING ; i++) g_pending_scr[i] = 0;
 
1698
        g_pending_task = g_do_disconnect;
 
1699
      }
 
1700
    }
 
1701
  }
 
1702
}
 
1703
 
 
1704
static void (*XErrHandler)(char *errMsg)= 0;
 
1705
 
 
1706
static void
 
1707
g_on_panic(p_scr *screen)
 
1708
{
 
1709
  Engine *eng = 0;
 
1710
  XEngine *xeng = 0;
 
1711
  do {
 
1712
    for (eng=GpNextEngine(eng) ; eng ; eng=GpNextEngine(eng)) {
 
1713
      xeng= GisXEngine(eng);
 
1714
      if (xeng && xeng->s==screen) break;
 
1715
    }
 
1716
    if (eng) {
 
1717
      xeng->s = 0;  /* be sure not to call p_disconnect */
 
1718
      Kill(eng);
 
1719
    }
 
1720
  } while (eng);
 
1721
  XErrHandler("play on_panic called (screen graphics engines killed)");
 
1722
}
 
1723
 
 
1724
/* this routine actually calls the XErrHandler, which may not return
 
1725
   and/or which may trigger additional X protocol requests */
 
1726
static void GxErrorHandler(void)
 
1727
{
 
1728
  char msg[80];
 
1729
  gxErrorFlag= 0;
 
1730
  XErrHandler(msg);
 
1731
}
 
1732
 
 
1733
int GpSetXHandler(void (*ErrHandler)(char *errMsg))
 
1734
{
 
1735
  /* install X error handlers which don't call exit */
 
1736
  XErrHandler= ErrHandler;
 
1737
  return 0;
 
1738
}
 
1739
 
 
1740
/* ------------------------------------------------------------------------ */
 
1741
 
 
1742
int
 
1743
g_rgb_read(Engine *eng, GpColor *rgb, long *nx, long *ny)
 
1744
{
 
1745
  XEngine *xeng = GisXEngine(eng);
 
1746
  if (!xeng || !xeng->w || !xeng->win) return 1;
 
1747
  if (!rgb) {
 
1748
    *nx = xeng->wtop;
 
1749
    *ny = xeng->htop;
 
1750
  } else {
 
1751
    p_rgb_read(xeng->win, rgb, xeng->leftMargin, xeng->topMargin,
 
1752
               xeng->leftMargin+xeng->wtop, xeng->topMargin+xeng->htop);
 
1753
  }
 
1754
  return 0;
 
1755
}
 
1756
 
 
1757
/* ------------------------------------------------------------------------ */