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 : #include "fontforgeui.h"
28 : #include <gfile.h>
29 : #include <stdarg.h>
30 : #include <unistd.h>
31 : #include <utype.h>
32 : #include <ustring.h>
33 : #include <sys/time.h>
34 : #include <gkeysym.h>
35 :
36 : extern GBox _ggadget_Default_Box;
37 : #define ACTIVE_BORDER (_ggadget_Default_Box.active_border)
38 : #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
39 :
40 : #if __CygWin
41 : extern void cygwin_conv_to_full_posix_path(const char *win,char *unx);
42 : extern void cygwin_conv_to_full_win32_path(const char *unx,char *win);
43 : #endif
44 :
45 : static char browser[1025];
46 :
47 0 : static void findbrowser(void) {
48 : /* Find a browser to use so that help messages can be displayed */
49 :
50 : /* Both xdg-open and htmlview are not browsers per se, but browser dispatchers*/
51 : /* which try to figure out what browser the user intents. It seems no one */
52 : /* uses (understands?) environment variables any more, so BROWSER is a bit */
53 : /* old-fashioned */
54 : static char *stdbrowsers[] = { "xdg-open", "x-www-browser", "htmlview",
55 : #if __Mac
56 : "safari",
57 : #endif
58 : "firefox", "mozilla", "seamonkey", "iceweasel", "opera", "konqueror", "google-chrome",
59 : "galeon", "kfmclient", "netscape", "mosaic", /*"grail",*/ "lynx",
60 : NULL };
61 : int i;
62 : char *path;
63 :
64 0 : if ( getenv("BROWSER")!=NULL ) {
65 0 : strncpy(browser,getenv("BROWSER"),sizeof(browser));
66 0 : browser[sizeof(browser)-1] = '\0';
67 0 : if ( strcmp(browser,"kde")==0 || strcmp(browser,"kfm")==0 ||
68 0 : strcmp(browser,"konqueror")==0 || strcmp(browser,"kfmclient")==0 )
69 0 : strcpy(browser,"kfmclient openURL");
70 0 : return;
71 : }
72 0 : for ( i=0; stdbrowsers[i]!=NULL; ++i ) {
73 0 : if ( (path=_GFile_find_program_dir(stdbrowsers[i]))!=NULL ) {
74 0 : if ( strcmp(stdbrowsers[i],"kfmclient")==0 )
75 0 : strcpy(browser,"kfmclient openURL");
76 : else
77 0 : strcpy(browser,stdbrowsers[i]);
78 0 : free(path);
79 0 : return;
80 : }
81 : }
82 : #if __Mac
83 : strcpy(browser,"open"); /* thanks to riggle */
84 : #endif
85 : }
86 :
87 0 : static int SupportedLocale(char *fullspec,char *locale) {
88 : /* If there's additional help files written for other languages, then check */
89 : /* to see if this local matches the additional help message language. If so */
90 : /* then report back that there's another language available to use for help */
91 : /* NOTE: If Docs are not maintained very well, maybe comment-out lang here. */
92 : int i;
93 : /* list languages in specific to generic order, ie: en_CA, en_GB, en... */
94 : static char *supported[] = { "de","ja", NULL }; /* other html lang list */
95 :
96 0 : for ( i=0; supported[i]!=NULL; ++i ) {
97 0 : if ( strcmp(locale,supported[i])==0 ) {
98 0 : strcat(fullspec,supported[i]);
99 0 : strcat(fullspec,"/");
100 0 : return( true );
101 : }
102 : }
103 0 : return( false );
104 : }
105 :
106 0 : static void AppendSupportedLocale(char *fullspec) {
107 : /* Add Browser HELP for this local if there's more html docs for this local */
108 :
109 : /* KANOU has provided a japanese translation of the docs */
110 : /* Edward Lee is working on traditional chinese docs */
111 0 : const char *loc = getenv("LC_ALL");
112 : char buffer[40], *pt;
113 :
114 0 : if ( loc==NULL ) loc = getenv("LC_CTYPE");
115 0 : if ( loc==NULL ) loc = getenv("LANG");
116 0 : if ( loc==NULL ) loc = getenv("LC_MESSAGES");
117 0 : if ( loc==NULL )
118 0 : return;
119 :
120 : /* first, try checking entire string */
121 0 : strncpy(buffer,loc,sizeof(buffer));
122 0 : buffer[sizeof(buffer)-1] = '\0';
123 0 : if ( SupportedLocale(fullspec,buffer) )
124 0 : return;
125 :
126 : /* parse possible suffixes, such as .UTF-8, then try again */
127 0 : if ( (pt=strchr(buffer,'.'))!=NULL ) {
128 0 : *pt = '\0';
129 0 : if ( SupportedLocale(fullspec,buffer) )
130 0 : return;
131 : }
132 :
133 : /* parse possible suffixes such as _CA, _GB, and try again */
134 0 : if ( (pt=strchr(buffer,'_'))!=NULL ) {
135 0 : *pt = '\0';
136 0 : if ( SupportedLocale(fullspec,buffer) )
137 0 : return;
138 : }
139 : }
140 :
141 : #ifdef _WIN32
142 : #include <gresource.h>
143 : #include <windows.h>
144 : void help(char *file) {
145 : if(file){
146 : int len = strlen(file);
147 : char* p_file = (char*) malloc(len+1);
148 : char* p_uri = (char*) malloc(len+1024);
149 : char* p_param = NULL;
150 :
151 : strcpy(p_file, file);
152 :
153 : {
154 : char* delim = strrchr(p_file, '#');
155 : if(delim){
156 : p_param = (char*) malloc(len+1);
157 : strcpy(p_param, delim);
158 : *delim = '\0';
159 : }
160 : }
161 :
162 : strcpy(p_uri, p_file);
163 :
164 : if(! GFileIsAbsolute(p_uri)){
165 : char* p_helpdir = (char*) malloc(1024);
166 :
167 : #if __CygWin
168 : { /* cygwin */
169 : #if defined(DOCDIR)
170 : strncpy( p_helpdir, DOCDIR "/", 1024 );
171 : #elif defined(SHAREDIR)
172 : strncpy( p_helpdir, SHAREDIR "/doc/fontforge/", 1024 );
173 : #else
174 : strncpy( p_helpdir, "/usr/local/share/doc/fontforge/", 1024 );
175 : #endif
176 : }
177 : #else
178 : { /* mingw */
179 : strcpy( p_helpdir, GResourceProgramDir );
180 : strcat( p_helpdir, "/doc/fontforge/");
181 : }
182 : #endif
183 :
184 : /* /usr/share/fontforge/doc/ja/file */
185 : strcpy(p_uri, p_helpdir);
186 : AppendSupportedLocale(p_uri);
187 : strcat(p_uri, p_file);
188 :
189 : if(!GFileReadable(p_uri)){
190 : strcpy(p_uri, p_helpdir);
191 : strcat(p_uri, p_file);
192 :
193 : if(!GFileReadable(p_uri)){
194 : strcpy(p_uri, "http://fontforge.org/");
195 : /* AppendSupportedLocale(p_uri); */
196 : strcat(p_uri, p_file);
197 : }
198 : }
199 : free(p_helpdir);
200 : }
201 :
202 : #if __CygWin
203 : if( strncmp(p_uri, "http:", 5) != 0 ){
204 : char* temp = (char*) malloc(1024);
205 : cygwin_conv_to_full_win32_path(p_uri, temp);
206 : free(p_uri);
207 : p_uri = temp;
208 : }
209 : #endif
210 :
211 : if(p_param){
212 : strcat(p_uri, p_param);
213 : free(p_param);
214 : }
215 :
216 : /* using default browser */
217 : ShellExecute(NULL, "open", p_uri, NULL, NULL, SW_SHOWDEFAULT);
218 :
219 : free(p_uri);
220 : free(p_file);
221 : }
222 : }
223 : #else
224 :
225 0 : void help(char *file) {
226 : char fullspec[PATH_MAX], *temp, *pt;
227 :
228 0 : if ( browser[0]=='\0' )
229 0 : findbrowser();
230 0 : if ( browser[0]=='\0' ) {
231 0 : gwwv_post_error(_("No Browser"),_("Could not find a browser. Set the BROWSER environment variable to point to one"));
232 0 : return;
233 : }
234 :
235 0 : if ( strstr(file,"http://")==NULL ) {
236 0 : memset(fullspec,0,sizeof(fullspec));
237 0 : if ( ! GFileIsAbsolute(file) )
238 0 : snprintf(fullspec, PATH_MAX, "%s", getHelpDir());
239 0 : strcat(fullspec,file);
240 0 : if (( pt = strrchr(fullspec,'#') )!=NULL ) *pt ='\0';
241 0 : if ( !GFileReadable( fullspec )) {
242 0 : if ( *file!='/' ) {
243 0 : strcpy(fullspec,"/usr/share/doc/fontforge/");
244 0 : strcat(fullspec,file);
245 0 : if (( pt = strrchr(fullspec,'#') )!=NULL ) *pt ='\0';
246 : }
247 : }
248 0 : if ( !GFileReadable( fullspec )) {
249 0 : strcpy(fullspec,"http://fontforge.sf.net/");
250 0 : AppendSupportedLocale(fullspec);
251 0 : strcat(fullspec,file);
252 0 : } else if ( pt!=NULL )
253 0 : *pt = '#';
254 : } else
255 0 : strncpy(fullspec,file,sizeof(fullspec));
256 : #if __Mac
257 : if ( strcmp(browser,"open")==0 )
258 : /* open doesn't want "file:" prepended */;
259 : else
260 : #endif
261 0 : if ( strstr(fullspec,":/")==NULL ) {
262 0 : if ( (temp=malloc(strlen(fullspec)+strlen("file:")+20))==NULL )
263 0 : return;
264 0 : sprintf(temp,"file:%s",fullspec);
265 0 : strncpy(fullspec,temp,sizeof(fullspec));
266 0 : fullspec[sizeof(fullspec)-1] = '\0';
267 0 : free(temp);
268 : }
269 : #if __Mac
270 : /* This seems a bit easier... Thanks to riggle */
271 : if ( strcmp(browser,"open")==0 ) {
272 : char *str = "DYLD_LIBRARY_PATH=\"\"; open ";
273 : if ( (temp=malloc(strlen(str) + strlen(fullspec) + 20))==NULL )
274 : return;
275 : sprintf( temp, "%s \"%s\" &", str, fullspec );
276 : system(temp);
277 : free(temp);
278 : } else {
279 : #else
280 : {
281 : #endif
282 0 : if ( (temp=malloc(strlen(browser) + strlen(fullspec) + 20))==NULL )
283 0 : return;
284 0 : sprintf( temp, strcmp(browser,"kfmclient openURL")==0 ? "%s \"%s\" &" : "\"%s\" \"%s\" &", browser, fullspec );
285 0 : system(temp);
286 0 : free(temp);
287 : }
288 : }
289 : #endif
290 :
291 1 : static void UI_IError(const char *format,...) {
292 : va_list ap;
293 : char buffer[300];
294 1 : va_start(ap,format);
295 1 : vsnprintf(buffer,sizeof(buffer),format,ap);
296 1 : GDrawIError("%s",buffer);
297 1 : va_end(ap);
298 1 : }
299 :
300 : #define MAX_ERR_LINES 400
301 : static struct errordata {
302 : char *errlines[MAX_ERR_LINES];
303 : GFont *font;
304 : int fh, as;
305 : GGadget *vsb;
306 : GWindow gw, v;
307 : int cnt, linecnt;
308 : int offtop;
309 : int showing;
310 : int start_l, start_c, end_l, end_c;
311 : int down;
312 : } errdata;
313 :
314 0 : static void ErrHide(void) {
315 0 : GDrawSetVisible(errdata.gw,false);
316 0 : errdata.showing = false;
317 0 : }
318 :
319 0 : static void ErrScroll(struct sbevent *sb) {
320 0 : int newpos = errdata.offtop;
321 :
322 0 : switch( sb->type ) {
323 : case et_sb_top:
324 0 : newpos = 0;
325 0 : break;
326 : case et_sb_uppage:
327 0 : newpos -= errdata.linecnt;
328 0 : break;
329 : case et_sb_up:
330 0 : --newpos;
331 0 : break;
332 : case et_sb_down:
333 0 : ++newpos;
334 0 : break;
335 : case et_sb_downpage:
336 0 : newpos += errdata.linecnt;
337 0 : break;
338 : case et_sb_bottom:
339 0 : newpos = errdata.cnt-errdata.linecnt;
340 0 : break;
341 : case et_sb_thumb:
342 : case et_sb_thumbrelease:
343 0 : newpos = sb->pos;
344 0 : break;
345 : }
346 0 : if ( newpos>errdata.cnt-errdata.linecnt )
347 0 : newpos = errdata.cnt-errdata.linecnt;
348 0 : if ( newpos<0 ) newpos =0;
349 0 : if ( newpos!=errdata.offtop ) {
350 0 : errdata.offtop = newpos;
351 0 : GScrollBarSetPos(errdata.vsb,errdata.offtop);
352 0 : GDrawRequestExpose(errdata.v,NULL,false);
353 : }
354 0 : }
355 :
356 0 : static int ErrChar(GEvent *e) {
357 0 : int newpos = errdata.offtop;
358 :
359 0 : switch( e->u.chr.keysym ) {
360 : case GK_Home:
361 0 : newpos = 0;
362 0 : break;
363 : case GK_End:
364 0 : newpos = errdata.cnt-errdata.linecnt;
365 0 : break;
366 : case GK_Page_Up: case GK_KP_Page_Up:
367 0 : newpos -= errdata.linecnt;
368 0 : break;
369 : case GK_Page_Down: case GK_KP_Page_Down:
370 0 : newpos += errdata.linecnt;
371 0 : break;
372 : case GK_Up: case GK_KP_Up:
373 0 : --newpos;
374 0 : break;
375 : case GK_Down: case GK_KP_Down:
376 0 : ++newpos;
377 0 : break;
378 : }
379 0 : if ( newpos>errdata.cnt-errdata.linecnt )
380 0 : newpos = errdata.cnt-errdata.linecnt;
381 0 : if ( newpos<0 ) newpos =0;
382 0 : if ( newpos!=errdata.offtop ) {
383 0 : errdata.offtop = newpos;
384 0 : GScrollBarSetPos(errdata.vsb,errdata.offtop);
385 0 : GDrawRequestExpose(errdata.v,NULL,false);
386 0 : return( true );
387 : }
388 0 : return( false );
389 : }
390 :
391 0 : static int warnings_e_h(GWindow gw, GEvent *event) {
392 :
393 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
394 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
395 0 : return( GGadgetDispatchEvent(errdata.vsb,event));
396 : }
397 :
398 0 : switch ( event->type ) {
399 : case et_char:
400 0 : return( ErrChar(event));
401 : break;
402 : case et_expose:
403 0 : break;
404 : case et_resize: {
405 : GRect size, sbsize;
406 0 : GDrawGetSize(gw,&size);
407 0 : GGadgetGetSize(errdata.vsb,&sbsize);
408 0 : GGadgetMove(errdata.vsb,size.width-sbsize.width,0);
409 0 : GGadgetResize(errdata.vsb,sbsize.width,size.height);
410 0 : GDrawResize(errdata.v,size.width-sbsize.width,size.height);
411 0 : errdata.linecnt = size.height/errdata.fh;
412 0 : GScrollBarSetBounds(errdata.vsb,0,errdata.cnt,errdata.linecnt);
413 0 : if ( errdata.offtop + errdata.linecnt > errdata.cnt ) {
414 0 : errdata.offtop = errdata.cnt-errdata.linecnt;
415 0 : if ( errdata.offtop < 0 ) errdata.offtop = 0;
416 0 : GScrollBarSetPos(errdata.vsb,errdata.offtop);
417 : }
418 0 : GDrawRequestExpose(errdata.v,NULL,false);
419 0 : } break;
420 : case et_controlevent:
421 0 : switch ( event->u.control.subtype ) {
422 : case et_scrollbarchange:
423 0 : ErrScroll(&event->u.control.u.sb);
424 0 : break;
425 : }
426 0 : break;
427 : case et_close:
428 0 : ErrHide();
429 0 : break;
430 : case et_create:
431 0 : break;
432 : case et_destroy:
433 0 : break;
434 : }
435 0 : return( true );
436 : }
437 :
438 0 : static void noop(void *_ed) {
439 0 : }
440 :
441 0 : static void *genutf8data(void *_ed,int32 *len) {
442 : int cnt, l;
443 0 : int s_l = errdata.start_l, s_c = errdata.start_c, e_l = errdata.end_l, e_c = errdata.end_c;
444 : char *ret, *pt;
445 :
446 0 : if ( s_l>e_l ) {
447 0 : s_l = e_l; s_c = e_c; e_l = errdata.start_l; e_c = errdata.start_c;
448 : }
449 :
450 0 : if ( s_l==-1 ) {
451 0 : *len = 0;
452 0 : return( copy(""));
453 : }
454 :
455 0 : l = s_l;
456 0 : if ( e_l == l ) {
457 0 : *len = e_c-s_c;
458 0 : return( copyn( errdata.errlines[l]+s_c, e_c-s_c ));
459 : }
460 :
461 0 : cnt = strlen(errdata.errlines[l]+s_c)+1;
462 0 : for ( ++l; l<e_l; ++l )
463 0 : cnt += strlen(errdata.errlines[l])+1;
464 0 : cnt += e_c;
465 :
466 0 : ret = malloc(cnt+1);
467 0 : strcpy( ret, errdata.errlines[s_l]+s_c );
468 0 : pt = ret+strlen( ret );
469 0 : *pt++ = '\n';
470 0 : for ( l=s_l+1; l<e_l; ++l ) {
471 0 : strcpy(pt,errdata.errlines[l]);
472 0 : pt += strlen(pt);
473 0 : *pt++ = '\n';
474 : }
475 0 : strncpy(pt,errdata.errlines[l],e_c);
476 0 : *len = cnt;
477 0 : return( ret );
478 : }
479 :
480 0 : static void MouseToPos(GEvent *event,int *_l, int *_c) {
481 0 : int l,c=0;
482 :
483 0 : GDrawSetFont(errdata.v,errdata.font);
484 0 : l = event->u.mouse.y/errdata.fh + errdata.offtop;
485 0 : if ( l>=errdata.cnt ) {
486 0 : l = errdata.cnt-1;
487 0 : if ( l>=0 )
488 0 : c = strlen(errdata.errlines[l]);
489 0 : } else if ( l>=0 ) {
490 0 : GDrawLayoutInit(errdata.v,errdata.errlines[l],-1,NULL);
491 0 : c = GDrawLayoutXYToIndex(errdata.v,event->u.mouse.x-3,4);
492 : }
493 0 : *_l = l;
494 0 : *_c = c;
495 0 : }
496 :
497 0 : static void WarnMenuCopy(GWindow gw,struct gmenuitem *mi,GEvent *e) {
498 0 : GDrawGrabSelection(gw,sn_clipboard);
499 0 : GDrawAddSelectionType(gw,sn_clipboard,"UTF8_STRING",&errdata,1,
500 : sizeof(char),
501 : genutf8data,noop);
502 0 : GDrawAddSelectionType(gw,sn_clipboard,"STRING",&errdata,1,
503 : sizeof(char),
504 : genutf8data,noop);
505 0 : }
506 :
507 0 : static void WarnMenuClear(GWindow gw,struct gmenuitem *mi,GEvent *e) {
508 : int i;
509 :
510 0 : for ( i=0; i<errdata.cnt; ++i ) {
511 0 : free(errdata.errlines[i]);
512 0 : errdata.errlines[i] = NULL;
513 : }
514 0 : errdata.cnt = 0;
515 0 : GDrawRequestExpose(gw,NULL,false);
516 0 : }
517 :
518 : #define MID_Copy 1
519 : #define MID_Clear 2
520 :
521 : GMenuItem warnpopupmenu[] = {
522 : { { (unichar_t *) N_("Cu_t"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, NULL, 0 },
523 : { { (unichar_t *) N_("_Copy"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 'C' }, '\0', ksm_control, NULL, NULL, WarnMenuCopy, MID_Copy },
524 : { { (unichar_t *) N_("_Paste"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'P' }, '\0', ksm_control, NULL, NULL, NULL, 0 },
525 : { { (unichar_t *) N_("C_lear"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 'l' }, 0, 0, NULL, NULL, WarnMenuClear, MID_Clear },
526 : GMENUITEM_EMPTY
527 : };
528 :
529 0 : static int warningsv_e_h(GWindow gw, GEvent *event) {
530 : int i;
531 : extern GBox _ggadget_Default_Box;
532 :
533 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
534 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
535 0 : return( GGadgetDispatchEvent(errdata.vsb,event));
536 : }
537 :
538 0 : switch ( event->type ) {
539 : case et_expose:
540 : /*GDrawFillRect(gw,&event->u.expose.rect,GDrawGetDefaultBackground(NULL));*/
541 0 : GDrawSetFont(gw,errdata.font);
542 0 : for ( i=0; i<errdata.linecnt && i+errdata.offtop<errdata.cnt; ++i ) {
543 : int xs, xe;
544 0 : int s_l = errdata.start_l, s_c = errdata.start_c, e_l = errdata.end_l, e_c = errdata.end_c;
545 : GRect r;
546 0 : if ( s_l>e_l ) {
547 0 : s_l = e_l; s_c = e_c; e_l = errdata.start_l; e_c = errdata.start_c;
548 : }
549 0 : GDrawLayoutInit(gw,errdata.errlines[i+errdata.offtop],-1,NULL);
550 0 : if ( i+errdata.offtop >= s_l && i+errdata.offtop <= e_l ) {
551 0 : if ( i+errdata.offtop > s_l )
552 0 : xs = 0;
553 : else {
554 : GRect pos;
555 0 : GDrawLayoutIndexToPos(gw,s_c,&pos);
556 0 : xs = pos.x+3;
557 : }
558 0 : if ( i+errdata.offtop < e_l )
559 0 : xe = 3000;
560 : else {
561 : GRect pos;
562 0 : GDrawLayoutIndexToPos(gw,s_c,&pos);
563 0 : xe = pos.x+pos.width+3;
564 : }
565 0 : r.x = xs+3; r.width = xe-xs;
566 0 : r.y = i*errdata.fh; r.height = errdata.fh;
567 0 : GDrawFillRect(gw,&r,ACTIVE_BORDER);
568 : }
569 0 : GDrawLayoutDraw(gw,3,i*errdata.fh+errdata.as,MAIN_FOREGROUND);
570 : }
571 0 : break;
572 : case et_char:
573 0 : return( ErrChar(event));
574 : break;
575 : case et_mousedown:
576 0 : if ( event->u.mouse.button==3 ) {
577 0 : warnpopupmenu[1].ti.disabled = errdata.start_l == -1;
578 0 : warnpopupmenu[3].ti.disabled = errdata.cnt == 0;
579 0 : GMenuCreatePopupMenu(gw,event, warnpopupmenu);
580 : } else {
581 0 : if ( errdata.down )
582 0 : return( true );
583 0 : MouseToPos(event,&errdata.start_l,&errdata.start_c);
584 0 : errdata.down = true;
585 : }
586 : case et_mousemove:
587 : case et_mouseup:
588 0 : if ( !errdata.down )
589 0 : return( true );
590 0 : MouseToPos(event,&errdata.end_l,&errdata.end_c);
591 0 : GDrawRequestExpose(gw,NULL,false);
592 0 : if ( event->type==et_mouseup ) {
593 0 : errdata.down = false;
594 0 : if ( errdata.start_l == errdata.end_l && errdata.start_c == errdata.end_c ) {
595 0 : errdata.start_l = errdata.end_l = -1;
596 : } else {
597 0 : GDrawGrabSelection(gw,sn_primary);
598 0 : GDrawAddSelectionType(gw,sn_primary,"UTF8_STRING",&errdata,1,
599 : sizeof(char),
600 : genutf8data,noop);
601 0 : GDrawAddSelectionType(gw,sn_primary,"STRING",&errdata,1,
602 : sizeof(char),
603 : genutf8data,noop);
604 : }
605 : }
606 0 : break;
607 : case et_selclear:
608 0 : errdata.start_l = errdata.end_l = -1;
609 0 : GDrawRequestExpose(gw,NULL,false);
610 0 : break;
611 : case et_timer:
612 0 : break;
613 : case et_focus:
614 0 : break;
615 : }
616 0 : return( true );
617 : }
618 :
619 0 : static void CreateErrorWindow(void) {
620 : GWindowAttrs wattrs;
621 : FontRequest rq;
622 : GRect pos,size;
623 : int as, ds, ld;
624 : GWindow gw;
625 : GGadgetData gd;
626 : extern int _GScrollBar_Width;
627 :
628 0 : GDrawGetSize(GDrawGetRoot(NULL),&size);
629 :
630 0 : memset(&wattrs,0,sizeof(wattrs));
631 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_isdlg|wam_positioned;
632 0 : wattrs.event_masks = ~(1<<et_charup);
633 0 : wattrs.is_dlg = true;
634 0 : wattrs.cursor = ct_pointer;
635 0 : wattrs.positioned = true;
636 0 : wattrs.utf8_window_title = _("Warnings");
637 0 : pos.width = GDrawPointsToPixels(NULL,GGadgetScale(400));
638 0 : pos.height = GDrawPointsToPixels(NULL,GGadgetScale(100));
639 0 : pos.x = size.width - pos.width - 10;
640 0 : pos.y = size.height - pos.height - 30;
641 0 : errdata.gw = gw = GDrawCreateTopWindow(NULL,&pos,warnings_e_h,&errdata,&wattrs);
642 :
643 0 : memset(&rq,0,sizeof(rq));
644 0 : rq.utf8_family_name = SANS_UI_FAMILIES;
645 0 : rq.point_size = 10;
646 0 : rq.weight = 400;
647 0 : errdata.font = GDrawInstanciateFont(NULL,&rq);
648 0 : errdata.font = GResourceFindFont("Warnings.Font",errdata.font);
649 0 : GDrawWindowFontMetrics(errdata.gw,errdata.font,&as,&ds,&ld);
650 0 : errdata.as = as;
651 0 : errdata.fh = as+ds;
652 :
653 0 : memset(&gd,0,sizeof(gd));
654 0 : gd.pos.y = 0; gd.pos.height = pos.height;
655 0 : gd.pos.width = GDrawPointsToPixels(gw,_GScrollBar_Width);
656 0 : gd.pos.x = pos.width-gd.pos.width;
657 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
658 0 : errdata.vsb = GScrollBarCreate(gw,&gd,&errdata);
659 :
660 0 : pos.width -= gd.pos.width;
661 0 : pos.x = pos.y = 0;
662 0 : wattrs.mask = wam_events|wam_cursor;
663 0 : errdata.v = GWidgetCreateSubWindow(gw,&pos,warningsv_e_h,&errdata,&wattrs);
664 0 : GDrawSetVisible(errdata.v,true);
665 :
666 0 : errdata.linecnt = pos.height/errdata.fh;
667 0 : errdata.start_l = errdata.end_l = -1;
668 0 : }
669 :
670 0 : static void AppendToErrorWindow(char *buffer) {
671 : int i,linecnt;
672 : char *pt,*end;
673 :
674 0 : if ( buffer[strlen(buffer)-1]=='\n' ) buffer[strlen(buffer)-1] = '\0';
675 :
676 0 : for ( linecnt=1, pt=buffer; (pt=strchr(pt,'\n'))!=NULL; ++linecnt )
677 0 : ++pt;
678 0 : if ( errdata.cnt + linecnt > MAX_ERR_LINES ) {
679 0 : int off = errdata.cnt + linecnt - MAX_ERR_LINES;
680 0 : for ( i=0; i<off; ++i )
681 0 : free(errdata.errlines[i]);
682 0 : for ( /*i=off*/; i<errdata.cnt; ++i )
683 0 : errdata.errlines[i-off] = errdata.errlines[i];
684 0 : for ( ; i<MAX_ERR_LINES+off ; ++i )
685 0 : errdata.errlines[i-off] = NULL;
686 0 : errdata.cnt -= off;
687 0 : if (( errdata.start_l -= off)< 0 ) errdata.start_l = errdata.start_c = 0;
688 0 : if (( errdata.end_l -= off)< 0 ) errdata.end_l = errdata.start_l = -1;
689 : }
690 0 : for ( i=errdata.cnt, pt=buffer; i<MAX_ERR_LINES; ++i ) {
691 0 : end = strchr(pt,'\n');
692 0 : if ( end==NULL ) end = pt+strlen(pt);
693 0 : errdata.errlines[i] = copyn(pt,end-pt);
694 0 : pt = end;
695 0 : if ( *pt=='\0' ) {
696 0 : ++i;
697 0 : break;
698 : }
699 0 : ++pt;
700 : }
701 0 : errdata.cnt = i;
702 :
703 0 : errdata.offtop = errdata.cnt - errdata.linecnt;
704 0 : if ( errdata.offtop<0 ) errdata.offtop = 0;
705 0 : GScrollBarSetBounds(errdata.vsb,0,errdata.cnt,errdata.linecnt);
706 0 : GScrollBarSetPos(errdata.vsb,errdata.offtop);
707 0 : }
708 :
709 0 : int ErrorWindowExists(void) {
710 0 : return( errdata.gw!=NULL );
711 : }
712 :
713 0 : void ShowErrorWindow(void) {
714 0 : if ( errdata.gw==NULL )
715 0 : return;
716 0 : GDrawSetVisible(errdata.gw,true);
717 0 : GDrawRaise(errdata.gw);
718 0 : if ( errdata.showing )
719 0 : GDrawRequestExpose(errdata.v,NULL,false);
720 0 : errdata.showing = true;
721 : }
722 :
723 201 : static void _LogError(const char *format,va_list ap) {
724 : char buffer[2500], nbuffer[2600], *str, *pt, *npt;
725 201 : vsnprintf(buffer,sizeof(buffer),format,ap);
726 17831 : for ( pt=buffer, npt=nbuffer; *pt!='\0' && npt<nbuffer+sizeof(nbuffer)-2; ) {
727 17429 : *npt++ = *pt++;
728 17429 : if ( pt[-1]=='\n' && *pt!='\0' ) {
729 : /* Force an indent of at least two spaces on secondary lines of a warning */
730 50 : if ( npt<nbuffer+sizeof(nbuffer)-2 ) {
731 50 : *npt++ = ' ';
732 50 : if ( *pt==' ' ) ++pt;
733 : }
734 50 : if ( npt<nbuffer+sizeof(nbuffer)-2 ) {
735 50 : *npt++ = ' ';
736 50 : if ( *pt==' ' ) ++pt;
737 : }
738 : }
739 : }
740 201 : *npt='\0';
741 :
742 201 : if ( no_windowing_ui || screen_display==NULL ) {
743 201 : str = utf82def_copy(nbuffer);
744 201 : fprintf(stderr,"%s",str);
745 201 : if ( str[strlen(str)-1]!='\n' )
746 154 : putc('\n',stderr);
747 201 : free(str);
748 : } else {
749 0 : if ( !ErrorWindowExists())
750 0 : CreateErrorWindow();
751 0 : AppendToErrorWindow(nbuffer);
752 0 : ShowErrorWindow();
753 : }
754 201 : }
755 :
756 201 : static void UI_LogError(const char *format,...) {
757 : va_list ap;
758 :
759 201 : va_start(ap,format);
760 201 : _LogError(format,ap);
761 201 : va_end(ap);
762 201 : }
763 :
764 0 : static void UI_post_notice(const char *title,const char *statement,...) {
765 : va_list ap;
766 0 : va_start(ap,statement);
767 0 : if ( no_windowing_ui ) {
768 0 : _LogError(statement,ap);
769 : } else {
770 0 : if ( GWidgetPostNoticeActive8(title))
771 0 : _LogError(statement,ap);
772 : else
773 0 : _GWidgetPostNotice8(title,statement,ap,40);
774 : }
775 0 : va_end(ap);
776 0 : }
777 :
778 0 : static char *UI_open_file(const char *title, const char *defaultfile,
779 : const char *initial_filter) {
780 0 : return( gwwv_open_filename(title,defaultfile,initial_filter,NULL) );
781 : }
782 :
783 0 : static char *UI_saveas_file(const char *title, const char *defaultfile,
784 : const char *initial_filter) {
785 0 : return( gwwv_save_filename(title,defaultfile,initial_filter) );
786 : }
787 :
788 0 : static void tinysleep(int microsecs) {
789 : #if !defined(__MINGW32__)
790 : fd_set none;
791 : struct timeval timeout;
792 :
793 0 : FD_ZERO(&none);
794 0 : memset(&timeout,0,sizeof(timeout));
795 0 : timeout.tv_usec = microsecs;
796 :
797 0 : select(1,&none,&none,&none,&timeout);
798 : #endif
799 0 : }
800 :
801 0 : static void allow_events(void) {
802 0 : GDrawSync(NULL);
803 0 : tinysleep(100);
804 0 : GDrawProcessPendingEvents(NULL);
805 0 : }
806 :
807 :
808 : struct ui_interface gdraw_ui_interface = {
809 : UI_IError,
810 : gwwv_post_error,
811 : UI_LogError,
812 : UI_post_notice,
813 : gwwv_ask_centered,
814 : gwwv_choose,
815 : gwwv_choose_multiple,
816 : gwwv_ask_string,
817 : gwwv_ask_password,
818 : UI_open_file,
819 : UI_saveas_file,
820 : gwwv_progress_start_indicator,
821 : gwwv_progress_end_indicator,
822 : gwwv_progress_show,
823 : gwwv_progress_enable_stop,
824 : gwwv_progress_next,
825 : gwwv_progress_next_stage,
826 : gwwv_progress_increment,
827 : gwwv_progress_change_line1,
828 : gwwv_progress_change_line2,
829 : gwwv_progress_pause_timer,
830 : gwwv_progress_resume_timer,
831 : gwwv_progress_change_stages,
832 : gwwv_progress_change_total,
833 : gwwv_progress_reset,
834 :
835 : allow_events,
836 :
837 : UI_TTFNameIds,
838 : UI_MSLangString,
839 : (int (*)(void)) Ps_StrokeFlagsDlg
840 : };
841 :
|