1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 /* Lefteris Koutsofios - AT&T Labs Research */
15 
16 #include "common.h"
17 #include "g.h"
18 #include "gcommon.h"
19 #include "mem.h"
20 
21 Gwidget_t *Gwidgets;
22 int Gwidgetn;
23 
24 Gbitmap_t *Gbitmaps;
25 int Gbitmapn;
26 #define BITMAPINCR 10
27 #define BITMAPSIZE sizeof (Gbitmap_t)
28 
29 char *Gdefaultfont;
30 int Gneedredraw;
31 int Gbuttonsdown;
32 int Gerrflag;
33 int Gerrno;
34 
35 char *texts;
36 int textn;
37 
38 static long wsizes[G_WTYPESIZE];
39 static Gtextline_t tlarray[1000];
40 
41 Gwattrmap_t Gwattrmap[] = {
42     { G_ATTRORIGIN,      G_ATTRTYPEPOINT, "origin",      },
43     { G_ATTRSIZE,        G_ATTRTYPESIZE,  "size",        },
44     { G_ATTRBORDERWIDTH, G_ATTRTYPEINT,   "borderwidth", },
45     { G_ATTRNAME,        G_ATTRTYPETEXT,  "name",        },
46     { G_ATTRTEXT,        G_ATTRTYPETEXT,  "text",        },
47     { G_ATTRAPPENDTEXT,  G_ATTRTYPETEXT,  "appendtext",  },
48     { G_ATTRSELECTION,   G_ATTRTYPETEXT,  "selection",   },
49     { G_ATTRCURSOR,      G_ATTRTYPETEXT,  "cursor",      },
50     { G_ATTRMODE,        G_ATTRTYPETEXT,  "mode",        },
51     { G_ATTRLAYOUT,      G_ATTRTYPETEXT,  "layout",      },
52     { G_ATTRZORDER,      G_ATTRTYPETEXT,  "zorder",      },
53     { G_ATTRCOLOR,       G_ATTRTYPECOLOR, "color",       },
54     { G_ATTRVIEWPORT,    G_ATTRTYPESIZE,  "viewport",    },
55     { G_ATTRWINDOW,      G_ATTRTYPERECT,  "window",      },
56     { G_ATTRWINDOWID,    G_ATTRTYPETEXT,  "windowid",    },
57     { G_ATTRCHILDCENTER, G_ATTRTYPEPOINT, "childcenter", },
58     { G_ATTRNEWLINECB,   G_ATTRTYPEFUNC,  "newlinecb",   },
59     { G_ATTRRESIZECB,    G_ATTRTYPEFUNC,  "resizecb",    },
60     { G_ATTRBUTTONCB,    G_ATTRTYPEFUNC,  "buttoncb",    },
61     { G_ATTREVENTCB,     G_ATTRTYPEFUNC,  "eventcb",     },
62     { G_ATTRUSERDATA,    G_ATTRTYPEFUNC,  "userdata",    },
63     { -1,                -1,              NULL,          },
64 };
65 
66 static int arrayattr[] = {
67     G_ATTRSIZE,
68     G_ATTRBORDERWIDTH,
69     G_ATTRMODE,
70     G_ATTRLAYOUT,
71     G_ATTRCOLOR,
72     G_ATTRWINDOWID,
73     G_ATTRRESIZECB,
74     G_ATTRUSERDATA,
75     -1
76 };
77 
78 static int buttonattr[] = {
79     G_ATTRSIZE,
80     G_ATTRBORDERWIDTH,
81     G_ATTRTEXT,
82     G_ATTRCOLOR,
83     G_ATTRWINDOWID,
84     G_ATTRBUTTONCB,
85     G_ATTRUSERDATA,
86     -1
87 };
88 
89 static int canvasattr[] = {
90     G_ATTRSIZE,
91     G_ATTRBORDERWIDTH,
92 #ifdef FEATURE_GMAP
93     G_ATTRMODE,
94 #endif
95     G_ATTRCURSOR,
96     G_ATTRCOLOR,
97     G_ATTRVIEWPORT,
98     G_ATTRWINDOW,
99     G_ATTRWINDOWID,
100     G_ATTREVENTCB,
101     G_ATTRUSERDATA,
102     -1
103 };
104 
105 static int labelattr[] = {
106     G_ATTRSIZE,
107     G_ATTRBORDERWIDTH,
108     G_ATTRTEXT,
109     G_ATTRCOLOR,
110     G_ATTRWINDOWID,
111     G_ATTREVENTCB,
112     G_ATTRUSERDATA,
113     -1
114 };
115 
116 static int menuattr[] = {
117     G_ATTRUSERDATA,
118     -1
119 };
120 
121 static int pcanvasattr[] = {
122     G_ATTRORIGIN,
123     G_ATTRSIZE,
124     G_ATTRNAME,
125     G_ATTRMODE,
126     G_ATTRCOLOR,
127     G_ATTRWINDOW,
128     G_ATTRWINDOWID,
129     G_ATTREVENTCB,
130     G_ATTRUSERDATA,
131     -1
132 };
133 
134 static int queryattr[] = {
135     G_ATTRMODE,
136     G_ATTRUSERDATA,
137     -1
138 };
139 
140 static int scrollattr[] = {
141     G_ATTRSIZE,
142     G_ATTRBORDERWIDTH,
143     G_ATTRCHILDCENTER,
144     G_ATTRMODE,
145     G_ATTRCOLOR,
146     G_ATTRWINDOWID,
147     G_ATTRUSERDATA,
148     -1,
149 };
150 
151 static int textattr[] = {
152     G_ATTRSIZE,
153     G_ATTRBORDERWIDTH,
154     G_ATTRTEXT,
155     G_ATTRAPPENDTEXT,
156     G_ATTRSELECTION,
157     G_ATTRMODE,
158     G_ATTRCOLOR,
159     G_ATTRWINDOWID,
160     G_ATTRNEWLINECB,
161     G_ATTRUSERDATA,
162     -1
163 };
164 
165 static int viewattr[] = {
166     G_ATTRORIGIN,
167     G_ATTRSIZE,
168     G_ATTRNAME,
169     G_ATTRCOLOR,
170     G_ATTRZORDER,
171     G_ATTRWINDOWID,
172     G_ATTREVENTCB,
173     G_ATTRUSERDATA,
174     -1
175 };
176 
177 Gwlist_t Gwlist[] = {
178     { G_ARRAYWIDGET,   "array",  &arrayattr[0],   },
179     { G_BUTTONWIDGET,  "button", &buttonattr[0],  },
180     { G_CANVASWIDGET,  "canvas", &canvasattr[0],  },
181     { G_LABELWIDGET,   "label",  &labelattr[0],   },
182     { G_MENUWIDGET,    "menu",   &menuattr[0],    },
183     { G_PCANVASWIDGET, "ps",     &pcanvasattr[0], },
184     { G_QUERYWIDGET,   "query",  &queryattr[0],   },
185     { G_SCROLLWIDGET,  "scroll", &scrollattr[0],  },
186     { G_TEXTWIDGET,    "text",   &textattr[0],    },
187     { G_VIEWWIDGET,    "view",   &viewattr[0],    },
188     { -1,               NULL,    NULL,            },
189 };
190 
191 static char *errmsg[] = {
192     /* Gerrno starts at 1      */ "no error",
193     /* G_ERRBADATTRID          */ "bad attribute id %d",
194     /* G_ERRBADATTRVALUE       */ "bad attribute value %s",
195     /* G_ERRBADCOLORINDEX      */ "bad color index %d",
196     /* G_ERRBADPARENTWIDGETID  */ "bad parent widget id %d",
197     /* G_ERRBADWIDGETID        */ "bad widget id %d",
198     /* G_ERRBADWIDGETTYPE      */ "bad widget type %d",
199     /* G_ERRCANNOTCREATEWIDGET */ "cannot create widget",
200     /* G_ERRCANNOTGETATTR      */ "cannot get attribute %s",
201     /* G_ERRCANNOTOPENFILE     */ "cannot open file %s",
202     /* G_ERRCANNOTSETATTR1     */ "cannot set attribute %s in createwidget",
203     /* G_ERRCANNOTSETATTR2     */ "cannot set attribute %s in setwidgetattr",
204     /* G_ERRINITFAILED         */ "initialization failed",
205     /* G_ERRNOCHILDWIDGET      */ "no child widget",
206     /* G_ERRNOPARENTWIDGET     */ "no parent widget",
207     /* G_ERRNOSUCHCURSOR       */ "no such cursor %s",
208     /* G_ERRNOTACANVAS         */ "widget %d is not a canvas",
209     /* G_ERRNOTIMPLEMENTED     */ "not implemented",
210     /* G_ERRNOTSUPPORTED       */ "not supported",
211     /* G_ERRBADBITMAPID        */ "bad bitmap id %d",
212     /* G_ERRCANNOTCREATEBITMAP */ "cannot create bitmap",
213     /* G_ERRNOBITMAP           */ "no bitmap",
214     /* G_ERRCANNOTREADBITMAP   */ "cannot read bitmap",
215 };
216 
217 static int unpackstring (char *);
218 
Ginit(void)219 int Ginit (void) {
220     int wi, bi;
221 
222     wsizes[G_ARRAYWIDGET]   = AWSIZE;
223     wsizes[G_BUTTONWIDGET]  = BWSIZE;
224     wsizes[G_CANVASWIDGET]  = CWSIZE;
225     wsizes[G_LABELWIDGET]   = LWSIZE;
226     wsizes[G_MENUWIDGET]    = MWSIZE;
227     wsizes[G_PCANVASWIDGET] = PWSIZE;
228     wsizes[G_QUERYWIDGET]   = QWSIZE;
229     wsizes[G_SCROLLWIDGET]  = SWSIZE;
230     wsizes[G_TEXTWIDGET]    = TWSIZE;
231     wsizes[G_VIEWWIDGET]    = VWSIZE;
232     Gwidgets = Marrayalloc ((long) WIDGETINCR * WIDGETSIZE);
233     Gwidgetn = WIDGETINCR;
234     for (wi = 0; wi < Gwidgetn; wi++)
235         Gwidgets[wi].inuse = FALSE;
236     Gbitmapn = BITMAPINCR;
237     Gbitmaps = Marrayalloc ((long) Gbitmapn * BITMAPSIZE);
238     for (bi = 0; bi < Gbitmapn; bi++)
239         Gbitmaps[bi].inuse = FALSE;
240     Gneedredraw = FALSE;
241     Gbuttonsdown = 0;
242     Gdefaultfont = "";
243     Gerrflag = FALSE;
244     textn = 100;
245     texts = Marrayalloc ((long) textn);
246     texts[0] = '\0';
247     Ginitgraphics ();
248     return 0;
249 }
250 
Gterm(void)251 int Gterm (void) {
252     int wi;
253 
254     for (wi = 0; wi < Gwidgetn; wi++)
255         if (Gwidgets[wi].inuse)
256             Gdestroywidget (wi);
257     Gtermgraphics ();
258     Marrayfree (texts), texts = NULL, textn = 0;
259     Marrayfree (Gwidgets), Gwidgets = NULL, Gwidgetn = 0;
260     Marrayfree (Gbitmaps), Gbitmaps = NULL, Gbitmapn = 0;
261     return 0;
262 }
263 
Gcreatewidget(int pwi,int type,int attrn,Gwattr_t * attrp)264 int Gcreatewidget (int pwi, int type, int attrn, Gwattr_t *attrp) {
265     Gwidget_t *parent, *widget;
266     int rtn;
267 
268     if ((pwi != -1) && (pwi < 0 || pwi > Gwidgetn || !Gwidgets[pwi].inuse)) {
269         Gerr (POS, G_ERRBADPARENTWIDGETID, pwi);
270         return -1;
271     }
272     if (type < 0 || type >= G_WTYPESIZE) {
273         Gerr (POS, G_ERRBADWIDGETTYPE, type);
274         return -1;
275     }
276     widget = newwidget (type);
277     widget->inuse = TRUE;
278     widget->pwi = pwi;
279     parent = (pwi == -1) ? NULL : &Gwidgets[pwi];
280     rtn = -1;
281     switch (type) {
282     case G_ARRAYWIDGET:
283         rtn = GAcreatewidget (parent, widget, attrn, attrp);
284         break;
285     case G_BUTTONWIDGET:
286         rtn = GBcreatewidget (parent, widget, attrn, attrp);
287         break;
288     case G_CANVASWIDGET:
289         rtn = GCcreatewidget (parent, widget, attrn, attrp);
290         break;
291     case G_LABELWIDGET:
292         rtn = GLcreatewidget (parent, widget, attrn, attrp);
293         break;
294     case G_MENUWIDGET:
295         rtn = GMcreatewidget (parent, widget, attrn, attrp);
296         break;
297     case G_PCANVASWIDGET:
298         rtn = GPcreatewidget (parent, widget, attrn, attrp);
299         break;
300     case G_QUERYWIDGET:
301         rtn = GQcreatewidget (parent, widget, attrn, attrp);
302         break;
303     case G_SCROLLWIDGET:
304         rtn = GScreatewidget (parent, widget, attrn, attrp);
305         break;
306     case G_TEXTWIDGET:
307         rtn = GTcreatewidget (parent, widget, attrn, attrp);
308         break;
309     case G_VIEWWIDGET:
310         rtn = GVcreatewidget (parent, widget, attrn, attrp);
311         break;
312     }
313     if (rtn == -1) {
314         widget->inuse = FALSE;
315         return -1;
316     }
317     return widget - &Gwidgets[0];
318 }
319 
Gsetwidgetattr(int wi,int attrn,Gwattr_t * attrp)320 int Gsetwidgetattr (int wi, int attrn, Gwattr_t *attrp) {
321     Gwidget_t *widget;
322 
323     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
324         Gerr (POS, G_ERRBADWIDGETID, wi);
325         return -1;
326     }
327     widget = &Gwidgets[wi];
328     switch (widget->type) {
329     case G_ARRAYWIDGET:   return GAsetwidgetattr (widget, attrn, attrp);
330     case G_BUTTONWIDGET:  return GBsetwidgetattr (widget, attrn, attrp);
331     case G_CANVASWIDGET:  return GCsetwidgetattr (widget, attrn, attrp);
332     case G_LABELWIDGET:   return GLsetwidgetattr (widget, attrn, attrp);
333     case G_MENUWIDGET:    return GMsetwidgetattr (widget, attrn, attrp);
334     case G_PCANVASWIDGET: return GPsetwidgetattr (widget, attrn, attrp);
335     case G_QUERYWIDGET:   return GQsetwidgetattr (widget, attrn, attrp);
336     case G_SCROLLWIDGET:  return GSsetwidgetattr (widget, attrn, attrp);
337     case G_TEXTWIDGET:    return GTsetwidgetattr (widget, attrn, attrp);
338     case G_VIEWWIDGET:    return GVsetwidgetattr (widget, attrn, attrp);
339     }
340     return -1;
341 }
342 
Ggetwidgetattr(int wi,int attrn,Gwattr_t * attrp)343 int Ggetwidgetattr (int wi, int attrn, Gwattr_t *attrp) {
344     Gwidget_t *widget;
345 
346     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
347         Gerr (POS, G_ERRBADWIDGETID, wi);
348         return -1;
349     }
350     widget = &Gwidgets[wi];
351     switch (widget->type) {
352     case G_ARRAYWIDGET:   return GAgetwidgetattr (widget, attrn, attrp);
353     case G_BUTTONWIDGET:  return GBgetwidgetattr (widget, attrn, attrp);
354     case G_CANVASWIDGET:  return GCgetwidgetattr (widget, attrn, attrp);
355     case G_LABELWIDGET:   return GLgetwidgetattr (widget, attrn, attrp);
356     case G_MENUWIDGET:    return GMgetwidgetattr (widget, attrn, attrp);
357     case G_PCANVASWIDGET: return GPgetwidgetattr (widget, attrn, attrp);
358     case G_QUERYWIDGET:   return GQgetwidgetattr (widget, attrn, attrp);
359     case G_SCROLLWIDGET:  return GSgetwidgetattr (widget, attrn, attrp);
360     case G_TEXTWIDGET:    return GTgetwidgetattr (widget, attrn, attrp);
361     case G_VIEWWIDGET:    return GVgetwidgetattr (widget, attrn, attrp);
362     }
363     return -1;
364 }
365 
Gdestroywidget(int wi)366 int Gdestroywidget (int wi) {
367     Gwidget_t *widget;
368 
369     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
370         Gerr (POS, G_ERRBADWIDGETID, wi);
371         return -1;
372     }
373     widget = &Gwidgets[wi];
374     switch (widget->type) {
375     case G_ARRAYWIDGET:   GAdestroywidget (widget); break;
376     case G_BUTTONWIDGET:  GBdestroywidget (widget); break;
377     case G_CANVASWIDGET:  GCdestroywidget (widget); break;
378     case G_LABELWIDGET:   GLdestroywidget (widget); break;
379     case G_MENUWIDGET:    GMdestroywidget (widget); break;
380     case G_PCANVASWIDGET: GPdestroywidget (widget); break;
381     case G_QUERYWIDGET:   GQdestroywidget (widget); break;
382     case G_SCROLLWIDGET:  GSdestroywidget (widget); break;
383     case G_TEXTWIDGET:    GTdestroywidget (widget); break;
384     case G_VIEWWIDGET:    GVdestroywidget (widget); break;
385     }
386     /* HACK: should do switch on type ... */
387     free (widget->u.c);
388     widget->inuse = FALSE;
389     return 0;
390 }
391 
Gqueryask(int wi,char * prompt,char * args,char * responsep,int responsen)392 int Gqueryask (
393     int wi, char *prompt, char *args, char *responsep, int responsen
394 ) {
395     Gwidget_t *widget;
396 
397     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
398         Gerr (POS, G_ERRBADWIDGETID, wi);
399         return -1;
400     }
401     widget = &Gwidgets[wi];
402     return GQqueryask (widget, prompt, args, responsep, responsen);
403 }
404 
Gmenuaddentries(int wi,int en,char ** ep)405 int Gmenuaddentries (int wi, int en, char **ep) {
406     Gwidget_t *widget;
407 
408     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
409         Gerr (POS, G_ERRBADWIDGETID, wi);
410         return -1;
411     }
412     widget = &Gwidgets[wi];
413     return GMmenuaddentries (widget, en, ep);
414 }
415 
Gmenudisplay(int pwi,int wi)416 int Gmenudisplay (int pwi, int wi) {
417     Gwidget_t *parent, *widget;
418 
419     if (pwi < 0 || pwi > Gwidgetn || !Gwidgets[pwi].inuse) {
420         Gerr (POS, G_ERRBADPARENTWIDGETID, wi);
421         return -1;
422     }
423     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
424         Gerr (POS, G_ERRBADWIDGETID, wi);
425         return -1;
426     }
427     parent = &Gwidgets[pwi];
428     widget = &Gwidgets[wi];
429     return GMmenudisplay (parent, widget);
430 }
431 
432 /* functions for drawing on canvas and pcanvas widgets */
433 
Gcanvasclear(int wi)434 int Gcanvasclear (int wi) {
435     Gwidget_t *widget;
436 
437     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
438         Gerr (POS, G_ERRBADWIDGETID, wi);
439         return -1;
440     }
441     widget = &Gwidgets[wi];
442     switch (widget->type) {
443     case G_CANVASWIDGET:  return GCcanvasclear (widget);
444     case G_PCANVASWIDGET: return GPcanvasclear (widget);
445     }
446     Gerr (POS, G_ERRNOTACANVAS, wi);
447     return -1;
448 }
449 
Gsetgfxattr(int wi,Ggattr_t * ap)450 int Gsetgfxattr (int wi, Ggattr_t *ap) {
451     Gwidget_t *widget;
452 
453     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
454         Gerr (POS, G_ERRBADWIDGETID, wi);
455         return -1;
456     }
457     widget = &Gwidgets[wi];
458     switch (widget->type) {
459     case G_CANVASWIDGET:  return GCsetgfxattr (widget, ap);
460     case G_PCANVASWIDGET: return GPsetgfxattr (widget, ap);
461     }
462     Gerr (POS, G_ERRNOTACANVAS, wi);
463     return -1;
464 }
465 
Ggetgfxattr(int wi,Ggattr_t * ap)466 int Ggetgfxattr (int wi, Ggattr_t *ap) {
467     Gwidget_t *widget;
468 
469     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
470         Gerr (POS, G_ERRBADWIDGETID, wi);
471         return -1;
472     }
473     widget = &Gwidgets[wi];
474     switch (widget->type) {
475     case G_CANVASWIDGET:  return GCgetgfxattr (widget, ap);
476     case G_PCANVASWIDGET: return GPgetgfxattr (widget, ap);
477     }
478     Gerr (POS, G_ERRNOTACANVAS, wi);
479     return -1;
480 }
481 
Garrow(int wi,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)482 int Garrow (int wi, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
483     Gwidget_t *widget;
484 
485     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
486         Gerr (POS, G_ERRBADWIDGETID, wi);
487         return -1;
488     }
489     widget = &Gwidgets[wi];
490     switch (widget->type) {
491     case G_CANVASWIDGET:  return GCarrow (widget, gp1, gp2, ap);
492     case G_PCANVASWIDGET: return GParrow (widget, gp1, gp2, ap);
493     }
494     Gerr (POS, G_ERRNOTACANVAS, wi);
495     return -1;
496 }
497 
Gline(int wi,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)498 int Gline (int wi, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
499     Gwidget_t *widget;
500 
501     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
502         Gerr (POS, G_ERRBADWIDGETID, wi);
503         return -1;
504     }
505     widget = &Gwidgets[wi];
506     switch (widget->type) {
507     case G_CANVASWIDGET:  return GCline (widget, gp1, gp2, ap);
508     case G_PCANVASWIDGET: return GPline (widget, gp1, gp2, ap);
509     }
510     Gerr (POS, G_ERRNOTACANVAS, wi);
511     return -1;
512 }
513 
Gbox(int wi,Grect_t gr,Ggattr_t * ap)514 int Gbox (int wi, Grect_t gr, Ggattr_t *ap) {
515     Gwidget_t *widget;
516 
517     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
518         Gerr (POS, G_ERRBADWIDGETID, wi);
519         return -1;
520     }
521     widget = &Gwidgets[wi];
522     switch (widget->type) {
523     case G_CANVASWIDGET:  return GCbox (widget, gr, ap);
524     case G_PCANVASWIDGET: return GPbox (widget, gr, ap);
525     }
526     Gerr (POS, G_ERRNOTACANVAS, wi);
527     return -1;
528 }
529 
Gpolygon(int wi,int gpn,Gpoint_t * gpp,Ggattr_t * ap)530 int Gpolygon (int wi, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
531     Gwidget_t *widget;
532 
533     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
534         Gerr (POS, G_ERRBADWIDGETID, wi);
535         return -1;
536     }
537     widget = &Gwidgets[wi];
538     switch (widget->type) {
539     case G_CANVASWIDGET:  return GCpolygon (widget, gpn, gpp, ap);
540     case G_PCANVASWIDGET: return GPpolygon (widget, gpn, gpp, ap);
541     }
542     Gerr (POS, G_ERRNOTACANVAS, wi);
543     return -1;
544 }
545 
Gsplinegon(int wi,int gpn,Gpoint_t * gpp,Ggattr_t * ap)546 int Gsplinegon (int wi, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
547     Gwidget_t *widget;
548 
549     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
550         Gerr (POS, G_ERRBADWIDGETID, wi);
551         return -1;
552     }
553     widget = &Gwidgets[wi];
554     switch (widget->type) {
555     case G_CANVASWIDGET:  return GCsplinegon (widget, gpn, gpp, ap);
556     case G_PCANVASWIDGET: return GPsplinegon (widget, gpn, gpp, ap);
557     }
558     Gerr (POS, G_ERRNOTACANVAS, wi);
559     return -1;
560 }
561 
Garc(int wi,Gpoint_t gc,Gsize_t gs,double ang1,double ang2,Ggattr_t * ap)562 int Garc (
563     int wi, Gpoint_t gc, Gsize_t gs, double ang1, double ang2, Ggattr_t *ap
564 ) {
565     Gwidget_t *widget;
566 
567     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
568         Gerr (POS, G_ERRBADWIDGETID, wi);
569         return -1;
570     }
571     widget = &Gwidgets[wi];
572     switch (widget->type) {
573     case G_CANVASWIDGET:  return GCarc (widget, gc, gs, ang1, ang2, ap);
574     case G_PCANVASWIDGET: return GParc (widget, gc, gs, ang1, ang2, ap);
575     }
576     Gerr (POS, G_ERRNOTACANVAS, wi);
577     return -1;
578 }
579 
Gtext(int wi,char * string,Gpoint_t go,char * fn,double fs,char * justs,Ggattr_t * ap)580 int Gtext (
581     int wi, char *string, Gpoint_t go, char *fn, double fs,
582     char *justs, Ggattr_t *ap
583 ) {
584     Gwidget_t *widget;
585     char js[2];
586     int n;
587 
588     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
589         Gerr (POS, G_ERRBADWIDGETID, wi);
590         return -1;
591     }
592     widget = &Gwidgets[wi];
593     if (string[0] == '\000')
594         return 0;
595     n = unpackstring (string);
596     if (!justs[0] || !justs[1])
597         js[0] = 'c', js[1] = 'c';
598     else {
599         js[0] = justs[0], js[1] = justs[1];
600         if (js[0] != 'l' && js[0] != 'c' && js[0] != 'r')
601             js[0] = 'c';
602         if (js[1] != 'd' && js[1] != 'b' && js[1] != 'c' && js[1] != 'u')
603             js[1] = 'c';
604     }
605     switch (widget->type) {
606     case G_CANVASWIDGET:
607         return GCtext (widget, &tlarray[0], n, go, fn, fs, &js[0], ap);
608     case G_PCANVASWIDGET:
609         return GPtext (widget, &tlarray[0], n, go, fn, fs, &js[0], ap);
610     }
611     Gerr (POS, G_ERRNOTACANVAS, wi);
612     return -1;
613 }
614 
Ggettextsize(int wi,char * string,char * fn,double fs,Gsize_t * gsp)615 int Ggettextsize (int wi, char *string, char *fn, double fs, Gsize_t *gsp) {
616     Gwidget_t *widget;
617     int n;
618 
619     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
620         Gerr (POS, G_ERRBADWIDGETID, wi);
621         return -1;
622     }
623     widget = &Gwidgets[wi];
624     if (widget->type != G_CANVASWIDGET) {
625         Gerr (POS, G_ERRNOTACANVAS, wi);
626         return -1;
627     }
628     if (string[0] == '\000') {
629         gsp->x = gsp->y = 0.0;
630         return 0;
631     }
632     n = unpackstring (string);
633     return GCgettextsize (widget, &tlarray[0], n, fn, fs, gsp);
634 }
635 
Gcreatebitmap(int wi,Gsize_t s)636 int Gcreatebitmap (int wi, Gsize_t s) {
637     Gwidget_t *widget;
638     Gbitmap_t *bitmap;
639     int rtn;
640 
641     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
642         Gerr (POS, G_ERRBADPARENTWIDGETID, wi);
643         return -1;
644     }
645     widget = &Gwidgets[wi];
646     if (widget->type != G_CANVASWIDGET && widget->type != G_PCANVASWIDGET) {
647         Gerr (POS, G_ERRNOTACANVAS, wi);
648         return -1;
649     }
650     bitmap = newbitmap ();
651     bitmap->inuse = TRUE;
652     bitmap->canvas = wi;
653     rtn = -1;
654     switch (widget->type) {
655     case G_CANVASWIDGET:  rtn = GCcreatebitmap (widget, bitmap, s); break;
656     case G_PCANVASWIDGET: rtn = GPcreatebitmap (widget, bitmap, s); break;
657     }
658     if (rtn == -1) {
659         bitmap->inuse = FALSE;
660         return -1;
661     }
662     return bitmap - &Gbitmaps[0];
663 }
664 
Gdestroybitmap(int bi)665 int Gdestroybitmap (int bi) {
666     Gbitmap_t *bitmap;
667 
668     if (bi < 0 || bi > Gbitmapn || !Gbitmaps[bi].inuse) {
669         Gerr (POS, G_ERRBADBITMAPID, bi);
670         return -1;
671     }
672     bitmap = &Gbitmaps[bi];
673     switch (bitmap->ctype) {
674     case G_CANVASWIDGET:  GCdestroybitmap (bitmap); break;
675     case G_PCANVASWIDGET: GPdestroybitmap (bitmap); break;
676     }
677     bitmap->inuse = FALSE;
678     return 0;
679 }
680 
Greadbitmap(int wi,FILE * fp)681 int Greadbitmap (int wi, FILE *fp) {
682     Gwidget_t *widget;
683     Gbitmap_t *bitmap;
684     int rtn;
685 
686     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
687         Gerr (POS, G_ERRBADPARENTWIDGETID, wi);
688         return -1;
689     }
690     widget = &Gwidgets[wi];
691     if (widget->type != G_CANVASWIDGET && widget->type != G_PCANVASWIDGET) {
692         Gerr (POS, G_ERRNOTACANVAS, wi);
693         return -1;
694     }
695     bitmap = newbitmap ();
696     bitmap->inuse = TRUE;
697     bitmap->canvas = wi;
698     rtn = -1;
699     switch (widget->type) {
700     case G_CANVASWIDGET:  rtn = GCreadbitmap (widget, bitmap, fp); break;
701     case G_PCANVASWIDGET: rtn = GPreadbitmap (widget, bitmap, fp); break;
702     }
703     if (rtn == -1) {
704         bitmap->inuse = FALSE;
705         return -1;
706     }
707     return bitmap - &Gbitmaps[0];
708 }
709 
Gwritebitmap(FILE * fp,int bi)710 int Gwritebitmap (FILE *fp, int bi) {
711     Gbitmap_t *bitmap;
712     int rtn;
713 
714     if (bi < 0 || bi > Gbitmapn || !Gbitmaps[bi].inuse) {
715         Gerr (POS, G_ERRBADBITMAPID, bi);
716         return -1;
717     }
718     bitmap = &Gbitmaps[bi];
719     rtn = -1;
720     switch (bitmap->ctype) {
721     case G_CANVASWIDGET:  rtn = GCwritebitmap (bitmap, fp); break;
722     case G_PCANVASWIDGET: rtn = GPwritebitmap (bitmap, fp); break;
723     }
724     if (rtn == -1)
725         return -1;
726     return 0;
727 }
728 
Gbitblt(int wi,Gpoint_t gp,Grect_t gr,int bi,char * mode,Ggattr_t * ap)729 int Gbitblt (
730     int wi, Gpoint_t gp, Grect_t gr, int bi, char *mode, Ggattr_t *ap
731 ) {
732     Gwidget_t *widget;
733     Gbitmap_t *bitmap;
734 
735     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
736         Gerr (POS, G_ERRBADWIDGETID, wi);
737         return -1;
738     }
739     widget = &Gwidgets[wi];
740     if (bi < 0 || bi > Gbitmapn || !Gbitmaps[bi].inuse) {
741         Gerr (POS, G_ERRBADBITMAPID, bi);
742         return -1;
743     }
744     bitmap = &Gbitmaps[bi];
745     switch (widget->type) {
746     case G_CANVASWIDGET:  return GCbitblt (widget, gp, gr, bitmap, mode, ap);
747     case G_PCANVASWIDGET: return GPbitblt (widget, gp, gr, bitmap, mode, ap);
748     }
749     Gerr (POS, G_ERRNOTACANVAS, wi);
750     return -1;
751 }
752 
Ggetmousecoords(int wi,Gpoint_t * gsp,int * count)753 int Ggetmousecoords (int wi, Gpoint_t *gsp, int *count) {
754     Gwidget_t *widget;
755 
756     if (wi < 0 || wi > Gwidgetn || !Gwidgets[wi].inuse) {
757         Gerr (POS, G_ERRBADWIDGETID, wi);
758         return -1;
759     }
760     widget = &Gwidgets[wi];
761     if (widget->type != G_CANVASWIDGET) {
762         Gerr (POS, G_ERRNOTACANVAS, wi);
763         return -1;
764     }
765     return GCgetmousecoords (widget, gsp, count);
766 }
767 
newwidget(int type)768 Gwidget_t *newwidget (int type) {
769     Gwidget_t *new;
770     int wi;
771 
772     for (wi = 0; wi < Gwidgetn; wi++)
773         if (!Gwidgets[wi].inuse)
774             goto found;
775 
776     Gwidgets = Marraygrow (
777         Gwidgets, (long) (Gwidgetn + WIDGETINCR) * WIDGETSIZE
778     );
779     for (wi = Gwidgetn; wi < Gwidgetn + WIDGETINCR; wi++)
780         Gwidgets[wi].inuse = FALSE;
781     wi = Gwidgetn, Gwidgetn += WIDGETINCR;
782 
783 found:
784     new = &Gwidgets[wi];
785     new->type = type;
786     new->w = 0;
787     new->udata = 0;
788     /* HACK: should do a switch on type, but ... */
789     if (!(new->u.c = (Gcw_t *) malloc (wsizes[type])))
790         panic1 (POS, "newwidget", "cannot allocate data");
791     return new;
792 }
793 
findwidget(uint64_t w,int type)794 Gwidget_t *findwidget (uint64_t w, int type) {
795     int wi;
796 
797     if (type == G_WTYPESIZE) {
798         for (wi = 0; wi < Gwidgetn; wi++)
799             if (Gwidgets[wi].inuse && (uint64_t) Gwidgets[wi].w == w)
800                 return &Gwidgets[wi];
801     } else {
802         for (wi = 0; wi < Gwidgetn; wi++)
803             if (
804                 Gwidgets[wi].inuse && Gwidgets[wi].type == type &&
805                 (uint64_t) Gwidgets[wi].w == w
806             )
807                 return &Gwidgets[wi];
808     }
809     return NULL;
810 }
811 
newbitmap(void)812 Gbitmap_t *newbitmap (void) {
813     Gbitmap_t *new;
814     int bi;
815 
816     for (bi = 0; bi < Gbitmapn; bi++)
817         if (!Gbitmaps[bi].inuse)
818             goto found;
819 
820     Gbitmaps = Marraygrow (
821         Gbitmaps, (long) (Gbitmapn + BITMAPINCR) * BITMAPSIZE
822     );
823     for (bi = Gbitmapn; bi < Gbitmapn + BITMAPINCR; bi++)
824         Gbitmaps[bi].inuse = FALSE;
825     bi = Gbitmapn, Gbitmapn += BITMAPINCR;
826 
827 found:
828     new = &Gbitmaps[bi];
829     return new;
830 }
831 
Gerr(char * file,int line,int errnum,...)832 void Gerr (char *file, int line, int errnum, ...) {
833     va_list args;
834 
835 #ifdef FEATURE_X11
836     Gerrno = errnum;
837     if (!Gerrflag)
838         return;
839 
840     va_start(args, errnum);
841     fprintf (stderr, "warning: (file %s, line %d) ", file, line);
842     vfprintf (stderr, errmsg[errnum], args);
843     fprintf (stderr, "\n");
844     va_end(args);
845 #else
846 #ifdef FEATURE_WIN32
847     char buf[256];
848 
849     Gerrno = errnum;
850     if (!warnflag)
851         return;
852 
853     va_start(args, errnum);
854     vsprintf (buf, errmsg[errnum], args);
855     Gnocallbacks = TRUE;
856     MessageBox ((HWND) NULL, buf, "Lefty Warning", MB_APPLMODAL);
857     Gnocallbacks = FALSE;
858     va_end(args);
859 #endif
860 #endif
861 }
862 
unpackstring(char * s)863 static int unpackstring (char *s) {
864     char *p1, *p2;
865     int n;
866 
867     if ((n = strlen (s) + 1) > textn)
868         textn = n, texts = Marraygrow (texts, (long) textn);
869     strcpy (texts, s);
870     n = 0;
871     p1 = p2 = texts;
872     tlarray[0].p = p1;
873     while (*p1) {
874         if (p1[0] == '\\') {
875             if (p1[1] == 'n' || p1[1] == 'l' || p1[1] == 'r') {
876                 tlarray[n].n = p1 - tlarray[n].p;
877                 tlarray[n].j = p1[1];
878                 tlarray[++n].p = (p1 += 2);
879             } else {
880                 for (p2 = p1 + 1; *p2; p2++)
881                     p2[-1] = p2[0];
882                 p2[-1] = 0;
883                 p1++;
884             }
885         } else
886             p1++;
887     }
888     if ((tlarray[n].n = p1 - tlarray[n].p) > 0)
889         tlarray[n++].j = 'n';
890     return n;
891 }
892