1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "gdrawP.h"
31 #include "ustring.h"
32 
33 #include <stdarg.h>
34 
35 /* Preallocate an error dialog so that we can pop it up if things go really bad*/
36 /*  ie. if memory gets munched somehow */
37 
38 #define ERR_LINE_MAX	20
39 static GWindow error;
40 enum err_type { et_info, et_warn, et_error, et_fatal };
41 static struct errinfo {
42     unichar_t *lines[ERR_LINE_MAX];
43     unsigned int dismissed: 1;
44     int width;
45     enum err_type err_type;
46 } errinfo;
47 
e_h(GWindow gw,GEvent * event)48 static int e_h(GWindow gw, GEvent *event) {
49     int line;
50     int x,len, max_len;
51     GRect r;
52     static unichar_t ok[] = { 'O', 'K', '\0' };
53 
54     if ( event->type == et_expose ) {
55 	max_len = 0;
56 	for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line ) {
57 	    len = GDrawGetTextWidth(gw,errinfo.lines[line],-1);
58 	    if ( len>max_len ) max_len = len;
59 	}
60 	x = (errinfo.width-max_len)/2;
61 	for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line )
62 	    GDrawDrawText(gw,x, 10+10+15*line, errinfo.lines[line],-1,0x000000);
63 
64 	x = (errinfo.width-(len = GDrawGetTextWidth(gw,ok,2)))/2;
65 	r.x = x-10; r.y = 25+15*line; r.width = len+20; r.height = 18;
66 	GDrawFillRect(gw,&r,0xffffff);
67 	GDrawDrawRect(gw,&r,0x000000);
68 	GDrawDrawText(gw,x,r.y+13,ok,2,0x000000);
69     } else if ( event->type==et_char ) {
70 	if ( event->u.chr.chars[0]=='\r' || event->u.chr.chars[0]=='\33' )
71 	    errinfo.dismissed = true;
72     } else if ( event->type==et_mouseup ) {
73 	errinfo.dismissed = true;
74     } else if ( event->type==et_close ) {
75 	errinfo.dismissed = true;
76     }
77 return( 1 );
78 }
79 
RunError()80 static void RunError() {
81     errinfo.dismissed = false;
82     GDrawSetVisible(error,true);
83     while ( !errinfo.dismissed )
84 	GDrawProcessOneEvent(NULL);
85     GDrawSetVisible(error,false);
86     GDrawSync(NULL);
87     GDrawProcessPendingEvents(NULL);
88 }
89 
ProcessText(unichar_t * ubuf,char * buf,enum err_type et)90 static void ProcessText(unichar_t *ubuf,char *buf, enum err_type et) {
91     int max_len = 60, len;
92     char *pt, *ept, *last_space;
93     unichar_t *ue = ubuf;
94     int line=0;
95 
96     pt = buf;
97     for ( line=0; line<ERR_LINE_MAX && *pt; ++line ) {
98 	last_space = NULL;
99 	for ( ept = pt; *ept!='\n' && *ept!='\0' && ept-pt<max_len; ++ept )
100 	    if ( *ept==' ' )
101 		last_space = ept;
102 	if ( *ept!='\n' && *ept!='\0' && last_space!=NULL )
103 	    ept = last_space;
104 	errinfo.lines[line] = def2u_strncpy(ue,pt,ept-pt);
105 	ue[ept-pt] = '\0'; ue += (ept+1-pt);
106 	if ( *ept=='\n' || *ept==' ' ) ++ept;
107 	pt = ept;
108     }
109     for ( ; line<ERR_LINE_MAX ; ++line )
110 	errinfo.lines[line] = NULL;
111     errinfo.err_type = et;
112 
113     max_len = 0;
114     for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line ) {
115 	len = GDrawGetTextWidth(error,errinfo.lines[line],-1);
116 	if ( len>max_len ) max_len = len;
117     }
118     errinfo.width = max_len+30;
119     GDrawResize(error,max_len+30,15*line+50);
120 }
121 
122 GDisplay *global_gd;
123 
_GDraw_InitError(GDisplay * gd)124 void _GDraw_InitError(GDisplay *gd) {
125     GRect screen, pos;
126     static unichar_t title[]= { 'E', 'r', 'r', 'o', 'r', '\0' };
127     static unichar_t courier[] = { 'c', 'o', 'u', 'r', 'i', 'e', 'r', '\0' };
128     static GDisplay *static_gd;
129     GWindowAttrs wattrs;
130     FontRequest rq;
131 
132     if ( gd!=NULL )
133 	static_gd = gd;
134     else
135 	screen_display = gd = static_gd;
136 
137     global_gd = static_gd;
138 
139     if ( gd==NULL )
140 return;
141 
142     if ( error != NULL )
143 return;
144     GDrawGetSize(GDrawGetRoot(gd),&screen);
145 
146     memset(&wattrs,0,sizeof(wattrs));
147     wattrs.mask = wam_events|wam_positioned|wam_cursor|wam_wtitle|wam_backcol|
148 	    wam_restrict|wam_redirect|wam_isdlg;
149     wattrs.event_masks = -1;
150     wattrs.positioned = 1;
151     wattrs.cursor = ct_pointer;
152     wattrs.window_title = title;
153     wattrs.background_color = 0xbbbbbb;
154     wattrs.restrict_input_to_me = true;
155     wattrs.redirect_chars_to_me = true;
156     wattrs.is_dlg = true;
157     pos.width = 300; pos.height = 180;
158     pos.x = (screen.width-pos.width)/2;
159     pos.y = (screen.width-pos.width)/3;
160     errinfo.width = pos.width;
161 
162     error = GDrawCreateTopWindow(gd,&pos,e_h,NULL,&wattrs);
163 
164     memset(&rq,0,sizeof(rq));
165     rq.family_name = courier;
166     rq.point_size = -12;
167     rq.weight = 400;
168     rq.style = 0;
169     GDrawAttachFont(error,&rq);
170 }
171 
GDrawIError(const char * fmt,...)172 void GDrawIError(const char *fmt,...) {
173   // GDrawIErrorRun was the previous version of this function.
174   // This new function intercepts the calls and stashes them for future processing.
175   // This avoids stack overflows in certain cases.
176   GDisplay * gd = global_gd;
177   char * buffer = NULL;
178   va_list ap;
179   va_start(ap, fmt);
180   buffer = vsmprintf(fmt, ap);
181   va_end(ap);
182   if (buffer != NULL ) {
183     if ( gd==NULL ) {
184       fprintf(stderr, "%s", buffer); // If there is no display, we write to stderr.
185     } else {
186       if ((gd->err_flag) && (gd->err_report != NULL)) {
187         if (strlen(gd->err_report) + strlen(buffer) + 1 < 2048) {
188           // If there is an existing error message, we concatenate if there is space.
189           char * tmp = smprintf("%s%s\n", gd->err_report, buffer);
190           free(gd->err_report); gd->err_report = tmp;
191         }
192       } else {
193         // If there is no existing error message, we copy to the right spot.
194         gd->err_report = smprintf("%s\n", buffer);
195       }
196       gd->err_flag |= 1;
197     }
198   }
199   free(buffer); buffer = NULL;
200 }
201 
GDrawIErrorRun(const char * fmt,...)202 void GDrawIErrorRun(const char *fmt,...) {
203     char buf[1025]; unichar_t ubuf[1025];
204     va_list ap;
205 
206     strcpy(buf,"Internal Error:\n");
207     va_start(ap, fmt);
208     vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, ap);
209     va_end(ap);
210     fprintf( stderr, "%s\n", buf );
211     _GDraw_InitError(NULL);
212     if ( error!=NULL ) {
213 	ProcessText(ubuf,buf,et_error);
214 	RunError();
215     }
216 }
217 
GDrawError(const char * fmt,...)218 void GDrawError(const char *fmt,...) {
219     char buf[1025]; unichar_t ubuf[1025];
220     va_list ap;
221 
222     va_start(ap, fmt);
223     vsprintf(buf, fmt, ap);
224     va_end(ap);
225     _GDraw_InitError(NULL);
226     if ( error==NULL )
227 	fprintf( stderr, "%s\n", buf );
228     else {
229 	ProcessText(ubuf,buf,et_error);
230 	RunError();
231     }
232 }
233 
GDrawFatalError(const char * fmt,...)234 void GDrawFatalError(const char *fmt,...) {
235     char buf[1025]; unichar_t ubuf[1025];
236     va_list ap;
237 
238     strcpy(buf,"Fatal Error:\n");
239     va_start(ap, fmt);
240     vsprintf(buf+strlen(buf), fmt, ap);
241     va_end(ap);
242 	fprintf( stderr, "%s\n", buf );
243     if ( error!=NULL ) {
244 	ProcessText(ubuf,buf,et_fatal);
245 	RunError();
246     }
247     exit(1);
248 }
249