Line data Source code
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 : #define _GNU_SOURCE
29 : // GNU stdio does not enable vasprintf if we fail to define this.
30 : #include <stdio.h>
31 : #include <string.h>
32 : #include <stdarg.h>
33 :
34 : #include "gdrawP.h"
35 : #include "ustring.h"
36 :
37 : /* Preallocate an error dialog so that we can pop it up if things go really bad*/
38 : /* ie. if memory gets munched somehow */
39 :
40 : #define ERR_LINE_MAX 20
41 : static GWindow error;
42 : enum err_type { et_info, et_warn, et_error, et_fatal };
43 : static struct errinfo {
44 : unichar_t *lines[ERR_LINE_MAX];
45 : unsigned int dismissed: 1;
46 : int width;
47 : enum err_type err_type;
48 : } errinfo;
49 :
50 0 : static int e_h(GWindow gw, GEvent *event) {
51 : int line;
52 : int x,len, max_len;
53 : GRect r;
54 : static unichar_t ok[] = { 'O', 'K', '\0' };
55 :
56 0 : if ( event->type == et_expose ) {
57 0 : max_len = 0;
58 0 : for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line ) {
59 0 : len = GDrawGetTextWidth(gw,errinfo.lines[line],-1);
60 0 : if ( len>max_len ) max_len = len;
61 : }
62 0 : x = (errinfo.width-max_len)/2;
63 0 : for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line )
64 0 : GDrawDrawText(gw,x, 10+10+15*line, errinfo.lines[line],-1,0x000000);
65 :
66 0 : x = (errinfo.width-(len = GDrawGetTextWidth(gw,ok,2)))/2;
67 0 : r.x = x-10; r.y = 25+15*line; r.width = len+20; r.height = 18;
68 0 : GDrawFillRect(gw,&r,0xffffff);
69 0 : GDrawDrawRect(gw,&r,0x000000);
70 0 : GDrawDrawText(gw,x,r.y+13,ok,2,0x000000);
71 0 : } else if ( event->type==et_char ) {
72 0 : if ( event->u.chr.chars[0]=='\r' || event->u.chr.chars[0]=='\33' )
73 0 : errinfo.dismissed = true;
74 0 : } else if ( event->type==et_mouseup ) {
75 0 : errinfo.dismissed = true;
76 0 : } else if ( event->type==et_close ) {
77 0 : errinfo.dismissed = true;
78 : }
79 0 : return( 1 );
80 : }
81 :
82 0 : static void RunError() {
83 0 : errinfo.dismissed = false;
84 0 : GDrawSetVisible(error,true);
85 0 : while ( !errinfo.dismissed )
86 0 : GDrawProcessOneEvent(NULL);
87 0 : GDrawSetVisible(error,false);
88 0 : GDrawSync(NULL);
89 0 : GDrawProcessPendingEvents(NULL);
90 0 : }
91 :
92 0 : static void ProcessText(unichar_t *ubuf,char *buf, enum err_type et) {
93 0 : int max_len = 60, len;
94 : char *pt, *ept, *last_space;
95 0 : unichar_t *ue = ubuf;
96 0 : int line=0;
97 :
98 0 : pt = buf;
99 0 : for ( line=0; line<ERR_LINE_MAX && *pt; ++line ) {
100 0 : last_space = NULL;
101 0 : for ( ept = pt; *ept!='\n' && *ept!='\0' && ept-pt<max_len; ++ept )
102 0 : if ( *ept==' ' )
103 0 : last_space = ept;
104 0 : if ( *ept!='\n' && *ept!='\0' && last_space!=NULL )
105 0 : ept = last_space;
106 0 : errinfo.lines[line] = def2u_strncpy(ue,pt,ept-pt);
107 0 : ue[ept-pt] = '\0'; ue += (ept+1-pt);
108 0 : if ( *ept=='\n' || *ept==' ' ) ++ept;
109 0 : pt = ept;
110 : }
111 0 : for ( ; line<ERR_LINE_MAX ; ++line )
112 0 : errinfo.lines[line] = NULL;
113 0 : errinfo.err_type = et;
114 :
115 0 : max_len = 0;
116 0 : for ( line = 0; line<ERR_LINE_MAX && errinfo.lines[line]!=NULL; ++line ) {
117 0 : len = GDrawGetTextWidth(error,errinfo.lines[line],-1);
118 0 : if ( len>max_len ) max_len = len;
119 : }
120 0 : errinfo.width = max_len+30;
121 0 : GDrawResize(error,max_len+30,15*line+50);
122 0 : }
123 :
124 : GDisplay *global_gd;
125 :
126 0 : void _GDraw_InitError(GDisplay *gd) {
127 : GRect screen, pos;
128 : static unichar_t title[]= { 'E', 'r', 'r', 'o', 'r', '\0' };
129 : static unichar_t courier[] = { 'c', 'o', 'u', 'r', 'i', 'e', 'r', '\0' };
130 : static GDisplay *static_gd;
131 : GWindowAttrs wattrs;
132 : FontRequest rq;
133 :
134 0 : if ( gd!=NULL )
135 0 : static_gd = gd;
136 : else
137 0 : screen_display = gd = static_gd;
138 :
139 0 : global_gd = static_gd;
140 :
141 0 : if ( gd==NULL )
142 0 : return;
143 :
144 0 : if ( error != NULL )
145 0 : return;
146 0 : GDrawGetSize(GDrawGetRoot(gd),&screen);
147 :
148 0 : memset(&wattrs,0,sizeof(wattrs));
149 0 : wattrs.mask = wam_events|wam_positioned|wam_cursor|wam_wtitle|wam_backcol|
150 : wam_restrict|wam_redirect|wam_isdlg;
151 0 : wattrs.event_masks = -1;
152 0 : wattrs.positioned = 1;
153 0 : wattrs.cursor = ct_pointer;
154 0 : wattrs.window_title = title;
155 0 : wattrs.background_color = 0xbbbbbb;
156 0 : wattrs.restrict_input_to_me = true;
157 0 : wattrs.redirect_chars_to_me = true;
158 0 : wattrs.is_dlg = true;
159 0 : pos.width = 300; pos.height = 180;
160 0 : pos.x = (screen.width-pos.width)/2;
161 0 : pos.y = (screen.width-pos.width)/3;
162 0 : errinfo.width = pos.width;
163 :
164 0 : error = GDrawCreateTopWindow(gd,&pos,e_h,NULL,&wattrs);
165 :
166 0 : memset(&rq,0,sizeof(rq));
167 0 : rq.family_name = courier;
168 0 : rq.point_size = -12;
169 0 : rq.weight = 400;
170 0 : rq.style = 0;
171 0 : GDrawAttachFont(error,&rq);
172 : }
173 :
174 1 : void GDrawIError(const char *fmt,...) {
175 : // GDrawIErrorRun was the previous version of this function.
176 : // This new function intercepts the calls and stashes them for future processing.
177 : // This avoids stack overflows in certain cases.
178 1 : GDisplay * gd = global_gd;
179 1 : char * buffer = NULL;
180 : va_list ap;
181 1 : va_start(ap, fmt);
182 1 : int preret = vasprintf(&buffer, fmt, ap);
183 1 : va_end(ap);
184 2 : if (preret < 0 ) return;
185 1 : if (buffer != NULL ) {
186 1 : if ( gd==NULL ) {
187 1 : fprintf(stderr, "%s", buffer); // If there is no display, we write to stderr.
188 : } else {
189 0 : if ((gd->err_flag) && (gd->err_report != NULL)) {
190 0 : if (strlen(gd->err_report) + strlen(buffer) + 1 < 2048) {
191 : // If there is an existing error message, we concatenate if there is space.
192 : char * tmp;
193 0 : asprintf(&tmp, "%s%s\n", gd->err_report, buffer);
194 0 : free(gd->err_report); gd->err_report = tmp;
195 : }
196 : } else {
197 : // If there is no existing error message, we copy to the right spot.
198 0 : asprintf(&gd->err_report, "%s\n", buffer);
199 : }
200 0 : gd->err_flag |= 1;
201 : }
202 : }
203 1 : free(buffer); buffer = NULL;
204 : }
205 :
206 0 : void GDrawIErrorRun(const char *fmt,...) {
207 : char buf[1025]; unichar_t ubuf[1025];
208 : va_list ap;
209 :
210 0 : strcpy(buf,"Internal Error:\n");
211 0 : va_start(ap, fmt);
212 0 : vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, ap);
213 0 : va_end(ap);
214 0 : fprintf( stderr, "%s\n", buf );
215 0 : _GDraw_InitError(NULL);
216 0 : if ( error!=NULL ) {
217 0 : ProcessText(ubuf,buf,et_error);
218 0 : RunError();
219 : }
220 0 : }
221 :
222 0 : void GDrawError(const char *fmt,...) {
223 : char buf[1025]; unichar_t ubuf[1025];
224 : va_list ap;
225 :
226 0 : va_start(ap, fmt);
227 0 : vsprintf(buf, fmt, ap);
228 0 : va_end(ap);
229 0 : _GDraw_InitError(NULL);
230 0 : if ( error==NULL )
231 0 : fprintf( stderr, "%s\n", buf );
232 : else {
233 0 : ProcessText(ubuf,buf,et_error);
234 0 : RunError();
235 : }
236 0 : }
237 :
238 0 : void GDrawFatalError(const char *fmt,...) {
239 : char buf[1025]; unichar_t ubuf[1025];
240 : va_list ap;
241 :
242 0 : strcpy(buf,"Fatal Error:\n");
243 0 : va_start(ap, fmt);
244 0 : vsprintf(buf+strlen(buf), fmt, ap);
245 0 : va_end(ap);
246 0 : fprintf( stderr, "%s\n", buf );
247 0 : if ( error!=NULL ) {
248 0 : ProcessText(ubuf,buf,et_fatal);
249 0 : RunError();
250 : }
251 0 : exit(1);
252 : }
|