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