1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "xutil.h"
8 #include "afni_environ.h"
9 #include "debugtrace.h"    /* 12 Mar 2001 */
10 #include <time.h>
11 
12 #undef  SYNC
13 #define SYNC(w) XSync(XtDisplay(w),False)
14 
15 #include "Amalloc.h"
16 extern char * THD_find_executable( char * ) ;
17 
18 /*--------------------------------------------------------------------
19   force an immediate expose for the widget
20 ----------------------------------------------------------------------*/
21 
22 /****************************************
23   requires the following line somewhere
24 
25 #include <X11/IntrinsicP.h>
26 
27 *****************************************/
28 
MCW_expose_widget(Widget w)29 void MCW_expose_widget( Widget w )
30 {
31    XExposeEvent xev;
32    Dimension ww=0 , hh=0 ;
33 
34    memset(&xev, 0, sizeof(xev));
35 
36                                if(   w == NULL                 ) return ;
37                                if( ! XtIsRealized(w)           ) return ;
38                                if( ! XtIsManaged(w)            ) return ;
39                                if( ! XtIsWidget(w)             ) return ;
40    xev.window  = XtWindow(w) ; if( xev.window == (Window) NULL ) return ;
41    xev.type    = Expose ;
42    xev.display = XtDisplay(w) ;
43    xev.x       = xev.y = 0 ; SYNC(w) ;
44    XtVaGetValues( w, XmNwidth, &ww, XmNheight, &hh, NULL ) ;
45    if( ww <= 0 || hh <= 0 ) return ;
46    xev.width   = ww ; xev.height  = hh ;
47    (XtClass (w))->core_class.expose( w, (XEvent *)&xev, NULL ) ;
48    XFlush( XtDisplay(w) ) ;
49    return ;
50 }
51 
52 /*--------------------------------------------------------------------
53   Get the Colormap for a widget -- 01 Sep 1998
54 ----------------------------------------------------------------------*/
55 
MCW_get_colormap(Widget w)56 Colormap MCW_get_colormap( Widget w )
57 {
58    Colormap cmap = (Colormap) 0 ;
59 
60    if( w == NULL || ! XtIsWidget(w) ) return (Colormap) 0 ;
61 
62    SYNC(w) ;
63    XtVaGetValues( w , XmNcolormap  , &cmap , NULL ) ;
64    return cmap ;
65 }
66 
67 /*--------------------------------------------------------------------*/
68 
MCW_get_depth(Widget w)69 int MCW_get_depth( Widget w )  /* 14 Sep 1998 */
70 {
71    int depth = 0 ;
72 
73    if( w == NULL || ! XtIsWidget(w) ) return 0 ;
74    SYNC(w) ;
75    XtVaGetValues( w , XmNdepth  , &depth , NULL ) ;
76    return depth  ;
77 }
78 
79 /*--------------------------------------------------------------------*/
80 
MCW_get_visual(Widget w)81 Visual * MCW_get_visual( Widget w )  /* 14 Sep 1998 */
82 {
83    Visual *visual = NULL ;
84    Widget wpar = w ;
85 
86    if( w == NULL || ! XtIsWidget(w) ) return NULL ;
87    SYNC(w) ;
88 
89    while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ;  /* find top */
90 
91    XtVaGetValues( wpar , XmNvisual , &visual , NULL ) ;
92    return visual ;
93 }
94 
95 /*--------------------------------------------------------------------
96   Set the Colormap for a widget -- 14 Sep 1998
97   (Will only work if widget is not yet realized)
98 ----------------------------------------------------------------------*/
99 
MCW_set_colormap(Widget w,Colormap cmap)100 void MCW_set_colormap( Widget w , Colormap cmap )
101 {
102    if( w == NULL || ! XtIsWidget(w) ) return ;
103    SYNC(w) ;
104    XtVaSetValues( w , XmNcolormap  , cmap , NULL ) ;
105    return ;
106 }
107 
108 /*--------------------------------------------------------------------
109    swap the fg and bg colors of a widget
110    (the shadow colors are altered to fit the new bg)
111 ----------------------------------------------------------------------*/
MCW_invert_widget(Widget w)112 void MCW_invert_widget( Widget w ) { return(MCW_invert_widget_sync(w,1)); }
113 
MCW_invert_widget_sync(Widget w,int sync)114 void MCW_invert_widget_sync( Widget w , int sync)
115 {
116    Pixel bg_pix=0 , topsh_pix=0 , botsh_pix=0 , fg_pix=0 , sel_pix=0 ;
117    Colormap cmap ;
118 
119    memset(&cmap, 0, sizeof(cmap));
120 
121    if( ! XtIsWidget(w) ) return ;
122    if (sync) { SYNC(w) ; }
123 
124    XtVaGetValues( w , XmNforeground , &bg_pix ,  /* foreground -> bg */
125                       XmNbackground , &fg_pix ,  /* background -> fg */
126                       XmNcolormap   , &cmap ,
127                   NULL ) ;
128 
129    XmGetColors( XtScreen(w) , cmap , bg_pix ,
130                 NULL , &topsh_pix , &botsh_pix , &sel_pix ) ;
131 
132    XtVaSetValues( w ,
133                     XmNtopShadowColor    , topsh_pix ,
134                     XmNbottomShadowColor , botsh_pix ,
135                     XmNselectColor       , sel_pix   ,
136                     XmNarmColor          , sel_pix   ,
137                     XmNborderColor       , fg_pix    ,
138                     XmNforeground        , fg_pix    ,
139                     XmNbackground        , bg_pix    ,
140                   NULL ) ;
141 
142    if (sync) {
143       XSync( XtDisplay(w) , False ) ;  /* make it happen NOW */
144       XmUpdateDisplay( w ) ;
145    }
146    return ;
147 }
148 
149 /*---------------------------------------------------------------------*/
150 
MCW_flash_widget(int ntime,Widget w)151 void MCW_flash_widget( int ntime , Widget w )  /* 12 Feb 2010 */
152 {
153    int ii ;
154 
155    if( ! XtIsWidget(w) ) return ;
156    if( ntime < 1 ) ntime = 1 ;
157 
158    for( ii=0 ; ii < ntime ; ii++ ){
159      MCW_invert_widget(w) ; RWC_sleep(100) ;
160      MCW_invert_widget(w) ; RWC_sleep(100) ;
161    }
162 
163    return ;
164 }
165 
166 /*---------------------------------------------------------------------*/
167 
MCW_flash_widget_list(int ntime,...)168 void MCW_flash_widget_list( int ntime , ... )
169 {
170    int ii,kk , nwid=0 ; Widget w , *war=NULL ;
171    va_list vararg_ptr ;
172 
173    if( ntime < 1 ) ntime = 1 ;
174 
175    va_start( vararg_ptr , ntime ) ;
176 
177    while(1){
178      w = va_arg( vararg_ptr , Widget ) ;
179      if( w == (Widget)NULL ) break ;
180      war = (Widget *)realloc(war,sizeof(Widget)*(nwid+1)) ;
181      war[nwid++] = w ;
182    }
183    va_end( vararg_ptr ) ;
184    if( nwid < 1 ) return ;
185 
186    for( ii=0 ; ii < ntime ; ii++ ){
187      for( kk=0 ; kk < nwid ; kk++ ) MCW_invert_widget(war[kk]) ;
188      RWC_sleep(100) ;
189      for( kk=0 ; kk < nwid ; kk++ ) MCW_invert_widget(war[kk]) ;
190      RWC_sleep(100) ;
191    }
192 
193    free(war) ; return ;
194 }
195 
196 /*---------------------------------------------------------------------
197    set the background color of a widget; the other colors are
198    altered to match, a la Motif;
199      cname = character specification of color
200      pix   = if cname == NULL, use this pixel value
201 -----------------------------------------------------------------------*/
202 
MCW_set_widget_bg(Widget w,char * cname,Pixel pix)203 void MCW_set_widget_bg( Widget w , char *cname , Pixel pix )
204 {
205    Pixel bg_pix=0 , topsh_pix=0 , botsh_pix=0 , fg_pix=0 , sel_pix=0 ;
206    Colormap cmap ;
207 
208    memset(&cmap, 0, sizeof(cmap));
209 
210 #if 1
211    if( ! XtIsWidget(w) ) return ;
212 #else
213    if( ! XtIsObject(w) ) return ;
214 #endif
215 
216    SYNC(w) ;
217 
218    if( cname != NULL && strlen(cname) > 0 ){
219       XtVaSetValues( w ,
220                      XtVaTypedArg , XmNbackground , XmRString ,
221                                     cname , strlen(cname)+1 ,
222                      NULL ) ;
223 
224       XtVaGetValues( w , XmNbackground , &bg_pix , NULL ) ;
225    } else {
226       bg_pix = pix ;
227    }
228 
229 #if 0
230    XtVaGetValues( w , XmNcolormap , &cmap , NULL ) ;
231    XmGetColors( XtScreen(w) , cmap , bg_pix ,
232                 &fg_pix , &topsh_pix , &botsh_pix , &sel_pix ) ;
233    XtVaSetValues( w ,
234                     XmNtopShadowColor    , topsh_pix ,
235                     XmNbottomShadowColor , botsh_pix ,
236                     XmNselectColor       , sel_pix   ,
237                     XmNarmColor          , sel_pix   ,
238                     XmNborderColor       , fg_pix    ,
239                     XmNforeground        , fg_pix    ,
240                     XmNbackground        , bg_pix    ,
241                   NULL ) ;
242    XFlush( XtDisplay(w) ) ;
243 #else
244    XmChangeColor( w , bg_pix ) ;
245 #endif
246 
247    if( XmIsToggleButton(w) ){   /* 18 Sep 2009 */
248      Pixel  fg_pix=0 ;
249      XtVaGetValues( w , XmNforeground , &fg_pix , NULL ) ;
250      XtVaSetValues( w , XmNselectColor,  fg_pix , NULL ) ;
251    }
252 
253    return ;
254 }
255 
256 /*-------------------------------------------------------------------*/
257 
MCW_scale_widget_bg(Widget w,float fac,MCW_DC * dc)258 void MCW_scale_widget_bg( Widget w , float fac , MCW_DC *dc )
259 {
260    Pixel bg_pix=0 ; byte rr,gg,bb ;
261    unsigned int nr,ng,nb ;
262    float aa , fr,fg,fb , ff ;
263 
264    if( !XtIsWidget(w) || dc == NULL || fac < 0.0f || fac > 2.0f ) return ;
265 
266 
267    XtVaGetValues( w , XmNbackground , &bg_pix , NULL ) ;
268    DC_pixel_to_rgb( dc , bg_pix , &rr,&gg,&bb ) ;
269    aa = (fac > 1.0f) ? 1.0f : 0.0f ;
270    nr = aa+fac*rr ; ng = aa+fac*gg ; nb = aa+fac*bb ;
271    fr = fg = fb = fac ;
272    if( nr > 255 ){ nr = 255 ; fr = 255.0f/rr ; }
273    if( ng > 255 ){ ng = 255 ; fg = 255.0f/gg ; }
274    if( nb > 255 ){ nb = 255 ; fb = 255.0f/bb ; }
275    ff = MIN(fr,fac) ; ff = MIN(fg,ff) ; ff = MIN(fb,ff) ;
276    if( ff < fac ){ nr = aa+ff*rr ; ng = aa+ff*gg ; nb = aa+ff*bb ; }
277    if( nr > 255 ) nr = 255 ; else if( nr == 0 ) nr = lrand48()%32 ;
278    if( ng > 255 ) ng = 255 ; else if( ng == 0 ) ng = lrand48()%16 ;
279    if( nb > 255 ) nb = 255 ; else if( nb == 0 ) nb = lrand48()%24 ;
280 #if 0
281 INFO_message("scale_bg:  %u %u %u  ==>  %u %u %u",
282              (unsigned int)rr, (unsigned int)gg, (unsigned int)bb, nr,ng,nb ) ;
283 #endif
284    rr = (byte)nr ; gg = (byte)ng ; bb = (byte)nb ;
285    bg_pix = DC_rgb_to_pixel( dc , rr,gg,bb ) ;
286    MCW_set_widget_bg( w , NULL , bg_pix ) ;
287    return ;
288 }
289 
290 /*-------------------------------------------------------------------*/
291 
MCW_set_widget_fg(Widget w,char * cname)292 void MCW_set_widget_fg( Widget w , char *cname )
293 {
294    Pixel bg_pix , topsh_pix , botsh_pix , fg_pix , sel_pix ;
295    Colormap cmap ;
296 
297    if( !XtIsWidget(w) || cname == NULL || *cname == '\0' ) return ;
298 
299    SYNC(w) ;
300 
301    XtVaSetValues( w , XtVaTypedArg , XmNforeground , XmRString ,
302                                      cname , strlen(cname)+1 , NULL ) ;
303    return ;
304 }
305 
306 /*-------------------------------------------------------------------*/
307 
MCW_set_widget_label(Widget w,char * str)308 void MCW_set_widget_label( Widget w , char *str )
309 {
310    XmString xstr ;
311    if( w == NULL || str == NULL ) return ;
312    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
313    XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
314    XmStringFree( xstr ) ;
315    MCW_expose_widget( w ) ;
316    return ;
317 }
318 
319 #if 0
320 void MCW_set_widget_label_tagged( Widget w , char *str , char *tag )
321 {
322    XmString xstr ;
323    if( w == NULL || str == NULL ) return ;
324    xstr = XmStringCreateLtoR( str , tag ) ;
325    XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
326    XmStringFree( xstr ) ;
327    MCW_expose_widget( w ) ;
328    return ;
329 }
330 #endif
331 
332 /*-----------------------------------------------------------------------*/
333 
MCW_widget_geom(Widget w,int * wout,int * hout,int * xout,int * yout)334 void MCW_widget_geom( Widget w, int *wout, int *hout, int *xout, int *yout )
335 {
336    Dimension nx=0 , ny=0 ;  /* don't try to make these ints! */
337    Position  xx=0 , yy=0 ;
338 
339    if( w == NULL ) return ; /* user == loser */
340    SYNC(w) ; RWC_sleep(1) ;
341 
342    if( XtIsRealized(w) ){
343       XtVaGetValues( w , XmNwidth  , &nx , XmNheight , &ny ,
344                          XmNx      , &xx , XmNy      , &yy , NULL ) ;
345    } else {
346       XtWidgetGeometry wg ;
347       memset(&wg, 0, sizeof(wg)); /* probably doesn't matter, but be safe */
348       (void) XtQueryGeometry( w , NULL , &wg ) ;   /* works! */
349       nx = wg.width ; ny = wg.height ;
350       xx = wg.x     ; yy = wg.y      ;
351    }
352 
353 #define ASSIF(p,v) if( p!= NULL ) *p = v
354 
355    ASSIF(wout,nx) ; ASSIF(hout,ny) ;
356    ASSIF(xout,xx) ; ASSIF(yout,yy) ;
357 
358    return ;
359 }
360 
361 /*--------------------------------------------------------------------------*/
362 
MCW_discard_events(Widget w,int ev_mask)363 void MCW_discard_events( Widget w , int ev_mask )
364 {
365    XEvent evjunk ;
366 
367    if( w == NULL || XtWindow(w) == (Window) NULL ) return ;
368 
369    XSync( XtDisplay(w) , False ) ;
370    while( XCheckWindowEvent( XtDisplay(w), XtWindow(w) , ev_mask , &evjunk ) ) ;
371    return ;
372 }
373 
374 /*--------------------------------------------------------------------------*/
375 
MCW_discard_events_all(Widget w,int ev_mask)376 void MCW_discard_events_all( Widget w , int ev_mask )
377 {
378    XEvent evjunk ;
379 
380    if( w == NULL || XtWindow(w) == (Window) NULL ) return ;
381 
382    XSync( XtDisplay(w) , False ) ;
383    while( XCheckMaskEvent( XtDisplay(w), ev_mask , &evjunk ) ) ;
384    return ;
385 }
386 
387 /*--------------------------------------------------------------------------*/
388 
MCW_hotcolor(Widget w)389 char * MCW_hotcolor(Widget w)
390 {
391    static char *redcolor = NULL ;
392 
393    if( redcolor == NULL ){
394      char *xdef = RWC_getname( (w!=NULL) ? XtDisplay(w) : NULL, "hotcolor" ) ;
395 
396      redcolor = (xdef != NULL) ? (xdef) : ("red4") ;
397    }
398    return redcolor ;
399 }
400 
401 /*--------------------------------------------------------------------------*/
402 
MCW_buthighlight(Widget w)403 char * MCW_buthighlight(Widget w)
404 {
405    static char *buthighlight = NULL ;
406 
407    if( buthighlight == NULL ){
408      char *xdef = RWC_getname( (w!=NULL) ? XtDisplay(w) : NULL,
409                                                 "buthighlight" ) ;
410 
411      buthighlight = (xdef != NULL) ? (xdef) : ("blue2") ;
412    }
413    return buthighlight ;
414 }
415 
416 /*--------------------------------------------------------------------------
417    24 Apr 2001: manage array of widgets, some of which may be NULL
418 ----------------------------------------------------------------------------*/
419 
MCW_manage_widgets(Widget * war,int nar)420 void MCW_manage_widgets( Widget *war , int nar )
421 {
422    int ii ;
423    if( war == NULL ) return ;
424    for( ii=0 ; ii < nar ; ii++ )
425       if( war[ii] != (Widget) 0 ) XtManageChild( war[ii] ) ;
426    return ;
427 }
428 
MCW_unmanage_widgets(Widget * war,int nar)429 void MCW_unmanage_widgets( Widget *war , int nar )
430 {
431    int ii ;
432    if( war == NULL ) return ;
433    for( ii=0 ; ii < nar ; ii++ )
434       if( war[ii] != (Widget) 0 ) XtUnmanageChild( war[ii] ) ;
435    return ;
436 }
437 
438 /*--------------------------------------------------------------------------*/
439 
440 #define TIG 25
441 
MCW_action_area(Widget parent,MCW_action_item * action,int num_act)442 Widget MCW_action_area( Widget parent, MCW_action_item *action, int num_act )
443 {
444    Widget act_area , ww ;
445    int ii ;
446 
447    if( parent == NULL ) return NULL ;  /* should not happen */
448 
449    act_area = XtVaCreateWidget( "action_area" , xmFormWidgetClass , parent ,
450                                     XmNfractionBase , TIG*num_act - 1,
451 
452                                     XmNinitialResourcesPersistent , False ,
453                                 NULL ) ;
454 
455    for( ii=0 ; ii < num_act ; ii++ ){
456 
457       ww = XtVaCreateManagedWidget(
458                action[ii].label , xmPushButtonWidgetClass , act_area ,
459 
460                   XmNleftAttachment   ,
461            (ii) ? XmATTACH_POSITION : XmATTACH_FORM ,
462                   XmNleftPosition     , ii*TIG ,
463                   XmNtopAttachment    , XmATTACH_FORM ,
464                   XmNbottomAttachment , XmATTACH_FORM ,
465                   XmNrightAttachment  ,
466                      (ii==num_act-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
467 
468                   XmNrightPosition    , ii*TIG + (TIG-1) ,
469 
470                   XmNrecomputeSize , False ,
471                   XmNtraversalOn   , True  ,
472                   XmNinitialResourcesPersistent , False ,
473                NULL ) ;
474 
475       XtAddCallback( ww , XmNactivateCallback ,
476                      action[ii].func_CB , action[ii].data ) ;
477 
478       action[ii].data = (XtPointer) ww ;  /* Feb 1998: save widget */
479 
480       if( action[ii].help_text != NULL )
481          MCW_register_help( ww , action[ii].help_text ) ;
482 
483       if( action[ii].hint_text != NULL )
484          MCW_register_hint( ww , action[ii].hint_text ) ;
485 
486       if( action[ii].make_red > 0 )                  /* for some fun */
487          MCW_set_widget_bg( ww , MCW_hotcolor(ww) , 0 ) ;
488       else if( action[ii].make_red < 0 )             /* for no fun at all */
489          XtSetSensitive( ww , False ) ;
490 
491    }
492 
493    XtManageChild( act_area ) ;
494    return act_area ;
495 }
496 
497 /*------------------------------------------------------------------
498    Popup a window with a message;  return the Widget.
499    The message can be of two types, signified by the 3rd argument:
500       msg_type = MCW_CALLER_KILL means the caller has to kill the
501                  widget for the window to go away.
502 
503                = MCW_USER_KILL means that the user can click in
504                   the widget to kill it.
505 
506       msg_type may also be OR-ed with MCW_TIMER_KILL to have the
507       message automatically killed after 22 seconds --
508       OR with MCW_QUICK_KILL to be auto-killed after 7 seconds.
509 --------------------------------------------------------------------*/
510 
MCW_popup_message(Widget wparent,char * msg,int msg_type)511 Widget MCW_popup_message( Widget wparent , char *msg , int msg_type )
512 {
513    Widget wmsg , wlab ;
514    int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , lm ;
515    Screen *scr ;
516    XEvent ev ;
517 
518 ENTRY("MCW_popup_message") ;
519 
520    if( msg == NULL || (lm=strlen(msg)) == 0 ) RETURN(NULL) ;
521 
522    if( wparent == NULL || !XtIsRealized(wparent) ){  /* 21 Aug 2007 */
523      fprintf(stderr,"%s\n",msg) ; RETURN(NULL) ;
524    }
525 
526    /* set position for message box based on parent and screen geometry */
527 
528    MCW_widget_geom( wparent , &wx,&hy,&xx,&yy ) ;  /* geometry of parent */
529 
530 #if 1
531    { Position xroot , yroot ;
532      XtTranslateCoords( wparent, 0,0, &xroot,&yroot ) ; /* root coords */
533      xr = (int) xroot ; yr = (int) yroot ;
534    }
535 #else
536      xr = xx ; yr = yy ;  /* the old code, essentially */
537 #endif
538 
539    scr        = XtScreen( wparent ) ;
540    scr_width  = WidthOfScreen( scr ) ;
541    scr_height = HeightOfScreen( scr ) ;
542 
543    xp = xx+8 ;  xpr = xr+8 ;
544         if( xpr+50 > scr_width ){ xp -= 100 ; xpr -= 100 ; } /* too right */
545    else if( xpr+10 < 0 )        { xpr = xp = 1 ; }           /* too left  */
546 
547    yp = yy+hy+8 ;  ypr = yr+hy+8 ;
548         if( ypr+50 > scr_height ){ yp = yy-8 ; ypr = yr-100 ;} /* too down */
549    else if( ypr+10 < 0 )         { ypr = yp = 1 ;            } /* too up   */
550 
551    /* create a popup shell with a label */
552 
553    wmsg = XtVaCreatePopupShell(
554              "help" , xmDialogShellWidgetClass , wparent ,
555                 XmNx , xpr ,
556                 XmNy , ypr ,
557                 XmNinitialResourcesPersistent , False ,
558              NULL ) ;
559 
560    if( MCW_isitmwm( wparent ) ){
561       XtVaSetValues( wmsg ,
562                         XmNmwmDecorations , MWM_DECOR_BORDER ,
563                         XmNmwmFunctions   , MWM_FUNC_MOVE ,
564                      NULL ) ;
565    }
566 
567    switch( msg_type & (MCW_CALLER_KILL | MCW_USER_KILL) ){
568 
569       case MCW_CALLER_KILL:
570 
571          wlab = XtVaCreateManagedWidget(
572                   "help" , xmLabelWidgetClass , wmsg ,
573                      XtVaTypedArg,XmNlabelString,XmRString,msg,lm+1,
574                      XmNalignment , XmALIGNMENT_BEGINNING ,
575                      XmNinitialResourcesPersistent , False ,
576                   NULL ) ;
577       break ;
578 
579       default:
580       case MCW_USER_KILL:{
581          static int first=1 ; char *mmsg = msg ;     /* 'first' stuff  */
582          if( first ){                                /* on 06 Apr 2004 */
583            if( !AFNI_noenv("AFNI_CLICK_MESSAGE") ){
584              mmsg = (char *) malloc(lm+99) ;
585              strcpy(mmsg,msg) ;
586              strcat(mmsg,"\n [---------------] "
587                          "\n [ Click in Text ] "
588                          "\n [ to Pop Down!! ]\n" ) ;
589            }
590          }
591 
592          wlab = XtVaCreateManagedWidget(
593                   "help" , xmPushButtonWidgetClass , wmsg ,
594                      XtVaTypedArg,XmNlabelString,XmRString,mmsg,lm+1,
595                      XmNalignment , XmALIGNMENT_BEGINNING ,
596                      XmNinitialResourcesPersistent , False ,
597                   NULL ) ;
598 
599          if( mmsg != msg ){ free((void *)mmsg); first = 0; }
600 
601          XtAddCallback( wlab , XmNactivateCallback , MCW_message_CB , NULL ) ;
602       }
603       break ;
604    }
605 
606    SAVEUNDERIZE(wmsg) ;           /* 27 Feb 2001 */
607    XtPopup( wmsg , XtGrabNone ) ; RWC_sleep(1);
608 
609    /* now wait until the label is exposed, and make sure it appears;
610       the reason for this stuff is that this routine is likely to be
611       called by a long computation that won't return control to Xt   */
612 
613    WAIT_for_window(wlab) ;
614    XSync( XtDisplay(wlab) , False ) ;
615 #if 0
616    XMaskEvent( XtDisplay(wlab) , ExposureMask , &ev ) ;/* wait for expose  */
617 #else
618    XWindowEvent( XtDisplay(wlab) , XtWindow(wlab) , ExposureMask , &ev ) ;
619 #endif
620    XPutBackEvent( XtDisplay(wlab) , &ev ) ;            /* put expose back  */
621    XSync( XtDisplay(wlab) , False ) ;
622    XmUpdateDisplay( wlab ) ;                           /* show it for sure */
623 
624    /* now add the timer kill, if wanted */
625 
626 #define ALLOW_TIMER_KILL
627 #ifdef ALLOW_TIMER_KILL
628    if( (msg_type & (MCW_TIMER_KILL|MCW_QUICK_KILL)) ){
629       XtIntervalId tid ;
630       unsigned long dtime = (msg_type & MCW_TIMER_KILL) ? 22111 : 7111 ;
631 
632       tid = XtAppAddTimeOut( XtWidgetToApplicationContext( wmsg ) ,
633                              dtime , MCW_message_timer_CB , wmsg   ) ;
634 
635       XtVaSetValues( wlab , XmNuserData ,  tid , NULL ); /* put tid on wlab, */
636    } else {                                            /* since shells don't */
637       XtVaSetValues( wlab , XmNuserData , 0 , NULL ) ;   /* have XmNuserData */
638    }
639 #endif
640 
641    RWC_visibilize(wmsg) ;     /* 27 Sep 2000 */
642    NORMAL_cursorize(wmsg) ;
643    MCW_flash_widget(1,wlab) ; /* 25 Jul 2014 */
644    RETURN(wmsg) ;
645 }
646 
647 /*-------------------------------------------------------------------------
648   Alter the text in the popup message - 10 Jul 2001
649 ---------------------------------------------------------------------------*/
650 
MCW_message_alter(Widget wmsg,char * msg)651 void MCW_message_alter( Widget wmsg , char *msg )
652 {
653    Widget wlab ;
654    Widget *children=NULL ;
655    int  num_children=0 ;
656    XmString xstr ;
657 
658 ENTRY("MCW_message_alter") ;
659 
660    if( wmsg == NULL || msg == NULL || msg[0] == '\0' ) EXRETURN ;
661 
662    XtVaGetValues( wmsg , XmNchildren    , &children ,
663                          XmNnumChildren , &num_children , NULL ) ;
664    if( num_children < 1 ) EXRETURN ;
665 
666    MCW_set_widget_label( children[0] , msg ) ;
667    EXRETURN ;
668 }
669 
670 /*-------------------------------------------------------------------------
671     callback when the popup message created above is a PushButton
672     (Note that w is the PushButton widget, so its parent is to be killed)
673 ---------------------------------------------------------------------------*/
674 
MCW_message_CB(Widget w,XtPointer cd,XtPointer cbs)675 void MCW_message_CB( Widget w , XtPointer cd , XtPointer cbs )
676 {
677 #ifdef ALLOW_TIMER_KILL
678    XtIntervalId tid=0 ;
679 
680    XtVaGetValues( w , XmNuserData , &tid , NULL ) ;  /* get timer id */
681    XtDestroyWidget( XtParent(w) ) ;
682 
683    if( tid > 0 ) XtRemoveTimeOut( tid ) ;  /* if a timer exists, kill it */
684    RWC_sleep(1) ;
685 #else
686    XtDestroyWidget( XtParent(w) ) ;
687 #endif
688 }
689 
690 /*----------------------------------------------------*/
691 /*--- callback when timer expires on popup message ---*/
692 /*----------------------------------------------------*/
693 
MCW_message_timer_CB(XtPointer client_data,XtIntervalId * id)694 void MCW_message_timer_CB( XtPointer client_data , XtIntervalId *id )
695 {
696    XtDestroyWidget( (Widget) client_data ) ;
697    RWC_sleep(1) ;
698 }
699 
700 /*------------------------------------------------------------------------------*/
701 /* This function is intended to popup the given message only once
702    (for each user).  The 'w' and 'msg' arguments are self-explanatory, I hope.
703 
704    'expiry', if not NULL, is a data after which the message should not be shown.
705 
706    'codestring' is a short string to encode that the message has been seen,
707    in the ${HOME)/.afni.recordings file -- if codestring is NULL, then the
708    MD5 hashstring of the message will be used for this hideous purpose.
709 
710    Example:
711      MCW_popup_message_once( w, "Hi, this is Bob", "01 Jan 2099", "Bob#001" ) ;
712 *//*----------------------------------------------------------------------------*/
713 
MCW_popup_message_once(Widget w,char * msg,char * expiry,char * codestring)714 void MCW_popup_message_once( Widget w, char *msg, char *expiry, char *codestring )
715 {
716    char *home = getenv("HOME") , mname[1024]="file:" ;
717    NI_stream ns ; NI_element *nel ;
718    int seen=0 ;
719 
720    time_t tt=time(NULL) ; struct tm *lt=localtime(&tt) ;
721 
722    static char *monthlist[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
723                                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } ;
724 
725    if( w == (Widget)NULL ) return ;
726    if( msg == NULL || *msg == '\0' ) return ;
727    if( AFNI_yesenv("AFNI_SKIP_ONETIME_POPUPS") ) return ;
728 
729    /* check expiry date vs today */
730 
731    if( expiry != NULL && *expiry != '\0' ){
732      char da[16],db[16],dc[16] ;  int emon=-1,eday=-1,eyear=-1 , ii ;
733      da[0] = db[0] = dc[0] = '\0' ;
734      sscanf( expiry , "%5s%5s%5s" , da,db,dc ) ;
735      if( da[0] != '\0' && db[0] != '\0' && dc != '\0' ){ /* got 3 sub-strings */
736        if( isalpha(da[0]) ){ /* month is first */
737          for( ii=0; ii < 12 && strcasecmp(da,monthlist[ii]); ii++ ) ; /*nada*/
738          emon = ii ;
739          eday = (int)strtol(db,NULL,10) ;
740        } else if( isalpha(db[0]) ){ /* month is second */
741          for( ii=0; ii < 12 && strcasecmp(db,monthlist[ii]); ii++ ) ; /*nada*/
742          emon = ii ;
743          eday = (int)strtol(da,NULL,10) ;
744        }
745        eyear = (int)strtol(dc,NULL,10)-1900 ;
746        if( emon >= 0 && emon < 12 && eday > 0 && eday < 32 && eyear > 0 ){
747          if( lt->tm_year >  eyear ) return ;  /* past the expiry year == DONE */
748          if( lt->tm_year == eyear ){          /* in expiry year */
749            if( lt->tm_mon >  emon ) return ;  /* past expiry month    == DONE */
750            if( lt->tm_mon == emon ){          /* in expiry month */
751              if( lt->tm_mday >= eday ) return ; /* past expiry day    == DONE */
752            }
753          }
754        }
755      }
756    }
757 
758    if( codestring == NULL    ||
759        codestring[0] == '\0' || strlen(codestring) > 66 ) /* backup for luser */
760      codestring = MD5_static_string(msg) ;
761 
762    if( home != NULL ) strcat(mname,home) ;
763    else               strcat(mname,"." ) ;
764    strcat(mname,"/.afni.recordings") ;
765 
766    /* check if we saw this already */
767 
768    ns = NI_stream_open(mname,"r") ;
769    if( ns != NULL ){
770      while( !seen ){
771        nel = NI_read_element_header(ns,11) ;
772        if( nel == NULL ) break ;
773        if( strcmp(nel->name,"AFNI_saw_message") == 0 ){
774          char *rhs = NI_get_attribute(nel,"codestring") ;
775          if( rhs != NULL && strcmp(rhs,codestring) == 0 ) seen = 1 ;
776        }
777        NI_free_element(nel) ;
778      }
779      NI_stream_close(ns) ;
780    }
781    if( seen ) return ;  /* it was recorded! */
782 
783    /* popup the actual message now */
784 
785    (void)MCW_popup_message( w , msg , MCW_USER_KILL ) ;
786 
787    /* recordation of seeing */
788 
789    ns = NI_stream_open(mname,"a") ;
790    if( ns != NULL ){
791      char rhs[32] ;
792      nel = NI_new_data_element("AFNI_saw_message",0) ;
793      NI_set_attribute(nel,"codestring",codestring) ;
794      sprintf(rhs,"%02d %s %4d",lt->tm_mday,monthlist[lt->tm_mon],lt->tm_year+1900) ;
795      NI_set_attribute(nel,"seendate",rhs) ;
796      NI_write_element(ns,nel,NI_TEXT_MODE) ;
797      NI_free_element(nel) ;
798      NI_stream_close(ns) ;
799    }
800 
801    return ;
802 }
803 
804 /*------------------------------------------------------------------
805    routines to change Widget cursors
806      cur argument:  = 0 --> None
807                     > 0 --> is a Cursor already allocated
808                     < 0 --> -cur is a cursorfont index
809 --------------------------------------------------------------------*/
810 
MCW_set_widget_cursor(Widget w,int cur)811 void MCW_set_widget_cursor( Widget w , int cur )
812 {
813    MCW_alter_widget_cursor( w , cur , NULL,NULL ) ;
814    return ;
815 }
816 
817 /*--------------------------------------------------------------------*/
818 
MCW_alter_widget_cursor(Widget w,int cur,char * fgname,char * bgname)819 void MCW_alter_widget_cursor( Widget w, int cur, char *fgname, char *bgname )
820 {
821    XColor fg , bg ;
822    Cursor ccc ;
823    Colormap cmap ;
824    Display  *dis ;
825    RwcBoolean  good ;
826    int ii ;
827 
828    static Cursor  cur_font[XC_num_glyphs] ;
829    static RwcBoolean first = True ;
830 
831    if( AFNI_yesenv("AFNI_DISABLE_CURSORS") ) return ; /* 21 Mar 2004 */
832 
833    if( first ){
834       for( ii=0 ; ii < XC_num_glyphs ; ii++ ) cur_font[ii] = None ;
835       first = False ;
836    }
837 
838    if( w == NULL || !XtIsRealized(w) || XtWindow(w) == (Window)NULL ) return ;
839    RWC_sleep(1) ;
840 
841    dis = XtDisplay(w) ;
842 
843    if( cur == 0 || cur <= -XC_num_glyphs ){    /* define cursor */
844       ccc = None ;
845    } else if( cur > 0 ){
846       ccc = cur ;
847    } else {
848       ii = -cur ;
849       if( cur_font[ii] == None ) cur_font[ii] = XCreateFontCursor( dis , ii ) ;
850       ccc = cur_font[ii] ;
851    }
852 
853    XDefineCursor( dis , XtWindow(w) , ccc ) ;
854 
855    if( fgname != NULL && bgname != NULL ){
856 
857       cmap = DefaultColormap( dis , DefaultScreen(dis) ) ;
858 
859       good =    XParseColor( dis , cmap , fgname , &fg )
860              && XParseColor( dis , cmap , bgname , &bg ) ;
861 
862       if( good ) XRecolorCursor( dis , ccc , &fg , &bg ) ;
863    }
864    return ;
865 }
866 
867 /*------------------------------------------------------------------------
868    widget help routines (for "button help" buttons)
869 --------------------------------------------------------------------------*/
870 
MCW_click_help_CB(Widget w,XtPointer client_data,XtPointer call_data)871 void MCW_click_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
872 {
873    Widget whelp ;
874    XmAnyCallbackStruct cbs ;
875    XEvent ev ;
876    static Cursor cur = 0 ;
877    Display *dis = XtDisplay(w) ;
878 
879    if( cur == 0 ) cur = XCreateFontCursor( dis , XC_hand2 ) ;
880 
881 #ifdef USE_LOCATE  /* old version */
882    whelp = XmTrackingLocate( w , cur , False ) ; /* wait for user to click */
883 #else
884    cbs.event = &ev ;
885    whelp = XmTrackingEvent( w , cur , False , cbs.event ) ;
886 #endif
887 
888    if( whelp != NULL &&
889        XtHasCallbacks(whelp,XmNhelpCallback) == XtCallbackHasSome ){
890 
891       cbs.reason = XmCR_HELP ;
892       XtCallCallbacks( whelp , XmNhelpCallback , &cbs ) ;  /* call for help */
893    } else {
894       XBell( dis , 100 ) ;
895    }
896    return ;
897 }
898 
899 /*------------------------------------------------------------------------*/
900 /*------------------------------------------------------------------------*/
901 
902 static int disable_helps = 0 ;                     /* 02 Aug 1999 */
MCW_disable_help(void)903 void MCW_disable_help(void){ disable_helps = 1 ; }
MCW_enable_help(void)904 void MCW_enable_help (void){ disable_helps = 0 ; }
905 
906 #ifdef DONT_USE_HINTS
MCW_register_hint(Widget w,char * msg)907 void MCW_register_hint( Widget w , char *msg ) { return ; }
MCW_reghint_children(Widget w,char * msg)908 void MCW_reghint_children( Widget w , char *msg ) { return ; }
MCW_hint_toggle(void)909 void MCW_hint_toggle(void){ return ; }
MCW_unregister_hint(Widget w)910 void MCW_unregister_hint( Widget w ){ return ; }
911 #else
912 
913 #include "LiteClue.h"
914 
915 static Widget liteClue = NULL ;
916 static int clueless    = -1 ;
917 
MCW_hint_toggle(void)918 void MCW_hint_toggle(void)
919 {
920 #define PBIG 999999
921    int period=0 ;
922    char *pdef=NULL ;
923 
924    if( liteClue == NULL ) return ;
925 
926    XtVaGetValues( liteClue , XgcNwaitPeriod , &period , NULL ) ;
927    if( period < PBIG ){
928       period = PBIG ;
929    } else {
930 #if 0
931       pdef = XGetDefault(XtDisplay(liteClue),"AFNI","waitperiod") ;
932 #else
933       pdef = RWC_getname(XtDisplay(liteClue),"waitperiod") ;
934 #endif
935       if( pdef == NULL ){
936          period = 1066 ;
937       } else {
938          period = strtol( pdef , NULL , 10 ) ;
939          if( period < 100 ) period = 1066 ;
940       }
941    }
942    XtVaSetValues( liteClue , XgcNwaitPeriod , period , NULL ) ;
943    return ;
944 }
945 
946 /*--------------------------------------------------------------------*/
947 
MCW_unregister_hint(Widget w)948 void MCW_unregister_hint( Widget w )    /* 11 Jul 2001 */
949 {
950    if( liteClue != NULL && w != NULL )
951       XcgLiteClueDeleteWidget( liteClue , w ) ;
952    return ;
953 }
954 
955 /*--------------------------------------------------------------------*/
956 
957 #define RES_CONVERT( res_name, res_value) \
958        XtVaTypedArg, (res_name), XmRString, (res_value), strlen(res_value) + 1
959 
MCW_register_hint(Widget w,char * msg)960 void MCW_register_hint( Widget w , char *msg )
961 {
962    if( disable_helps ) return ;
963    if( w == NULL || msg == NULL || clueless == 1 || !XtIsWidget(w) ) return ;
964 
965    if( clueless == -1 ){
966       char *hh = my_getenv("AFNI_HINTS") ;
967       if( hh != NULL && ( strncmp(hh,"KILL",4)==0 ||
968                           strncmp(hh,"kill",4)==0 ||
969                           strncmp(hh,"Kill",4)==0 ) ){
970          clueless = 1 ;
971          return ;
972       } else {
973          clueless = 0 ;
974       }
975    }
976 
977    /*-- Do we have to make the hint-displaying widget? --*/
978 
979    if( liteClue == NULL ){
980       Widget wpar = w ;
981       char *cfont ;
982 
983       while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ;  /* find top */
984 
985       cfont = XGetDefault(XtDisplay(wpar),"AFNI","cluefont") ;
986       if( cfont == NULL ) cfont = "10x20" ;                    /* 08 Jan 2021 */
987       liteClue = XtVaCreatePopupShell( "help", xcgLiteClueWidgetClass, wpar,
988                                           RES_CONVERT(XtNfontSet,cfont) ,
989                                        NULL);
990       if( !RWC_liteclue_has_fontset(liteClue) ){   /* Failed :( */
991         INFO_message("\n") ;
992         INFO_message("\n Hints disabled: X11 failure to create LiteClue window") ;
993         INFO_message("\n") ;
994         clueless = 1 ;
995         return ;
996       }
997 
998       XtVaSetValues( liteClue , XmNsaveUnder , True , NULL ) ; /* 22 Jan 1999 */
999    }
1000 
1001    /*-- attach the hint to the widget, if it is a widget --*/
1002 
1003    if( XtIsWidget(w) ) XcgLiteClueAddWidget( liteClue, w, msg, 0,0 ) ;
1004 
1005    return ;
1006 }
1007 
1008 /*--------------------------------------------------------------------*/
1009 
MCW_reghint_children(Widget w,char * msg)1010 void MCW_reghint_children( Widget w , char *msg )
1011 {
1012    Widget *children=NULL ;
1013    int  num_children=0 , ic ;
1014 
1015    if( disable_helps ) return ;
1016    if( w == NULL || msg == NULL || clueless == 1 || !XtIsWidget(w) ) return ;
1017 
1018    XtVaGetValues( w , XmNchildren    , &children ,
1019                       XmNnumChildren , &num_children , NULL ) ;
1020 
1021    MCW_register_hint( w , msg ) ;
1022    if( children == NULL || num_children == 0 ) return ;
1023 
1024    for( ic=0 ; ic < num_children ; ic++ )
1025       MCW_register_hint( children[ic] , msg ) ;
1026 
1027    return ;
1028 }
1029 #endif /* DONT_USE_HINTS */
1030 /*------------------------------------------------------------------------*/
1031 /*------------------------------------------------------------------------*/
1032 
MCW_unregister_help(Widget w)1033 void MCW_unregister_help( Widget w ) /* 24 Apr 2001 */
1034 {
1035    XtCallbackList hc=NULL ;
1036 
1037    if( w == NULL ) return ;
1038    XtVaGetValues( w , XmNhelpCallback , &hc , NULL ) ;
1039    if( hc != NULL ) XtRemoveCallbacks( w , XmNhelpCallback , hc ) ;
1040 }
1041 
1042 /*------------------------------------------------------------------------*/
1043 
MCW_register_help(Widget w,char * msg)1044 void MCW_register_help( Widget w , char *msg )
1045 {
1046    if( disable_helps ) return ;
1047    if( w == NULL || msg == NULL ) return ;
1048    XtAddCallback( w , XmNhelpCallback , MCW_help_CB , msg ) ;
1049    return ;
1050 }
1051 
1052 /*--------------------------------------------------------------------*/
1053 
MCW_reghelp_children(Widget w,char * msg)1054 void MCW_reghelp_children( Widget w , char *msg )
1055 {
1056    Widget *children=NULL ;
1057    int  num_children=0 , ic ;
1058 
1059    if( disable_helps ) return ;
1060    if( w == NULL || msg == NULL ) return ;
1061 
1062    XtVaGetValues( w , XmNchildren    , &children ,
1063                       XmNnumChildren , &num_children , NULL ) ;
1064 
1065    XtAddCallback( w , XmNhelpCallback , MCW_help_CB , msg ) ;
1066 
1067    for( ic=0 ; ic < num_children ; ic++ )
1068       XtAddCallback( children[ic] , XmNhelpCallback , MCW_help_CB , msg ) ;
1069    return ;
1070 }
1071 
1072 /*------------------------------------------------------------------------*/
1073 
MCW_help_CB(Widget w,XtPointer client_data,XtPointer call_data)1074 void MCW_help_CB( Widget w , XtPointer client_data , XtPointer call_data )
1075 {
1076    char *msg          = (char *) client_data ;
1077    static Widget wpop = NULL , wbut = NULL ;
1078    Position xx,yy ;
1079    XmString xstr ;
1080    int ww,hh , sw,sh ;
1081    char *def ;
1082 
1083 ENTRY("MCW_help_CB") ;
1084 
1085 #ifndef USE_LOCATE
1086    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data ;
1087 #endif
1088 
1089    if( w == NULL ){
1090 STATUS("popdown call") ;
1091       if( wpop != NULL ) XtUnmapWidget(wpop) ;
1092       EXRETURN ;
1093    }
1094 
1095    if( wpop == NULL || ! XtIsWidget(wpop) ){
1096 
1097       Widget wpar = w ;
1098 
1099 STATUS("create help widget") ;
1100 
1101       while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ;  /* find top */
1102 
1103 STATUS("  create wpop") ;
1104 
1105       wpop = XtVaCreatePopupShell(
1106               "help" , xmDialogShellWidgetClass , wpar ,
1107                  XmNmappedWhenManaged , False ,
1108                  XmNallowShellResize , True ,
1109                  XmNdeleteResponse , XmDO_NOTHING ,
1110                  XmNinitialResourcesPersistent , False ,
1111               NULL ) ;
1112 
1113       if( wpop == NULL ){ ERROR_message("can't create help popup!"); EXRETURN; }
1114 
1115 #if 0
1116       def = XGetDefault(XtDisplay(wpar),"AFNI","helpborder") ;
1117 #else
1118       def = RWC_getname(XtDisplay(wpar),"helpborder") ;
1119 #endif
1120       if( def != NULL && strcmp(def,"False") == 0 ){
1121          XtVaSetValues( wpop ,
1122                            XmNoverrideRedirect , True ,
1123                         NULL ) ;
1124       } else if( MCW_isitmwm(wpar) ){
1125          XtVaSetValues( wpop ,
1126                            XmNmwmDecorations , MWM_DECOR_BORDER ,
1127                            XmNmwmFunctions   , MWM_FUNC_MOVE ,
1128                         NULL ) ;
1129       }
1130 
1131 STATUS("  create wbut") ;
1132 
1133       wbut = XtVaCreateManagedWidget(
1134                 "help" , xmPushButtonWidgetClass , wpop ,
1135                    XmNalignment , XmALIGNMENT_BEGINNING ,
1136                    XmNinitialResourcesPersistent , False ,
1137                 NULL ) ;
1138 
1139 STATUS("  add unhelp_CB") ;
1140 
1141       XtAddCallback( wbut , XmNactivateCallback , MCW_unhelp_CB , wpop ) ;
1142 
1143 STATUS("  update display") ;
1144 
1145       XmUpdateDisplay( wpar ) ;
1146 
1147 STATUS("  popdown wpop") ;
1148 
1149       RWC_XtPopdown( wpop ) ;
1150 
1151 STATUS("  add kill protocol") ;
1152 
1153       XmAddWMProtocolCallback(
1154            wpop ,
1155            XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
1156            MCW_unhelp_CB , wpop ) ;
1157 
1158       if( ! XtIsRealized(wpar) ) EXRETURN ;
1159    }
1160 
1161    if( msg == NULL || strlen(msg) == 0 ) EXRETURN ; /* no popup if no message */
1162 
1163    xstr = XmStringCreateLtoR( msg , XmFONTLIST_DEFAULT_TAG ) ;
1164    XtVaSetValues( wbut , XmNlabelString , xstr , NULL ) ;
1165    XmStringFree( xstr ) ;
1166 
1167 #ifndef USE_LOCATE
1168    if( cbs != NULL && cbs->event != NULL
1169                    && cbs->event->type == ButtonRelease ){
1170       XButtonEvent *xev = (XButtonEvent *) cbs->event ;
1171       xx = xev->x_root ;
1172       yy = xev->y_root ;
1173    } else
1174 #endif
1175    XtTranslateCoords( w , 15,15 , &xx , &yy ) ;    /* coordinates on root */
1176 
1177    MCW_widget_geom( wpop , &ww,&hh , NULL,NULL ) ; /* widget width and height */
1178    sw = WidthOfScreen (XtScreen(wpop)) ;           /* screen width and height */
1179    sh = HeightOfScreen(XtScreen(wpop)) ;
1180 
1181    if( xx+ww+3 >= sw && ww <= sw ) xx = sw-ww ;    /* make sure is on screen */
1182    if( yy+hh+3 >= sh && hh <= sh ) yy = sh-hh ;
1183 
1184    XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ;
1185    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
1186    RWC_visibilize(wpop) ;  /* 27 Sep 2000 */
1187    NORMAL_cursorize(wpop) ;
1188    EXRETURN ;
1189 }
1190 
1191 /*---------------------------------------------------------------------*/
1192 
MCW_unhelp_CB(Widget w,XtPointer client_data,XtPointer call_data)1193 void MCW_unhelp_CB( Widget w , XtPointer client_data , XtPointer call_data )
1194 {
1195    Widget wpop = (Widget) client_data ;
1196 
1197    RWC_XtPopdown(wpop) ;
1198    return ;
1199 }
1200 
1201 /*---------------------------------------------------------------------*/
1202 
MCW_filetype(char * fname)1203 int MCW_filetype( char *fname )
1204 {
1205    FILE *fff ;
1206 
1207    if( fname == NULL || strlen(fname) == 0 ) return MCW_nofile ;
1208 
1209    fff = fopen( fname , "r+" ) ;  /* open for read-update */
1210    fclose( fff ) ;
1211 
1212    if( fff != NULL ) return MCW_readwrite ;
1213 
1214    fff = fopen( fname , "r" ) ;   /* open for read-only */
1215    fclose(fff) ;
1216 
1217    if( fff != NULL ) return MCW_readonly ;
1218 
1219    return MCW_nofile ;
1220 }
1221 
1222 /*-------------------------------------------------------------------*/
1223 
1224 #if 0
1225 RwcBoolean MCW_isitmwm( Widget w )
1226 {
1227    Widget wsh ;
1228 
1229    if( w == NULL || ! XtIsWidget(w) ) return False ;
1230 
1231    wsh = w ;
1232 
1233    while( ! XtIsShell(wsh) ){
1234       wsh = XtParent(wsh) ;
1235       if( wsh == NULL ) return False ;
1236    }
1237 
1238 #if 1
1239    return XmIsMotifWMRunning(wsh) ;
1240 #else
1241    { int immm = -73 ;
1242      XtVaGetValues( wsh , XmNmwmDecorations , &immm , NULL ) ;
1243      if( immm == -73 ) return False ;
1244      else              return True ;
1245    }
1246 #endif
1247 }
1248 #endif
1249 
1250 /*------------------------------------------------------------------
1251    Popup a scale that will serve as a progress meter.
1252    The meter is set initially to 0, and can later be set to any
1253    value from 0 to 100 using MCW_set_meter().
1254 
1255    wparent is the widget the meter will be attached to
1256    position is one of
1257      METER_TOP      = meter on top of wparent, default width
1258      METER_TOP_WIDE = meter on top of parent, width of parent
1259      METER_BOT      = similar, but on bottom of parent
1260      METER_BOT_WIDE
1261 --------------------------------------------------------------------*/
1262 
1263 #define METER_HEIGHT 10
1264 #define METER_WIDTH  200
1265 
MCW_popup_meter(Widget wparent,int position)1266 Widget MCW_popup_meter( Widget wparent , int position )
1267 {
1268    Widget wmsg , wscal ;
1269    int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , wid ;
1270    Screen *scr ;
1271    XEvent ev ;
1272    Position xroot , yroot ;
1273 
1274 ENTRY("MCW_popup_meter") ;
1275 
1276    if( wparent == NULL || ! XtIsRealized(wparent) ) RETURN(NULL) ;
1277 
1278    /* set position parent and screen geometry */
1279 
1280    MCW_widget_geom( wparent , &wx,&hy,&xx,&yy ) ;     /* geometry of parent */
1281    XtTranslateCoords( wparent, 0,0, &xroot,&yroot ) ; /* root coords of parent */
1282    xr = (int) xroot ; yr = (int) yroot ;
1283 
1284    scr        = XtScreen( wparent ) ;
1285    scr_width  = WidthOfScreen( scr ) ;
1286    scr_height = HeightOfScreen( scr ) ;
1287 
1288    switch( position ){
1289 
1290       default:
1291       case METER_TOP:
1292       case METER_TOP_WIDE:
1293          xpr = xr ;
1294          ypr = yr - METER_HEIGHT-2 ;
1295          wid = (position==METER_TOP_WIDE) ? wx : METER_WIDTH ;
1296          if( ypr < 0 ) ypr = yr+hy+1 ;
1297       break ;
1298 
1299       case METER_BOT:
1300       case METER_BOT_WIDE:
1301          xpr = xr ;
1302          ypr = yr+hy+1 ;
1303          wid = (position==METER_BOT_WIDE) ? wx : METER_WIDTH ;
1304          if( ypr+METER_HEIGHT > scr_height ) ypr = yr - METER_HEIGHT-2 ;
1305       break ;
1306    }
1307 
1308    /* create a popup shell with a scale */
1309 
1310    wmsg = XtVaCreatePopupShell(
1311              "menu" , xmDialogShellWidgetClass , wparent ,
1312                 XmNx , xpr ,
1313                 XmNy , ypr ,
1314                 XmNborderWidth , 0 ,
1315                 XmNoverrideRedirect , True ,
1316                 XmNinitialResourcesPersistent , False ,
1317              NULL ) ;
1318 
1319 #if 0
1320    if( MCW_isitmwm( wparent ) ){
1321       XtVaSetValues( wmsg ,
1322                         XmNmwmDecorations , MWM_DECOR_BORDER ,
1323                         XmNmwmFunctions   , MWM_FUNC_MOVE ,
1324                      NULL ) ;
1325    }
1326 #endif
1327 
1328    wscal = XtVaCreateManagedWidget(
1329             "menu" , xmScaleWidgetClass , wmsg ,
1330                XmNminimum , 0 ,
1331                XmNmaximum , 100 ,
1332                XmNshowValue , False ,
1333                XmNvalue , 0 ,
1334                XmNorientation , XmHORIZONTAL ,
1335                XmNscaleWidth , wid ,
1336                XmNscaleHeight , METER_HEIGHT ,
1337                XmNborderWidth , 0 ,
1338                XmNhighlightThickness , 0 ,
1339                XmNshadowThickness , 0 ,
1340                XmNtraversalOn , True  ,
1341                XmNinitialResourcesPersistent , False ,
1342             NULL ) ;
1343 
1344    XtPopup( wmsg , XtGrabNone ) ; RWC_sleep(1);
1345 
1346    RETURN(wscal) ;
1347 }
1348 
1349 /*--------------------------------------------------------------------*/
1350 
MCW_popdown_meter(Widget wscal)1351 void MCW_popdown_meter( Widget wscal )
1352 {
1353    if( wscal == NULL ) return ;
1354    XtDestroyWidget( XtParent(wscal) ) ;
1355    return ;
1356 }
1357 
1358 /*--------------------------------------------------------------------*/
1359 
MCW_set_meter(Widget wscal,int percent)1360 void MCW_set_meter( Widget wscal , int percent )
1361 {
1362    int val , old ;
1363 
1364 #undef  NCOL
1365 #define NCOL 30
1366 #ifdef NCOL
1367    static int icol=0 ;
1368    static char *cname[] = {
1369       "#0000ff", "#3300ff", "#6600ff", "#9900ff", "#cc00ff",
1370       "#ff00ff", "#ff00cc", "#ff0099", "#ff0066", "#ff0033",
1371       "#ff0000", "#ff3300", "#ff6600", "#ff9900", "#ffcc00",
1372       "#ffff00", "#ccff00", "#99ff00", "#66ff00", "#33ff00",
1373       "#00ff00", "#00ff33", "#00ff66", "#00ff99", "#00ffcc",
1374       "#00ffff", "#00ccff", "#0099ff", "#0066ff", "#0033ff"
1375     } ;
1376 #endif
1377 
1378    val = percent ;
1379    if( wscal == NULL || val < 0 || val > 100 ) return ;
1380 
1381    XmScaleGetValue( wscal , &old ) ; if( val == old ) return ;
1382 
1383    XtVaSetValues( wscal , XmNvalue , val , NULL ) ;
1384 
1385 #ifdef NCOL
1386    { Widget ws = XtNameToWidget(wscal,"Scrollbar") ;
1387      if( ws != NULL )
1388        XtVaSetValues( ws ,
1389                        XtVaTypedArg , XmNtroughColor , XmRString ,
1390                                       cname[icol] , strlen(cname[icol])+1 ,
1391                       NULL ) ;
1392      icol = (icol+1) % NCOL ;
1393    }
1394 #endif
1395 
1396    XmUpdateDisplay(wscal) ;
1397    return ;
1398 }
1399 
1400 /*------------------------------------------------------------------------*/
1401 
1402 #if 0
1403 static void MCW_textwin_timer_CB( XtPointer client_data , XtIntervalId *id )
1404 {
1405    Widget ws = (Widget)client_data ;
1406    XtVaSetValues( ws , XmNincrement     , 1 ,
1407                        XmNpageIncrement , 1 ,
1408                        XmNmaximum       , 100 , NULL ) ;
1409 }
1410 #endif
1411 
1412 /*-----------------------------------------------------------------------*/
1413 
1414 #define RONLY_NUM 1
1415 #define EDIT_NUM  2
1416 
1417 static MCW_action_item TWIN_act[] = {
1418  { "Quit" , MCW_textwin_CB , NULL , NULL , "Close window" , 0 } ,
1419  { "Set"  , MCW_textwin_CB , NULL , NULL , "Apply choice and close window" , 0 }
1420 } ;
1421 
new_MCW_textwin(Widget wpar,char * msg,int type)1422 MCW_textwin * new_MCW_textwin( Widget wpar, char *msg, int type )
1423 {
1424    return new_MCW_textwin_2001( wpar,msg,type , NULL,NULL ) ;
1425 }
1426 
1427 static int bigtext = 0 ;
MCW_textwin_setbig(int b)1428 void MCW_textwin_setbig( int b ){ bigtext = b ; }  /* 29 Apr 2009 */
1429 
1430 /*-----------------------------------------------------------------------
1431    Modified 10 Jul 2001 to include killing callback
1432 -------------------------------------------------------------------------*/
1433 
new_MCW_textwin_2001(Widget wpar,char * msg,int type,void_func * kill_func,XtPointer kill_data)1434 MCW_textwin * new_MCW_textwin_2001( Widget wpar, char *msg, int type,
1435                                     void_func *kill_func , XtPointer kill_data )
1436 {
1437    MCW_textwin *tw ;
1438    int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , ii,nact ;
1439    int swid , shi ;
1440    Position xroot , yroot ;
1441    Screen *scr ;
1442    RwcBoolean editable , cursorable ;
1443    Arg wa[64] ; int na ; Widget ws ;
1444    char *wtype = "menu" ;
1445 
1446 ENTRY("new_MCW_textwin_2001") ;
1447 
1448    /*-- sanity check --*/
1449 
1450    if( wpar == NULL || !XtIsRealized(wpar) ) RETURN(NULL) ;
1451 
1452         if( bigtext > 0 ) wtype = "bigtext" ;  /* 29 Apr 2009 */
1453    else if( bigtext < 0 ) wtype = "font8"   ;
1454    bigtext = 0 ;
1455 
1456    /* set position based on parent and screen geometry */
1457 
1458    MCW_widget_geom( wpar , &wx,&hy,&xx,&yy ) ;     /* geometry of parent */
1459    XtTranslateCoords( wpar, 0,0, &xroot,&yroot ) ; /* root coords */
1460    xr = (int) xroot ; yr = (int) yroot ;
1461 
1462    scr        = XtScreen(wpar) ;
1463    scr_width  = WidthOfScreen(scr) ;
1464    scr_height = HeightOfScreen(scr) ;
1465 
1466    xp = xx+8 ;  xpr = xr+8 ;
1467         if( xpr+50 > scr_width ){ xp -= 100 ; xpr -= 100 ; } /* too right */
1468    else if( xpr+10 < 0 )        { xpr = xp = 1 ; }           /* too left  */
1469 
1470    yp = yy+hy+8 ;  ypr = yr+hy+8 ;
1471         if( ypr+50 > scr_height ){ yp = yy-8 ; ypr = yr-100 ;} /* too down */
1472    else if( ypr+10 < 0 )         { ypr = yp = 1 ;            } /* too up   */
1473 
1474    /* create a popup shell */
1475 
1476    tw = myXtNew(MCW_textwin) ;
1477 
1478    tw->kill_func = kill_func ;  /* 10 Jul 2001 */
1479    tw->kill_data = kill_data ;
1480 
1481    tw->wshell = XtVaCreatePopupShell(
1482                  wtype , xmDialogShellWidgetClass , wpar ,
1483                     XmNx , xpr ,
1484                     XmNy , ypr ,
1485                     XmNborderWidth , 0 ,
1486                     XmNborderColor , 0 ,
1487                     XmNinitialResourcesPersistent , False ,
1488                  NULL ) ;
1489 
1490    XmAddWMProtocolCallback(
1491         tw->wshell ,
1492         XmInternAtom( XtDisplay(tw->wshell) , "WM_DELETE_WINDOW" , False ) ,
1493         MCW_textwinkill_CB , (XtPointer) tw ) ;
1494 
1495    /* create a form to hold everything else */
1496 
1497    tw->wtop = XtVaCreateWidget(
1498                 wtype , xmFormWidgetClass , tw->wshell ,
1499                   XmNborderWidth , 0 ,
1500                   XmNborderColor , 0 ,
1501                   XmNtraversalOn , True  ,
1502                   XmNinitialResourcesPersistent , False ,
1503                 NULL ) ;
1504 
1505    /* create action area */
1506 
1507    editable = (RwcBoolean) (type == TEXT_EDITABLE) ;
1508    cursorable = True ;  /* 26 Feb 2007 */
1509 
1510    nact = (editable) ? EDIT_NUM : RONLY_NUM ;
1511    for( ii=0 ; ii < nact ; ii++ ){
1512      TWIN_act[ii].data     = (XtPointer) tw ;
1513      TWIN_act[ii].make_red = 0 ;
1514    }
1515    TWIN_act[nact-1].make_red = 1 ;
1516 
1517    tw->wactar = MCW_action_area( tw->wtop , TWIN_act , nact ) ;
1518 
1519    /* create text area */
1520 
1521    tw->wscroll = XtVaCreateManagedWidget(
1522                     wtype , xmScrolledWindowWidgetClass , tw->wtop ,
1523                        XmNscrollingPolicy        , XmAUTOMATIC ,
1524                        XmNvisualPolicy           , XmVARIABLE ,
1525                        XmNscrollBarDisplayPolicy , XmAS_NEEDED ,
1526 
1527                        XmNleftAttachment  , XmATTACH_FORM ,
1528                        XmNrightAttachment , XmATTACH_FORM ,
1529                        XmNbottomAttachment, XmATTACH_FORM ,
1530                        XmNtopAttachment   , XmATTACH_WIDGET ,
1531                        XmNtopWidget       , tw->wactar ,
1532                        XmNtopOffset       , 7 ,
1533 
1534                        XmNinitialResourcesPersistent , False ,
1535                     NULL ) ;
1536 
1537    XtVaSetValues( tw->wactar ,
1538                      XmNleftAttachment , XmATTACH_FORM ,
1539                      XmNrightAttachment, XmATTACH_FORM ,
1540                      XmNtopAttachment  , XmATTACH_FORM ,
1541                      XmNtopOffset      , 7 ,
1542                   NULL ) ;
1543 
1544    tw->wtext = XtVaCreateManagedWidget(
1545                     wtype , xmTextWidgetClass , tw->wscroll ,
1546                        XmNeditMode               , XmMULTI_LINE_EDIT ,
1547                        XmNautoShowCursorPosition , cursorable ,
1548                        XmNeditable               , editable ,
1549                        XmNcursorPositionVisible  , cursorable ,
1550                     NULL ) ;
1551 
1552    if( msg == NULL ) msg = "\0" ;  /* 27 Sep 2000 */
1553 
1554    if( msg != NULL ){
1555       int cmax = 20 , ll , nlin ;
1556       char *cpt , *cold , cbuf[128] ;
1557       XmString xstr=NULL ;
1558       XmFontList xflist=NULL ;
1559 
1560       /* In lesstif, the text length is limited by the XmTextGetMaxLength
1561        * resource, however setting it via XmTextSetMaxLength does not work.
1562        * The string lengths seems to be limited to perhaps 100, even though
1563        * XmTextGetMaxLength might return 256.
1564        *
1565        * The solution is to use XmTextSetString(w, str) to set the text.
1566        * After that, XmTextGetMaxLength returns an updated value.
1567        *
1568        * 31 Dec, 2008 [lesstif patrol] */
1569 #ifdef USING_LESSTIF
1570       XmTextSetString( tw->wtext , msg ) ;
1571 #else
1572       XtVaSetValues( tw->wtext , XmNvalue , msg , NULL ) ;
1573 #endif
1574 
1575       XtVaGetValues( tw->wtext , XmNfontList , &xflist , NULL ) ;
1576 
1577       cmax = 20 ; nlin = 1 ;
1578       for( cpt=msg,cold=msg ; *cpt != '\0' ; cpt++ ){
1579         if( *cpt == '\n' ){
1580           ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
1581           cold = cpt ; nlin++ ;
1582         }
1583       }
1584       ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
1585       if( cmax > 100 ) cmax = 100 ;
1586       cmax +=3 ;
1587       for( ll=0 ; ll < cmax ; ll++ ) cbuf[ll] = 'x' ;
1588       cbuf[cmax] = '\0' ;
1589 
1590       xstr = XmStringCreateLtoR( cbuf , XmFONTLIST_DEFAULT_TAG ) ;
1591       swid = XmStringWidth ( xflist , xstr ) + 44 ;
1592       shi  = XmStringHeight( xflist , xstr ) * nlin + 66 ;
1593       XmStringFree( xstr ) ;
1594 
1595       cmax = WidthOfScreen(XtScreen(wpar)) - 128 ;
1596       if( swid > cmax ) swid = cmax ;
1597 
1598       cmax = HeightOfScreen(XtScreen(wpar)) - 128 ;
1599       if( shi > cmax ) shi = cmax ;
1600    } else {
1601       swid = shi = 100 ;
1602    }
1603 
1604    XtManageChild( tw->wtop ) ;
1605 
1606    XtVaSetValues( tw->wshell , XmNwidth,swid , XmNheight,shi , NULL ) ;
1607 
1608    XtPopup( tw->wshell , XtGrabNone ) ; RWC_sleep(1);
1609 
1610    RWC_visibilize_widget( tw->wshell ) ;  /* 09 Nov 1999 */
1611 
1612    RWC_xineramize( XtDisplay(tw->wshell) ,
1613                    xpr,ypr,swid,shi , &xpr,&ypr ); /* 27 Sep 2000 */
1614 
1615    XtVaSetValues( tw->wshell, XmNx,xpr , XmNy,ypr , NULL ) ;
1616 
1617    tw->shell_width = swid ; tw->shell_height = shi ; /* 10 Jul 2001 */
1618 
1619    NORMAL_cursorize( tw->wshell ) ;
1620 
1621    ws = XtNameToWidget(tw->wscroll,"VertScrollBar") ;
1622    if( ws != NULL ){
1623 #ifdef DARWIN
1624      XtVaSetValues( ws , XmNshowArrows , XmMIN_SIDE , NULL ) ;
1625 #endif
1626      (void)XmProcessTraversal( ws , XmTRAVERSE_CURRENT ) ;
1627 #if 0
1628      (void)XtAppAddTimeOut( XtWidgetToApplicationContext(ws) ,
1629                             66 , MCW_textwin_timer_CB , ws   ) ;
1630 #endif
1631    }
1632 #ifdef DARWIN
1633    ws = XtNameToWidget(tw->wscroll,"HorScrollBar") ;
1634    if( ws != NULL )
1635      XtVaSetValues( ws , XmNshowArrows , XmMIN_SIDE , NULL ) ;
1636 #endif
1637 
1638    RETURN(tw) ;
1639 }
1640 
1641 /*--------------------------------------------------------------------*/
1642 
MCW_textwin_alter(MCW_textwin * tw,char * mmm)1643 void MCW_textwin_alter( MCW_textwin *tw , char *mmm ) /* 10 Jul 2001 */
1644 {
1645    int swid , shi ;
1646    char *msg = mmm ;
1647    int cmax = 20 , ll , nlin ;
1648    char *cpt , *cold , cbuf[128] ;
1649    XmString xstr ;
1650    XmFontList xflist=(XmFontList)NULL ;
1651 
1652 ENTRY("MCW_textwin_alter") ;
1653 
1654    if( tw == NULL ) EXRETURN ;     /* bad */
1655 
1656    if( msg == NULL ) msg = " " ; /* don't let user be so stupid */
1657 
1658 #if 0
1659    /*-- compute size of text window with new message in it --*/
1660 
1661    XtVaGetValues( tw->wtext , XmNfontList , &xflist , NULL ) ;
1662 
1663    /* find longest line in msg */
1664 
1665    cmax = 20 ; nlin = 1 ;
1666    for( cpt=msg,cold=msg ; *cpt != '\0' ; cpt++ ){
1667       if( *cpt == '\n' ){
1668          ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
1669          cold = cpt ; nlin++ ;
1670       }
1671    }
1672    ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
1673    if( cmax > 100 ) cmax = 100 ;
1674 
1675    /* fill a dummy string of that length, plus a bit */
1676 
1677    cmax+=3 ;
1678    for( ll=0 ; ll < cmax ; ll++ ) cbuf[ll] = 'x' ;
1679    cbuf[cmax] = '\0' ;
1680 
1681    /* find width, height of the dummy string */
1682 
1683    xstr = XmStringCreateLtoR( cbuf , XmFONTLIST_DEFAULT_TAG ) ;
1684    swid = XmStringWidth ( xflist , xstr ) + 44 ;
1685    shi  = XmStringHeight( xflist , xstr ) * nlin + 66 ;
1686    XmStringFree( xstr ) ;
1687 
1688    /* find width, height of screen */
1689 
1690    cmax = WidthOfScreen(XtScreen(tw->wshell)) - 128 ;
1691    if( swid > cmax ) swid = cmax ;
1692 
1693    cmax = HeightOfScreen(XtScreen(tw->wshell)) - 128 ;
1694    if( shi > cmax ) shi = cmax ;
1695 #endif
1696 
1697    /*-- actually set new text --*/
1698 
1699    XtVaSetValues( tw->wtext , XmNvalue , msg , NULL ) ;
1700 
1701 #if 1
1702    MCW_widget_geom( tw->wtext , &swid , &shi , NULL,NULL ) ;
1703    XtVaSetValues( tw->wshell , XmNwidth,swid+29 , XmNheight,shi+59 , NULL ) ;
1704    tw->shell_width = swid+29 ; tw->shell_height = shi+59 ;
1705 #endif
1706 
1707 #if 0
1708    /*-- maybe set new window size --*/
1709 
1710    if( swid > tw->shell_width || shi > tw->shell_height ){
1711       tw->shell_width  = swid = MAX( swid , tw->shell_width ) ;
1712       tw->shell_height = shi  = MAX( shi  , tw->shell_height ) ;
1713       XtVaSetValues( tw->wshell , XmNwidth,swid , XmNheight,shi , NULL ) ;
1714    }
1715 #endif
1716 
1717    EXRETURN ;
1718 }
1719 
1720 /*--------------------------------------------------------------------*/
1721 
MCW_textwin_CB(Widget w,XtPointer client_data,XtPointer call_data)1722 void MCW_textwin_CB( Widget w , XtPointer client_data , XtPointer call_data )
1723 {
1724    MCW_textwin *tw = (MCW_textwin *) client_data ;
1725    char *wname    = XtName(w) ;
1726 
1727    if( client_data == NULL ) return ;
1728 
1729    if( strcmp(wname,"Quit") == 0 ){
1730       if( tw->kill_func != NULL )
1731 #if 0
1732         tw->kill_func(tw->kill_data); /* 10 Jul 2001 */
1733 #else
1734         AFNI_CALL_VOID_1ARG( tw->kill_func , XtPointer , tw->kill_data ) ;
1735 #endif
1736       XtDestroyWidget( tw->wshell ) ;
1737       myXtFree( tw ) ;
1738       return ;
1739    }
1740 
1741    XBell( XtDisplay(w) , 100 ) ;
1742    return ;
1743 }
1744 
1745 /*--------------------------------------------------------------------*/
1746 
MCW_textwinkill_CB(Widget w,XtPointer client_data,XtPointer call_data)1747 void MCW_textwinkill_CB( Widget w , XtPointer client_data , XtPointer call_data )
1748 {
1749    MCW_textwin *tw = (MCW_textwin *) client_data ;
1750 
1751    if( tw->kill_func != NULL )
1752 #if 0
1753      tw->kill_func(tw->kill_data); /* 10 Jul 2001 */
1754 #else
1755      AFNI_CALL_VOID_1ARG( tw->kill_func , XtPointer , tw->kill_data ) ;
1756 #endif
1757    XtDestroyWidget( tw->wshell ) ;
1758    myXtFree( tw ) ;
1759    return ;
1760 }
1761 
1762 /*-----------------------------------------------------------------------
1763    03 Jan 1999: Check if a widget is potentially visible
1764                 -- return 0 if not, 1 if yes.
1765 -------------------------------------------------------------------------*/
1766 
MCW_widget_visible(Widget w)1767 int MCW_widget_visible( Widget w )
1768 {
1769    Window ww ;
1770    XWindowAttributes wa ;
1771 
1772    if( w == (Widget)NULL ) return 0 ;
1773    ww = XtWindow(w) ;
1774    if( ww == (Window)NULL ) return 0 ;
1775 
1776    XGetWindowAttributes( XtDisplay(w) , ww , &wa ) ;
1777 
1778    return ( (wa.map_state == IsViewable) ? 1 : 0 ) ;
1779 }
1780 
1781 /*------------------------------------------------------------------
1782  June 1999: routine to get string constants either from X defaults
1783             or from Unix environment variables.  Returns a pointer
1784             to static storage -- do not free()!
1785 --------------------------------------------------------------------*/
1786 
1787 #include <ctype.h>
1788 
RWC_getname(Display * display,char * name)1789 char * RWC_getname( Display *display , char *name )
1790 {
1791    char *cval , qqq[256] ;
1792    int nn , ii ;
1793 
1794    if( name == NULL || name[0] == '\0' ) return NULL ;
1795 
1796    /* try X11 */
1797 
1798    if( display != NULL ){
1799      cval = XGetDefault(display,"AFNI",name) ;
1800      if( cval != NULL ) return cval ;
1801    }
1802 
1803    /* try AFNI_name */
1804 
1805    strcpy(qqq,"AFNI_") ; strcat(qqq,name) ;
1806    cval = my_getenv(qqq) ;
1807    if( cval != NULL ) return cval ;
1808 
1809    /* try AFNI_NAME (uppercase it) */
1810 
1811    strcpy(qqq,"AFNI_") ; nn = strlen(name) ;
1812    for( ii=0 ; ii < nn && ii < 250 ; ii++ ) qqq[ii+5] = toupper(name[ii]) ;
1813    qqq[ii+5] = '\0' ;
1814    cval = my_getenv(qqq) ;
1815    return cval ;
1816 }
1817 
1818 /*-------------------------------------------------------------------
1819   09 Nov 1999: move a widget to make sure it is visible
1820 ---------------------------------------------------------------------*/
1821 
RWC_visibilize_widget(Widget w)1822 void RWC_visibilize_widget( Widget w )
1823 {
1824    Position xroot , yroot ;
1825    int wx,hy,xx,yy , scr_width,scr_height , xo,yo ;
1826    Screen *scr ;
1827 
1828 ENTRY("RWC_visibilize_widget") ;
1829 
1830    if( w == NULL || !XtIsWidget(w) ) EXRETURN ;
1831 
1832    MCW_widget_geom( w , &wx,&hy,&xx,&yy ) ;     /* geometry of widget */
1833 
1834    scr        = XtScreen( w ) ;
1835    scr_width  = WidthOfScreen( scr ) ;
1836    scr_height = HeightOfScreen( scr ) ;
1837 
1838    xo = xx ; yo = yy ;                          /* save original position */
1839 
1840    if( xx+wx > scr_width ) xx = scr_width - wx ;
1841    if( xx    < 0         ) xx = 0              ;
1842 
1843    if( yy+hy > scr_height ) yy = scr_height - hy ;
1844    if( yy    < 0          ) yy = 0               ;
1845 
1846    RWC_xineramize( XtDisplay(w) , xx,yy,wx,hy , &xx,&yy ); /* 27 Sep 2000 */
1847 
1848    if( xx != xo || yy != yo )
1849      XtVaSetValues( w , XmNx , xx , XmNy , yy , NULL ) ;
1850 
1851    RWC_sleep(1) ; MCW_expose_widget(w) ;  /* 09 Nov 2007 */
1852 
1853    EXRETURN ;
1854 }
1855 
1856 /*----------------------------------------------------------------------
1857   A callback version of the above (for use when menus are mapped, say)
1858 ------------------------------------------------------------------------*/
1859 
RWC_visibilize_timeout_CB(XtPointer cd,XtIntervalId * id)1860 static void RWC_visibilize_timeout_CB( XtPointer cd , XtIntervalId *id )
1861 {
1862    Widget w = (Widget) cd ;
1863 ENTRY("RWC_visibilize_timeout_CB") ;
1864    RWC_visibilize_widget(w) ; EXRETURN ;
1865 }
1866 
1867 /*--------------------------------------------------------------------*/
1868 
RWC_visibilize_CB(Widget w,XtPointer cd,XtPointer cb)1869 void RWC_visibilize_CB( Widget w , XtPointer cd , XtPointer cb )
1870 {
1871    Widget wpar = w ;
1872 ENTRY("RWC_visibilize_CB") ;
1873 
1874    if( AFNI_yesenv("AFNI_DONT_MOVE_MENUS") ) return ;  /* 08 Aug 2001 */
1875 
1876    while( !XtIsShell(wpar) ){ wpar = XtParent(w); } /* find 1st shell parent */
1877 
1878    /* must wait for the thing to actually appear, dammit */
1879 
1880    (void) XtAppAddTimeOut( XtWidgetToApplicationContext(wpar) ,
1881                            3 , RWC_visibilize_timeout_CB , wpar ) ;
1882    EXRETURN ;
1883 }
1884 
1885 /*----------------------------------------------------------------------
1886    Given a rectangle (xx..xx+ww,yy..yy+hh), return the new origin
1887    (xn,yn) so that the rectangle (xn..xn+ww,yn..yn+hh) fits onto
1888    a single Xinerama sub-screen.  If the AFNI.xinerama X11 resource is
1889    not found, then this routine uses the display size.
1890    -- RWCox -- 27 Sep 2000
1891 ------------------------------------------------------------------------*/
1892 
1893 #define BUF 5  /* buffer around the rectangle */
1894 
RWC_xineramize(Display * dpy,int xx,int yy,int ww,int hh,int * xn,int * yn)1895 void RWC_xineramize( Display *dpy,
1896                      int xx, int yy, int ww, int hh, int *xn, int *yn )
1897 {
1898    static int first=1 ;
1899    static int nxsi=0 , *xbot,*ybot,*xtop,*ytop ;
1900    int ii , ss ;
1901 
1902 ENTRY("RWC_xineramize") ;
1903 
1904    if( dpy==NULL || xn==NULL || yn==NULL || ww<0 || hh<0 ) EXRETURN; /* ERROR */
1905 
1906    /*--- first time in: check AFNI.xinerama X resource
1907                         load boundaries of sub-screens from resource ---*/
1908 
1909    if( first ){
1910       char *xdef , *xp ;
1911       int nn,xorg,yorg,wide,high ;
1912 
1913       first = 0 ;                         /* never again */
1914       xdef  = getenv( "AFNI_XINERAMA" ) ;
1915 
1916       if( xdef != NULL && (xdef[0] == 'N' || xdef[0] == 'n') ){ /* skip Xinerama */
1917          nxsi = 0 ;
1918          STATUS("AFNI_XINERAMA is NO") ;
1919       } else {
1920          xdef = XGetDefault(dpy,"AFNI","xinerama") ; /* get resource */
1921          if( xdef == NULL ) xdef = getenv("AFNI_xinerama") ;  /* 27 Oct 2003 */
1922          if( xdef != NULL ){
1923             char *qdef = strdup(xdef) ;
1924             for( nn=0 ; qdef[nn] != '\0' ; nn++ )
1925               if( qdef[nn] == '_' || qdef[nn] == ':' ||
1926                   qdef[nn] == ';' || qdef[nn] == ','   ) qdef[nn] = ' ' ;
1927 
1928             nn = 0 ; sscanf(qdef,"%d%n",&nxsi,&nn) ;  /* number of sub-screens */
1929             if( nn <= 0 || nxsi <= 1 ){               /* ERROR */
1930                nxsi = 0 ;
1931             } else {
1932                xbot = (int *) malloc(sizeof(int)*nxsi) ; /* make arrays to */
1933                ybot = (int *) malloc(sizeof(int)*nxsi) ; /* store sub-screen */
1934                xtop = (int *) malloc(sizeof(int)*nxsi) ; /* coordinate ranges */
1935                ytop = (int *) malloc(sizeof(int)*nxsi) ;
1936                xp = qdef + nn ;
1937                for( ii=0 ; ii < nxsi ; ii++ ){    /* scan for sub-screen info */
1938                   nn = 0 ;
1939                   sscanf(xp,"%d%d%d%d%d%n",&ss,&xorg,&yorg,&wide,&high,&nn) ;
1940                   if( nn <= 0 ) break ;           /* ERROR */
1941                   xbot[ii] = xorg ; xtop[ii] = xorg+wide ;
1942                   ybot[ii] = yorg ; ytop[ii] = yorg+high ;
1943                   xp += nn ;
1944 
1945                   if(PRINT_TRACING){
1946                     char str[256] ;
1947                     sprintf(str," Screen %d: xbot=%4d ybot=%4d xtop=%4d ytop=%4d",
1948                                   ii,xbot[ii],ybot[ii],xtop[ii],ytop[ii] ) ;
1949                     STATUS(str) ;
1950                   }
1951                }
1952 
1953                nxsi = ii ;  /* in case the scan aborted */
1954             }
1955          }
1956       }
1957 
1958       /* if nothing found yet, use the display size */
1959 
1960       if( nxsi <= 0 ){
1961          nxsi = 1 ;
1962          xbot = (int *) malloc(sizeof(int)*nxsi) ;
1963          ybot = (int *) malloc(sizeof(int)*nxsi) ;
1964          xtop = (int *) malloc(sizeof(int)*nxsi) ;
1965          ytop = (int *) malloc(sizeof(int)*nxsi) ;
1966          xbot[0] = ybot[0] = 0 ;
1967          xtop[0] = WidthOfScreen(DefaultScreenOfDisplay(dpy)) ;
1968          ytop[0] = HeightOfScreen(DefaultScreenOfDisplay(dpy)) ;
1969       }
1970    }
1971 
1972 #if 0                                           /* doesn't occur anymore */
1973    if( nxsi == 0 ){ *xn=xx; *yn=yy; EXRETURN; } /* not setup? change nothing */
1974 #endif
1975 
1976    /*--- find the Xinerama sub-screen that (xx,yy) is on (if any) ---*/
1977 
1978    if( nxsi > 1 ){
1979       for( ss=0 ; ss < nxsi ; ss++ ){
1980          if( xx >= xbot[ss] && xx < xtop[ss] &&
1981              yy >= ybot[ss] && yy < ytop[ss]   ) break ;
1982       }
1983    } else {
1984       ss = 0 ;  /* must use #0 - what else is there? */
1985    }
1986 
1987    if(PRINT_TRACING){
1988       char str[256] ;
1989       sprintf(str,"Rect: xx=%d yy=%d ww=%d hh=%d; On ss=%d",xx,yy,ww,hh,ss); STATUS(str);
1990    }
1991 
1992    /*--- if not inside any screen, find one it is closest to ---*/
1993 
1994    if( ss >= nxsi ){
1995       int dleft,dright,dtop,dbot,dd , dmin , xdif,ydif ;
1996       dmin = 123456789 ; ss = 0 ;
1997       for( ii=0 ; ii < nxsi; ii++ ){
1998          xdif = (xx < xbot[ii]) ? (xbot[ii]-xx)       /* x dist to    */
1999                :(xx > xtop[ii]) ? (xx-xtop[ii]) : 0 ; /* [xbot..xtop] */
2000 
2001          ydif = (yy < ybot[ii]) ? (ybot[ii]-yy)
2002                :(yy > ytop[ii]) ? (yy-ytop[ii]) : 0 ;
2003 
2004          dleft  = abs(xx-xbot[ii]) + ydif ;  /* L1 dist to left edge */
2005          dright = abs(xx-xtop[ii]) + ydif ;
2006          dbot   = abs(yy-ybot[ii]) + xdif ;
2007          dtop   = abs(yy-ytop[ii]) + xdif ;
2008 
2009                            dd = dleft ;      /* find smallest dist */
2010          if( dright < dd ) dd = dright ;
2011          if( dbot   < dd ) dd = dbot ;
2012          if( dtop   < dd ) dd = dtop ;
2013 
2014          if( dd < dmin ){ dmin = dd; ss = ii; } /* smallest so far? */
2015       }
2016 
2017       if(PRINT_TRACING){
2018          char str[256] ; sprintf(str,"New ss=%d",ss) ; STATUS(str) ;
2019       }
2020    }
2021 
2022    /*--- now adjust position so all of rectangle
2023          (xx..xx+ww,yy..yy+hh) fits on that screen (if possible) ---*/
2024 
2025    if( xx+ww+BUF >= xtop[ss] ){ xx = xtop[ss]-ww-1-2*BUF; } /* move left */
2026    if( yy+hh+BUF >= ytop[ss] ){ yy = ytop[ss]-hh-1-2*BUF; } /* move up  */
2027    if( xx    < xbot[ss]+BUF  ){ xx = xbot[ss]+BUF; }        /* move right */
2028    if( yy    < ybot[ss]+BUF  ){ yy = ybot[ss]+BUF; }        /* move down */
2029 
2030 
2031    if(PRINT_TRACING){
2032       char str[256] ; sprintf(str,"New xx=%d yy=%d",xx,yy) ; STATUS(str) ;
2033    }
2034 
2035    *xn = xx ; *yn = yy ; EXRETURN ;
2036 }
2037 
2038 /*----------------------------------------------------------------------
2039   NULL out a pointer when a widget is destroyed -- 31 Jul 2001 - RWCox
2040 ------------------------------------------------------------------------*/
2041 
RWC_destroy_nullify_CB(Widget w,XtPointer xp,XtPointer cd)2042 void RWC_destroy_nullify_CB( Widget w, XtPointer xp, XtPointer cd )
2043 {
2044    void ** p = (void **) xp ;
2045 ENTRY("RWC_destroy_nullify_CB") ;
2046    if( p != NULL ) *p = NULL ;
2047    EXRETURN ;
2048 }
2049 
RWC_destroy_nullify(Widget w,void ** p)2050 void RWC_destroy_nullify( Widget w, void **p )
2051 {
2052    if( p != NULL && w != NULL )
2053      XtAddCallback( w, XmNdestroyCallback, RWC_destroy_nullify_CB, p ) ;
2054    return ;
2055 }
2056 
RWC_destroy_nullify_cancel(Widget w,void ** p)2057 void RWC_destroy_nullify_cancel( Widget w, void **p )
2058 {
2059    if( w != NULL )
2060      XtRemoveCallback( w, XmNdestroyCallback, RWC_destroy_nullify_CB, p ) ;
2061    return ;
2062 }
2063 
2064 /*---------------------------------------------------------------------------*/
2065 
RWC_draw_rect(Display * dis,Window win,GC gc,int x1,int y1,int x2,int y2)2066 static void RWC_draw_rect( Display *dis, Window win, GC gc,
2067                            int x1, int y1, int x2, int y2  )
2068 {
2069   int xb,yb , xt,yt ;
2070   unsigned int short w,h ;
2071 
2072   if( x1 < x2 ){ xb=x1; xt=x2; } else { xb=x2; xt=x1; }
2073   if( y1 < y2 ){ yb=y1; yt=y2; } else { yb=y2; yt=y1; }
2074   w = xt-xb ; h = yt-yb ;
2075   if( w || h )
2076     XDrawRectangle( dis,win,gc , xb,yb,w,h ) ;
2077   else
2078     XDrawPoint( dis,win,gc , xb,yb ) ;
2079 }
2080 
2081 /*---------------------------------------------------------------------------*/
2082 
2083 static Cursor cur = None ;  /* 17 Jun 2002 */
2084 
RWC_drag_cursor(Display * dis)2085 static void RWC_drag_cursor( Display *dis )
2086 {
2087    XColor fg , bg ;
2088    Colormap cmap ;
2089    RwcBoolean  good ;
2090 
2091    if( cur == None ){
2092      cur  = XCreateFontCursor( dis , XC_arrow ) ;
2093      cmap = DefaultColormap( dis , DefaultScreen(dis) ) ;
2094      good =   XParseColor( dis, cmap, "yellow" , &fg )
2095            && XParseColor( dis, cmap, "red"    , &bg )  ;
2096      if( good ) XRecolorCursor( dis , cur , &fg , &bg ) ;
2097    }
2098 }
2099 
RWC_drag_rectangle(Widget w,int x1,int y1,int * x2,int * y2)2100 void RWC_drag_rectangle( Widget w, int x1, int y1, int *x2, int *y2 )
2101 {
2102    Display *dis ;
2103    Window win , rW,cW ;
2104    int grab , xold,yold , x,y, rx,ry , first=1 ;
2105    unsigned int mask ;                                      /* which buttons */
2106    unsigned int bmask=Button1Mask|Button2Mask|Button3Mask ; /* all buttons  */
2107    XGCValues  gcv;
2108    GC         myGC ;
2109 
2110 ENTRY("RWC_drag_rectangle") ;
2111 
2112    /** make a GC for invert drawing **/
2113 
2114    gcv.function = GXinvert ;
2115    myGC         = XtGetGC( w , GCFunction , &gcv ) ;
2116 
2117    /** grab the pointer (so no one else gets events from it),
2118        and confine it to the window in question              **/
2119 
2120    dis = XtDisplay(w) ; win = XtWindow(w) ;
2121 
2122    RWC_drag_cursor(dis) ;
2123 
2124    grab = !XGrabPointer(dis, win, False, 0, GrabModeAsync,
2125                         GrabModeAsync, win, cur , (Time)CurrentTime);
2126 
2127    /* grab fails => exit */
2128 
2129    if( !grab ){ XBell(dis,100); *x2=x1; *y2=y1; EXRETURN; }
2130 
2131    xold = x1 ; yold = y1 ;  /* current location of pointer */
2132 
2133    /** loop and find out where the pointer is (while button is down) **/
2134 
2135    while( XQueryPointer(dis,win,&rW,&cW,&rx,&ry,&x,&y,&mask) ){
2136 
2137      /* check if all buttons are released */
2138 
2139      if( !(mask & bmask) ) break ;  /* no button down => done! */
2140 
2141      /* pointer now at (x,y) in the window */
2142 
2143      /* if it has moved, redraw rectangle */
2144 
2145      if( x != xold || y != yold ){
2146 
2147        if( !first )  /* undraw old rectangle */
2148          RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
2149 
2150        /* draw new rectangle */
2151 
2152        xold = x ; yold = y ; first = 0 ;
2153        RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
2154 
2155      } /* end of new (x,y) position */
2156 
2157    } /* end of loop while button is pressed */
2158 
2159    if( !first )  /* undraw old rectangle */
2160      RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
2161 
2162    /* clean up */
2163 
2164    XtReleaseGC( w , myGC ) ;
2165    if (grab) XUngrabPointer(dis, (Time)CurrentTime) ;
2166 
2167    *x2 = xold ; *y2 = yold ;  /* output values */
2168    EXRETURN ;
2169 }
2170 
2171 /*---------------------------------------------------------------------------*/
2172 
RWC_draw_circle(Display * dis,Window win,GC gc,int xc,int yc,int rad)2173 static void RWC_draw_circle( Display *dis, Window win, GC gc, int xc, int yc, int rad )
2174 {
2175    int xb,yb ;
2176    unsigned int ww ;
2177 
2178    if( rad < 0 ) rad = 0 ;
2179    xb = xc-rad ; yb = yc-rad ; ww = 2*rad ;
2180    XDrawArc( dis,win,gc , xb,yb , ww,ww , 0,360*64 ) ;
2181 }
2182 
2183 /*---------------------------------------------------------------------------*/
2184 
RWC_drag_circle(Widget w,int x1,int y1,int * radius)2185 void RWC_drag_circle( Widget w, int x1, int y1, int *radius )
2186 {
2187    Display *dis ;
2188    Window win , rW,cW ;
2189    int grab , xold,yold , x,y, rx,ry , first=1 , rrr=0 ;
2190    unsigned int mask ;                                      /* which buttons */
2191    unsigned int bmask=Button1Mask|Button2Mask|Button3Mask ; /* all buttons  */
2192    XGCValues  gcv;
2193    GC         myGC ;
2194 
2195 ENTRY("RWC_drag_circle") ;
2196 
2197    /** make a GC for invert drawing **/
2198 
2199    gcv.function = GXinvert ;
2200    myGC         = XtGetGC( w , GCFunction , &gcv ) ;
2201 
2202    /** grab the pointer (so no one else gets events from it),
2203        and confine it to the window in question              **/
2204 
2205    dis = XtDisplay(w) ; win = XtWindow(w) ;
2206 
2207    RWC_drag_cursor(dis) ;
2208 
2209    grab = !XGrabPointer(dis, win, False, 0, GrabModeAsync,
2210                         GrabModeAsync, win, cur , (Time)CurrentTime);
2211 
2212    /* grab fails => exit */
2213 
2214    if( !grab ){ XBell(dis,100); *radius=0; EXRETURN; }
2215 
2216    xold = x1 ; yold = y1 ;  /* current location of pointer */
2217 
2218    /** loop and find out where the pointer is (while button is down) **/
2219 
2220    while( XQueryPointer(dis,win,&rW,&cW,&rx,&ry,&x,&y,&mask) ){
2221 
2222      /* check if all buttons are released */
2223 
2224      if( !(mask & bmask) ) break ;  /* no button down => done! */
2225 
2226      /* pointer now at (x,y) in the window */
2227 
2228      /* if it has moved, redraw rectangle */
2229 
2230      if( x != xold || y != yold ){
2231 
2232        if( !first )  /* undraw old circle */
2233          RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
2234 
2235        /* draw new circle */
2236 
2237        xold = x ; yold = y ; first = 0 ;
2238        rrr = (int)rint(sqrt( (x-x1)*(x-x1) + (y-y1)*(y-y1) )) ;
2239        RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
2240 
2241      } /* end of new (x,y) position */
2242 
2243    } /* end of loop while button is pressed */
2244 
2245    if( !first )  /* undraw old circle */
2246      RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
2247 
2248    /* clean up */
2249 
2250    XtReleaseGC( w , myGC ) ;
2251    if (grab) XUngrabPointer(dis, (Time)CurrentTime) ;
2252 
2253    *radius = rrr ;
2254    EXRETURN ;
2255 }
2256 
2257 /*-------------------------------------------------------------------*/
2258 /*!  Sleep a given # of milliseconds (uses the Unix select routine).
2259 ---------------------------------------------------------------------*/
2260 
2261 #include <sys/time.h>
2262 #include <sys/types.h>
2263 #include <unistd.h>
2264 
RWC_sleep(int msec)2265 void RWC_sleep( int msec )
2266 {
2267    struct timeval tv ;
2268    if( msec <= 0 ) return ;             /* can't wait into the past */
2269    tv.tv_sec  = msec/1000 ;
2270    tv.tv_usec = (msec%1000)*1000 ;
2271    select( 1 , NULL,NULL,NULL , &tv ) ;
2272    return ;
2273 }
2274 
2275 /*-----------------------------------------------------------------*/
2276 /*! Popdown a widget that may not be a shell. [30 Jun 2003]
2277 -------------------------------------------------------------------*/
2278 
RWC_XtPopdown(Widget w)2279 void RWC_XtPopdown( Widget w )
2280 {
2281    Widget wpar = w ;
2282 
2283 ENTRY("RWC_XtPopdown") ;
2284 
2285    if( wpar == NULL ) EXRETURN ;
2286    RWC_sleep(1) ;
2287    while( XtIsShell(wpar)==0 && XtParent(wpar)!=NULL ) wpar = XtParent(wpar);
2288    XtPopdown(wpar) ; RWC_sleep(1) ;
2289    EXRETURN ;
2290 }
2291 
2292 /*-----------------------------------------------------------------*/
2293 /******************** Speech stuff (for Mac OS X) ******************/
2294 
2295 #if !defined(NO_FRIVOLITIES) && defined(DARWIN)
2296 
2297 #include <unistd.h>
2298 #include <string.h>
2299 #include <stdlib.h>
2300 #include <ctype.h>
2301 #include <sys/wait.h>
2302 #include <sys/types.h>
2303 
2304 static int have_say = -1 ;
2305 static char voice[128] = "Cellos" ;
2306 
2307 /*-----------------------------------------------------------------*/
2308 /*! Set the voice for the Apple speech synthesizer. */
2309 
AFNI_speak_setvoice(char * vvv)2310 void AFNI_speak_setvoice( char *vvv )
2311 {
2312    int ll ;
2313    if( vvv == NULL || *vvv == '\0' ) return ;
2314    ll = strlen(vvv) ; if( ll > 100 ) return ;
2315    strcpy(voice,vvv) ;               return ;
2316 }
2317 
2318 
2319 /*-----------------------------------------------------------------*/
2320 /*! Speak a string using Apple's say command:
2321     - string = Apple text-to-speech code
2322     - nofork = 1 if you want to wait for the speech to finish;
2323              = 0 if you want the function to return immediately,
2324                  before speech finishes (or perhaps even starts). */
2325 
AFNI_speak(char * string,int nofork)2326 void AFNI_speak( char *string , int nofork )
2327 {
2328    char *buf ; pid_t ppp ;
2329 
2330    /* bad input ==> quit */
2331 
2332    if( string == NULL || *string == '\0' ) return ;
2333 
2334    /* user says "don't talk" ==> quit */
2335 
2336    buf = getenv("AFNI_SPEECH") ;
2337 #if 1
2338    if( buf == NULL || toupper(*buf) != 'Y' ) return ;   /* 02 Apr 2004 */
2339 #else
2340    if( buf != NULL && toupper(*buf) == 'N' ) return ;
2341 #endif
2342 
2343    /* don't have "say" program ==> quit */
2344 
2345    if( have_say == -1 ) have_say = (THD_find_executable("say") != NULL) ;
2346    if( have_say ==  0 ) return ;
2347 
2348    /* if want speech to run in a separate process ... */
2349 
2350    if( !nofork ){
2351      ppp = fork() ;
2352      if( ppp < 0 ) return ; /* fork failed */
2353 
2354      /* parent: wait for child to exit (happens almost instantly) */
2355 
2356      if( ppp > 0 ){ waitpid(ppp,NULL,0); return; }
2357 
2358      /* child: fork again immediately, then this child exits;
2359         this is to prevent zombie processes from hanging around */
2360 
2361      ppp = fork() ; if( ppp != 0 ) _exit(0) ; /* child exits now */
2362 
2363      /* grandchild continues on to actually do something */
2364    }
2365 
2366    /* Run the say program using system() */
2367 
2368    buf = (char *)malloc(strlen(string)+32) ;
2369    sprintf(buf,"say -v%s '%s'",voice,string) ;
2370    system(buf) ; free(buf) ;
2371 
2372    if( !nofork ) _exit(0) ;  /* grandchild exits */
2373    return ;                  /* no forking ==> return to caller */
2374 }
2375 
2376 #else
2377 
AFNI_speak(char * string,int nofork)2378 void AFNI_speak( char *string , int nofork ){ return; }  /* dummy function */
AFNI_speak_setvoice(char * vvv)2379 void AFNI_speak_setvoice( char *vvv ){ return; }
2380 
2381 #endif
2382 
2383 /****************************************************************************/
2384 
AFNI_startup_sound(int nnn)2385 void AFNI_startup_sound(int nnn)
2386 {
2387 #ifndef NO_FRIVOLITIES
2388   static int have_sox=-1 ; int ii ;
2389 
2390   if( have_sox < 0 ) have_sox = ( THD_find_executable("sox") != NULL ) ;
2391   if( have_sox == 0 ) return ;
2392 
2393   for( ii=0 ; ii < nnn ; ii++ ){
2394    if( ii%2 == 0 )
2395      system("sox -n -d synth 0.5 pluck E3 pluck F3 gain -h -27 delay 0.2 0 fade t 0.05 &> /dev/null") ;
2396    else
2397      system("sox -n -d synth 0.5 pluck F3 pluck E3 gain -h -27 delay 0.2 0 fade t 0.05 &> /dev/null") ;
2398   }
2399 #endif
2400   return ;
2401 }
2402 
2403 /****************************************************************************/
2404 
2405 #ifdef DARWIN
get_XQuartz_version(void)2406 char * get_XQuartz_version(void){
2407    char *vers , *info , *cpt , *dpt ; int len , ii ;
2408 
2409    info = AFNI_suck_file("/Applications/Utilities/XQuartz.app/Contents/Info.plist") ;
2410    if( info == NULL ) return NULL ;
2411 
2412                      cpt = strcasestr(info,"CFBundleShortVersionString") ;
2413    if( cpt == NULL ) cpt = strcasestr(info,"CFBundleVersion") ;
2414    if( cpt == NULL ){ free(info); return NULL; }
2415    dpt = strcasestr(cpt+15,"<string>") ;
2416    if( dpt == NULL ){ free(info); return NULL; }
2417    dpt += 8 ;   /* 8 = strlen("<string>") */
2418    cpt = strstr(dpt,"<") ;
2419    if( cpt == NULL || cpt == dpt ) { free(info); return NULL; }
2420    len = cpt - dpt ; if( len > 32 ){ free(info); return NULL; }
2421    vers = (char *)malloc(sizeof(char)*(len+1)) ;
2422    for( ii=0 ; ii < len ; ii++ ) vers[ii] =  dpt[ii] ;
2423    vers[len] = '\0' ;
2424    free(info) ; return vers ;
2425 }
2426 #else
2427 
get_XQuartz_version(void)2428 char * get_XQuartz_version(void){ return NULL; }
2429 
2430 #endif
2431 
2432 /****************************************************************************/
2433 #define MIN_SIZE   4
2434 #define MAX_SIZE  26
2435 #define MIN_DIST   4
2436 #define MIN_WIDTH  8
2437 #define WIDTH_ADD  8
2438 #define FINISHED  50
2439 #define rnd(x)    (lrand48() % (x))
2440 
2441 /*--------------------------------------------------------------------------*/
2442 
calc_xloc(int width,int twid)2443 static int calc_xloc(int width , int twid )
2444 {
2445    int xloc = rnd(twid+MIN_WIDTH) - MIN_WIDTH;
2446    if ((xloc + width) >= twid ) xloc = twid - width-1;
2447    else if (xloc < 0 )          xloc = 0;
2448    return xloc;
2449 }
2450 
MCW_melt_widget(Widget w)2451 void MCW_melt_widget( Widget w )
2452 {
2453    Display *dpy;
2454    Window win , rin ;
2455    GC copygc, fillgc;
2456    int screen , rww,rhh,planes ;
2457    unsigned long vmask;
2458    XSetWindowAttributes xswat;
2459    XGCValues gcvals;
2460    int finished=0;
2461    int width, xloc, yloc, dist, size, i , slow ;
2462    short *heights;
2463 
2464                        if(   w == NULL         ) return ;
2465                        if( ! XtIsRealized(w)   ) return ;
2466                        if( ! XtIsManaged(w)    ) return ;
2467                        if( ! XtIsWidget(w)     ) return ;
2468    rin = XtWindow(w) ; if( rin == (Window)NULL ) return ;
2469 
2470    MCW_widget_geom( w , &rww , &rhh , NULL,NULL ) ;
2471    if( rww < MIN_WIDTH+FINISHED || rhh < 2*MIN_SIZE ) return ;
2472 
2473    dpy = XtDisplay(w) ; screen = DefaultScreen(dpy);
2474 
2475    planes = DefaultDepthOfScreen( XtScreen(w) ) ;
2476 
2477    xswat.override_redirect = True;
2478    xswat.do_not_propagate_mask = KeyPressMask    | KeyReleaseMask   |
2479                                  ButtonPressMask | ButtonReleaseMask ;
2480    vmask = CWOverrideRedirect | CWDontPropagate;
2481    win = XCreateWindow( dpy, rin , 0, 0,  rww , rhh ,
2482                         0, CopyFromParent, CopyFromParent, CopyFromParent,
2483                         vmask, &xswat);
2484    XMapWindow(dpy, win);
2485 
2486    gcvals.graphics_exposures = False;
2487    gcvals.foreground = 1;
2488    gcvals.background = 0;
2489    copygc = XCreateGC(dpy, win,
2490                       GCForeground | GCBackground | GCGraphicsExposures,
2491                       &gcvals);
2492 
2493    gcvals.foreground = (lrand48()%2==0) ? BlackPixel(dpy,screen)
2494                                         : WhitePixel(dpy,screen) ;
2495 
2496    fillgc = XCreateGC(dpy, win, GCForeground, &gcvals);
2497 
2498    slow = (rww*rhh) / 34567 ;  /* larger ==> faster */
2499 
2500    XSync(dpy,0); if( slow < 0 ) slow = -slow ;
2501 
2502    heights = (short *) calloc(sizeof(short), rww+1 );
2503 
2504    while (1){
2505       width = rnd(MIN_WIDTH) + WIDTH_ADD;
2506 
2507       xloc = calc_xloc(width,rww); yloc = rhh ;
2508       for (i = xloc; i < (xloc + width); i++) yloc = MIN(yloc, heights[i]);
2509       if (yloc == rhh) continue;
2510 
2511       dist = rnd(yloc/8 + MIN_DIST);
2512       size = rnd(MAX(yloc/4 + MIN_SIZE, MAX_SIZE));
2513 
2514       XCopyArea(dpy, win, win, copygc,
2515                 xloc, yloc, width, size, xloc, yloc + dist);
2516       XFillRectangle(dpy, win, fillgc,
2517                      xloc, yloc, width, dist);
2518       if( slow > 0 && rnd(slow)==0 ) RWC_sleep(1);
2519       if( rnd(33) == 0 ) XSync(dpy,0) ;
2520       yloc += dist;
2521       for (i = xloc; i < (xloc + width); i++){
2522         if( (heights[i] < (rhh - MIN_SIZE)) && (yloc >= (rhh - MIN_SIZE)) )
2523           finished++;
2524         heights[i] = MAX(heights[i], yloc);
2525       }
2526       if (finished >= (rww - FINISHED)){
2527         XDestroyWindow(dpy,win); XFreeGC(dpy,copygc); XFreeGC(dpy,fillgc);
2528         XSync(dpy,0); RWC_sleep(200); free(heights); return;
2529       }
2530 #if 1
2531       if( lrand48()%47 == 0 ){
2532         gcvals.foreground = (lrand48()%3) ? BlackPixel(dpy,screen) : WhitePixel(dpy,screen) ;
2533         XChangeGC(dpy, fillgc , GCForeground, &gcvals);
2534       }
2535 #endif
2536    }
2537 }
2538