/*****************************************************************************
Major portions of this software are copyrighted by the Medical College
of Wisconsin, 1994-2000, and are released under the Gnu General Public
License, Version 2. See the file README.Copyright for details.
******************************************************************************/
#include "xutil.h"
#include "afni_environ.h"
#include "debugtrace.h" /* 12 Mar 2001 */
#include "Amalloc.h"
extern char * THD_find_executable( char * ) ;
/*--------------------------------------------------------------------
force an immediate expose for the widget
----------------------------------------------------------------------*/
/****************************************
requires the following line somewhere
#include <X11/IntrinsicP.h>
*****************************************/
void MCW_expose_widget( Widget w )
{
XExposeEvent xev;
Dimension ww , hh ;
if( w == NULL ) return ;
if( ! XtIsRealized(w) ) return ;
if( ! XtIsManaged(w) ) return ;
if( ! XtIsWidget(w) ) return ;
xev.window = XtWindow(w) ; if( xev.window == (Window) NULL ) return ;
xev.type = Expose ;
xev.display = XtDisplay(w) ;
xev.x = xev.y = 0 ;
XtVaGetValues( w, XmNwidth, &ww, XmNheight, &hh, NULL ) ;
if( ww <= 0 || hh <= 0 ) return ;
xev.width = ww ; xev.height = hh ;
(XtClass (w))->core_class.expose( w, (XEvent *)&xev, NULL ) ;
XFlush( XtDisplay(w) ) ;
return ;
}
/*--------------------------------------------------------------------
Get the Colormap for a widget -- 01 Sep 1998
----------------------------------------------------------------------*/
Colormap MCW_get_colormap( Widget w )
{
Colormap cmap = (Colormap) 0 ;
if( w == NULL || ! XtIsWidget(w) ) return (Colormap) 0 ;
XtVaGetValues( w , XmNcolormap , &cmap , NULL ) ;
return cmap ;
}
/*--------------------------------------------------------------------*/
int MCW_get_depth( Widget w ) /* 14 Sep 1998 */
{
int depth = 0 ;
if( w == NULL || ! XtIsWidget(w) ) return 0 ;
XtVaGetValues( w , XmNdepth , &depth , NULL ) ;
return depth ;
}
/*--------------------------------------------------------------------*/
Visual * MCW_get_visual( Widget w ) /* 14 Sep 1998 */
{
Visual * visual = NULL ;
Widget wpar = w ;
if( w == NULL || ! XtIsWidget(w) ) return NULL ;
while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ; /* find top */
XtVaGetValues( wpar , XmNvisual , &visual , NULL ) ;
return visual ;
}
/*--------------------------------------------------------------------
Set the Colormap for a widget -- 14 Sep 1998
(Will only work if widget is not yet realized)
----------------------------------------------------------------------*/
void MCW_set_colormap( Widget w , Colormap cmap )
{
if( w == NULL || ! XtIsWidget(w) ) return ;
XtVaSetValues( w , XmNcolormap , cmap , NULL ) ;
return ;
}
/*--------------------------------------------------------------------
swap the fg and bg colors of a widget
(the shadow colors are altered to fit the new bg)
----------------------------------------------------------------------*/
void MCW_invert_widget( Widget w )
{
Pixel bg_pix , topsh_pix , botsh_pix , fg_pix , sel_pix ;
Colormap cmap ;
if( ! XtIsWidget(w) ) return ;
XtVaGetValues( w , XmNforeground , &bg_pix , /* foreground -> bg */
XmNbackground , &fg_pix , /* background -> fg */
XmNcolormap , &cmap ,
NULL ) ;
XmGetColors( XtScreen(w) , cmap , bg_pix ,
NULL , &topsh_pix , &botsh_pix , &sel_pix ) ;
XtVaSetValues( w ,
XmNtopShadowColor , topsh_pix ,
XmNbottomShadowColor , botsh_pix ,
XmNselectColor , sel_pix ,
XmNarmColor , sel_pix ,
XmNborderColor , fg_pix ,
XmNforeground , fg_pix ,
XmNbackground , bg_pix ,
NULL ) ;
XSync( XtDisplay(w) , False ) ; /* make it happen NOW */
XmUpdateDisplay( w ) ;
return ;
}
/*---------------------------------------------------------------------
set the background color of a widget; the other colors are
altered to match, a la Motif;
cname = character specification of color
pix = if cname == NULL, use this pixel value
-----------------------------------------------------------------------*/
void MCW_set_widget_bg( Widget w , char * cname , Pixel pix )
{
Pixel bg_pix , topsh_pix , botsh_pix , fg_pix , sel_pix ;
Colormap cmap ;
#if 1
if( ! XtIsWidget(w) ) return ;
#else
if( ! XtIsObject(w) ) return ;
#endif
if( cname != NULL && strlen(cname) > 0 ){
XtVaSetValues( w ,
XtVaTypedArg , XmNbackground , XmRString ,
cname , strlen(cname)+1 ,
NULL ) ;
XtVaGetValues( w , XmNbackground , &bg_pix , NULL ) ;
} else {
bg_pix = pix ;
}
#if 0
XtVaGetValues( w , XmNcolormap , &cmap , NULL ) ;
XmGetColors( XtScreen(w) , cmap , bg_pix ,
&fg_pix , &topsh_pix , &botsh_pix , &sel_pix ) ;
XtVaSetValues( w ,
XmNtopShadowColor , topsh_pix ,
XmNbottomShadowColor , botsh_pix ,
XmNselectColor , sel_pix ,
XmNarmColor , sel_pix ,
XmNborderColor , fg_pix ,
XmNforeground , fg_pix ,
XmNbackground , bg_pix ,
NULL ) ;
XFlush( XtDisplay(w) ) ;
#else
XmChangeColor( w , bg_pix ) ;
#endif
return ;
}
/*-------------------------------------------------------------------*/
void MCW_set_widget_label( Widget w , char *str )
{
XmString xstr ;
if( w == NULL || str == NULL ) return ;
xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
XmStringFree( xstr ) ;
MCW_expose_widget( w ) ;
return ;
}
/*-----------------------------------------------------------------------*/
void MCW_widget_geom( Widget w, int *wout, int *hout, int *xout, int *yout )
{
Dimension nx , ny ; /* don't try to make these ints! */
Position xx , yy ;
if( w == NULL ) return ;
if( XtIsRealized(w) ){
XtVaGetValues( w , XmNwidth , &nx , XmNheight , &ny ,
XmNx , &xx , XmNy , &yy , NULL ) ;
} else {
XtWidgetGeometry wg ;
(void) XtQueryGeometry( w , NULL , &wg ) ; /* works! */
nx = wg.width ; ny = wg.height ;
xx = wg.x ; yy = wg.y ;
}
#define ASSIF(p,v) if( p!= NULL ) *p = v
ASSIF(wout,nx) ; ASSIF(hout,ny) ;
ASSIF(xout,xx) ; ASSIF(yout,yy) ;
return ;
}
/*--------------------------------------------------------------------------*/
void MCW_discard_events( Widget w , int ev_mask )
{
XEvent evjunk ;
if( w == NULL || XtWindow(w) == (Window) NULL ) return ;
XSync( XtDisplay(w) , False ) ;
while( XCheckWindowEvent( XtDisplay(w), XtWindow(w) , ev_mask , &evjunk ) ) ;
return ;
}
/*--------------------------------------------------------------------------*/
void MCW_discard_events_all( Widget w , int ev_mask )
{
XEvent evjunk ;
if( w == NULL || XtWindow(w) == (Window) NULL ) return ;
XSync( XtDisplay(w) , False ) ;
while( XCheckMaskEvent( XtDisplay(w), ev_mask , &evjunk ) ) ;
return ;
}
/*--------------------------------------------------------------------------*/
char * MCW_hotcolor(Widget w)
{
static char *redcolor = NULL ;
if( redcolor == NULL ){
char *xdef = RWC_getname( (w!=NULL) ? XtDisplay(w) : NULL, "hotcolor" ) ;
redcolor = (xdef != NULL) ? (xdef) : ("red4") ;
}
return redcolor ;
}
/*--------------------------------------------------------------------------
24 Apr 2001: manage array of widgets, some of which may be NULL
----------------------------------------------------------------------------*/
void MCW_manage_widgets( Widget * war , int nar )
{
int ii ;
if( war == NULL ) return ;
for( ii=0 ; ii < nar ; ii++ )
if( war[ii] != (Widget) 0 ) XtManageChild( war[ii] ) ;
return ;
}
void MCW_unmanage_widgets( Widget * war , int nar )
{
int ii ;
if( war == NULL ) return ;
for( ii=0 ; ii < nar ; ii++ )
if( war[ii] != (Widget) 0 ) XtUnmanageChild( war[ii] ) ;
return ;
}
/*--------------------------------------------------------------------------*/
#define TIG 25
Widget MCW_action_area( Widget parent, MCW_action_item * action, int num_act )
{
Widget act_area , ww ;
int ii ;
act_area = XtVaCreateWidget( "action_area" , xmFormWidgetClass , parent ,
XmNfractionBase , TIG*num_act - 1,
XmNinitialResourcesPersistent , False ,
NULL ) ;
for( ii=0 ; ii < num_act ; ii++ ){
ww = XtVaCreateManagedWidget(
action[ii].label , xmPushButtonWidgetClass , act_area ,
XmNleftAttachment ,
(ii) ? XmATTACH_POSITION : XmATTACH_FORM ,
XmNleftPosition , ii*TIG ,
XmNtopAttachment , XmATTACH_FORM ,
XmNbottomAttachment , XmATTACH_FORM ,
XmNrightAttachment ,
(ii==num_act-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
XmNrightPosition , ii*TIG + (TIG-1) ,
XmNrecomputeSize , False ,
XmNtraversalOn , True ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
XtAddCallback( ww , XmNactivateCallback ,
action[ii].func_CB , action[ii].data ) ;
action[ii].data = (XtPointer) ww ; /* Feb 1998: save widget */
if( action[ii].help_text != NULL )
MCW_register_help( ww , action[ii].help_text ) ;
if( action[ii].hint_text != NULL )
MCW_register_hint( ww , action[ii].hint_text ) ;
if( action[ii].make_red > 0 ) /* for some fun */
MCW_set_widget_bg( ww , MCW_hotcolor(ww) , 0 ) ;
else if( action[ii].make_red < 0 ) /* for no fun at all */
XtSetSensitive( ww , False ) ;
}
XtManageChild( act_area ) ;
return act_area ;
}
/*------------------------------------------------------------------
Popup a window with a message; return the Widget.
The message can be of two types, signified by the 3rd argument:
msg_type = MCW_CALLER_KILL means the caller has to kill the
widget for the window to go away.
= MCW_USER_KILL means that the user can click in
the widget to kill it.
msg_type may also be OR-ed with MCW_TIMER_KILL to have the
message automatically killed after 30 seconds.
--------------------------------------------------------------------*/
Widget MCW_popup_message( Widget wparent , char *msg , int msg_type )
{
Widget wmsg , wlab ;
int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr ;
Screen *scr ;
XEvent ev ;
ENTRY("MCW_popup_message") ;
if( ! wparent || ! XtIsRealized( wparent ) ||
msg == NULL || strlen(msg) == 0 ) RETURN(NULL) ;
/* set position for message box based on parent and screen geometry */
MCW_widget_geom( wparent , &wx,&hy,&xx,&yy ) ; /* geometry of parent */
#if 1
{ Position xroot , yroot ;
XtTranslateCoords( wparent, 0,0, &xroot,&yroot ) ; /* root coords */
xr = (int) xroot ; yr = (int) yroot ;
}
#else
xr = xx ; yr = yy ; /* the old code, essentially */
#endif
scr = XtScreen( wparent ) ;
scr_width = WidthOfScreen( scr ) ;
scr_height = HeightOfScreen( scr ) ;
xp = xx+8 ; xpr = xr+8 ;
if( xpr+50 > scr_width ){ xp -= 100 ; xpr -= 100 ; } /* too right */
else if( xpr+10 < 0 ) { xpr = xp = 1 ; } /* too left */
yp = yy+hy+8 ; ypr = yr+hy+8 ;
if( ypr+50 > scr_height ){ yp = yy-8 ; ypr = yr-100 ;} /* too down */
else if( ypr+10 < 0 ) { ypr = yp = 1 ; } /* too up */
/* create a popup shell with a label */
wmsg = XtVaCreatePopupShell(
"help" , xmDialogShellWidgetClass , wparent ,
XmNx , xpr ,
XmNy , ypr ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
if( MCW_isitmwm( wparent ) ){
XtVaSetValues( wmsg ,
XmNmwmDecorations , MWM_DECOR_BORDER ,
XmNmwmFunctions , MWM_FUNC_MOVE ,
NULL ) ;
}
switch( msg_type & (MCW_CALLER_KILL | MCW_USER_KILL) ){
case MCW_CALLER_KILL:
wlab = XtVaCreateManagedWidget(
"help" , xmLabelWidgetClass , wmsg ,
XtVaTypedArg,XmNlabelString,XmRString,msg,strlen(msg)+1,
XmNalignment , XmALIGNMENT_BEGINNING ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
break ;
default:
case MCW_USER_KILL:{
static int first=1 ; char *mmsg = msg ; /* 'first' stuff */
if( first ){ /* on 06 Apr 2004 */
if( !AFNI_noenv("AFNI_CLICK_MESSAGE") ){
mmsg = (char *) malloc(strlen(msg)+99) ;
strcpy(mmsg,msg) ;
strcat(mmsg,"\n [---------------] "
"\n [ Click in Text ] "
"\n [ to Pop Down!! ]\n" ) ;
}
}
wlab = XtVaCreateManagedWidget(
"help" , xmPushButtonWidgetClass , wmsg ,
XtVaTypedArg,XmNlabelString,XmRString,mmsg,strlen(msg)+1,
XmNalignment , XmALIGNMENT_BEGINNING ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
if( mmsg != msg ){ free((void *)mmsg); first = 0; }
XtAddCallback( wlab , XmNactivateCallback , MCW_message_CB , NULL ) ;
}
break ;
}
SAVEUNDERIZE(wmsg) ; /* 27 Feb 2001 */
XtPopup( wmsg , XtGrabNone ) ; RWC_sleep(1);
/* now wait until the label is exposed, and make sure it appears;
the reason for this stuff is that this routine is likely to be
called by a long computation that won't return control to Xt */
WAIT_for_window(wlab) ;
XSync( XtDisplay(wlab) , False ) ;
#if 0
XMaskEvent( XtDisplay(wlab) , ExposureMask , &ev ) ;/* wait for expose */
#else
XWindowEvent( XtDisplay(wlab) , XtWindow(wlab) , ExposureMask , &ev ) ;
#endif
XPutBackEvent( XtDisplay(wlab) , &ev ) ; /* put expose back */
XSync( XtDisplay(wlab) , False ) ;
XmUpdateDisplay( wlab ) ; /* show it for sure */
/* now add the timer kill, if wanted */
#define ALLOW_TIMER_KILL
#ifdef ALLOW_TIMER_KILL
if( (msg_type & MCW_TIMER_KILL) != 0 ){
XtIntervalId tid ;
tid = XtAppAddTimeOut( XtWidgetToApplicationContext( wmsg ) ,
33333 , MCW_message_timer_CB , wmsg ) ;
XtVaSetValues( wlab , XmNuserData , tid , NULL );/* put tid on wlab; */
} else { /* shells don't */
XtVaSetValues( wlab , XmNuserData , 0 , NULL ) ; /* have XmNuserData */
}
#endif
RWC_visibilize(wmsg) ; /* 27 Sep 2000 */
NORMAL_cursorize(wmsg) ;
RETURN(wmsg) ;
}
/*-------------------------------------------------------------------------
Alter the text in the popup message - 10 Jul 2001
---------------------------------------------------------------------------*/
void MCW_message_alter( Widget wmsg , char *msg )
{
Widget wlab ;
Widget *children=NULL ;
int num_children=0 ;
XmString xstr ;
ENTRY("MCW_message_alter") ;
if( wmsg == NULL || msg == NULL || msg[0] == '\0' ) EXRETURN ;
XtVaGetValues( wmsg , XmNchildren , &children ,
XmNnumChildren , &num_children , NULL ) ;
if( num_children < 1 ) EXRETURN ;
MCW_set_widget_label( children[0] , msg ) ;
EXRETURN ;
}
/*-------------------------------------------------------------------------
callback when the popup message created above is a PushButton
(Note that w is the PushButton widget, so its parent is to be killed)
---------------------------------------------------------------------------*/
void MCW_message_CB( Widget w , XtPointer cd , XtPointer cbs )
{
#ifdef ALLOW_TIMER_KILL
XtIntervalId tid ;
XtVaGetValues( w , XmNuserData , &tid , NULL ) ; /* get timer id */
XtDestroyWidget( XtParent(w) ) ;
if( tid > 0 ) XtRemoveTimeOut( tid ) ; /* if a timer exists, kill it */
#else
XtDestroyWidget( XtParent(w) ) ;
#endif
}
/*----------------------------------------------------*/
/*--- callback when timer expires on popup message ---*/
/*----------------------------------------------------*/
void MCW_message_timer_CB( XtPointer client_data , XtIntervalId * id )
{
XtDestroyWidget( (Widget) client_data ) ;
}
/*------------------------------------------------------------------
routines to change Widget cursors
cur argument: = 0 --> None
> 0 --> is a Cursor already allocated
< 0 --> -cur is a cursorfont index
--------------------------------------------------------------------*/
void MCW_set_widget_cursor( Widget w , int cur )
{
MCW_alter_widget_cursor( w , cur , NULL,NULL ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_alter_widget_cursor( Widget w, int cur, char * fgname, char * bgname )
{
XColor fg , bg ;
Cursor ccc ;
Colormap cmap ;
Display * dis ;
Boolean good ;
int ii ;
static Cursor cur_font[XC_num_glyphs] ;
static Boolean first = True ;
if( AFNI_yesenv("AFNI_DISABLE_CURSORS") ) return ; /* 21 Mar 2004 */
if( first ){
for( ii=0 ; ii < XC_num_glyphs ; ii++ ) cur_font[ii] = None ;
first = False ;
}
if( !XtIsRealized(w) || XtWindow(w) == (Window) NULL ) return ;
dis = XtDisplay(w) ;
if( cur == 0 || cur <= -XC_num_glyphs ){ /* define cursor */
ccc = None ;
} else if( cur > 0 ){
ccc = cur ;
} else {
ii = -cur ;
if( cur_font[ii] == None ) cur_font[ii] = XCreateFontCursor( dis , ii ) ;
ccc = cur_font[ii] ;
}
XDefineCursor( dis , XtWindow(w) , ccc ) ;
if( fgname != NULL && bgname != NULL ){
cmap = DefaultColormap( dis , DefaultScreen(dis) ) ;
good = XParseColor( dis , cmap , fgname , &fg )
&& XParseColor( dis , cmap , bgname , &bg ) ;
if( good ) XRecolorCursor( dis , ccc , &fg , &bg ) ;
}
return ;
}
/*------------------------------------------------------------------------
widget help routines (for "button help" buttons)
--------------------------------------------------------------------------*/
void MCW_click_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
{
Widget whelp ;
XmAnyCallbackStruct cbs ;
XEvent ev ;
static Cursor cur = 0 ;
Display * dis = XtDisplay(w) ;
if( cur == 0 ){
cur = XCreateFontCursor( dis , XC_hand2 ) ;
}
#ifdef USE_LOCATE /* old version */
whelp = XmTrackingLocate( w , cur , False ) ; /* wait for user to click */
#else
cbs.event = &ev ;
whelp = XmTrackingEvent( w , cur , False , cbs.event ) ;
#endif
if( whelp != NULL &&
XtHasCallbacks(whelp,XmNhelpCallback) == XtCallbackHasSome ){
cbs.reason = XmCR_HELP ;
XtCallCallbacks( whelp , XmNhelpCallback , &cbs ) ; /* call for help */
} else {
XBell( dis , 100 ) ;
}
return ;
}
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
static int disable_helps = 0 ; /* 02 Aug 1999 */
void MCW_disable_help(void){ disable_helps = 1 ; }
void MCW_enable_help (void){ disable_helps = 0 ; }
#ifdef DONT_USE_HINTS
void MCW_register_hint( Widget w , char * msg ) { return ; }
void MCW_reghint_children( Widget w , char * msg ) { return ; }
void MCW_hint_toggle(void){ return ; }
void MCW_unregister_hint( Widget w ){ return ; }
#else
#include "LiteClue.h"
static Widget liteClue = NULL ;
static int clueless = -1 ;
void MCW_hint_toggle(void)
{
#define PBIG 999999
int period ;
char * pdef ;
if( liteClue == NULL ) return ;
XtVaGetValues( liteClue , XgcNwaitPeriod , &period , NULL ) ;
if( period < PBIG ){
period = PBIG ;
} else {
#if 0
pdef = XGetDefault(XtDisplay(liteClue),"AFNI","waitperiod") ;
#else
pdef = RWC_getname(XtDisplay(liteClue),"waitperiod") ;
#endif
if( pdef == NULL ){
period = 1066 ;
} else {
period = strtol( pdef , NULL , 10 ) ;
if( period < 100 ) period = 1066 ;
}
}
XtVaSetValues( liteClue , XgcNwaitPeriod , period , NULL ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_unregister_hint( Widget w ) /* 11 Jul 2001 */
{
if( liteClue != NULL && w != NULL )
XcgLiteClueDeleteWidget( liteClue , w ) ;
return ;
}
/*--------------------------------------------------------------------*/
#define RES_CONVERT( res_name, res_value) \
XtVaTypedArg, (res_name), XmRString, (res_value), strlen(res_value) + 1
void MCW_register_hint( Widget w , char * msg )
{
if( disable_helps ) return ;
if( w == NULL || msg == NULL || clueless == 1 || !XtIsWidget(w) ) return ;
if( clueless == -1 ){
char * hh = my_getenv("AFNI_HINTS") ;
if( hh != NULL && ( strncmp(hh,"KILL",4)==0 ||
strncmp(hh,"kill",4)==0 ||
strncmp(hh,"Kill",4)==0 ) ){
clueless = 1 ;
return ;
} else {
clueless = 0 ;
}
}
/*-- Do we have to make the hint-displaying widget? --*/
if( liteClue == NULL ){
Widget wpar = w ;
char * cfont ;
while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ; /* find top */
cfont = XGetDefault(XtDisplay(wpar),"AFNI","cluefont") ;
if( cfont != NULL ){
liteClue = XtVaCreatePopupShell( "help", xcgLiteClueWidgetClass, wpar,
RES_CONVERT(XtNfontSet,cfont) ,
NULL);
} else {
liteClue = XtVaCreatePopupShell( "help", xcgLiteClueWidgetClass, wpar,
NULL);
}
if( liteClue == NULL ) return ;
XtVaSetValues( liteClue , XmNsaveUnder , True , NULL ) ; /* 22 Jan 1999 */
}
/*-- attach the hint to the widget, if it is a widget --*/
if( XtIsWidget(w) ) XcgLiteClueAddWidget( liteClue, w, msg, 0,0 ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_reghint_children( Widget w , char * msg )
{
Widget * children=NULL ;
int num_children=0 , ic ;
if( disable_helps ) return ;
if( w == NULL || msg == NULL || clueless == 1 || !XtIsWidget(w) ) return ;
XtVaGetValues( w , XmNchildren , &children ,
XmNnumChildren , &num_children , NULL ) ;
MCW_register_hint( w , msg ) ;
if( children == NULL || num_children == 0 ) return ;
for( ic=0 ; ic < num_children ; ic++ )
MCW_register_hint( children[ic] , msg ) ;
return ;
}
#endif /* DONT_USE_HINTS */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
void MCW_unregister_help( Widget w ) /* 24 Apr 2001 */
{
XtCallbackList hc=NULL ;
XtVaGetValues( w , XmNhelpCallback , &hc , NULL ) ;
if( hc != NULL )
XtRemoveCallbacks( w , XmNhelpCallback , hc ) ;
}
/*------------------------------------------------------------------------*/
void MCW_register_help( Widget w , char * msg )
{
if( disable_helps ) return ;
if( w == NULL || msg == NULL ) return ;
XtAddCallback( w , XmNhelpCallback , MCW_help_CB , msg ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_reghelp_children( Widget w , char * msg )
{
Widget * children ;
int num_children , ic ;
if( disable_helps ) return ;
if( w == NULL || msg == NULL ) return ;
XtVaGetValues( w , XmNchildren , &children ,
XmNnumChildren , &num_children , NULL ) ;
XtAddCallback( w , XmNhelpCallback , MCW_help_CB , msg ) ;
for( ic=0 ; ic < num_children ; ic++ )
XtAddCallback( children[ic] , XmNhelpCallback , MCW_help_CB , msg ) ;
return ;
}
/*------------------------------------------------------------------------*/
void MCW_help_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
char * msg = (char *) client_data ;
static Widget wpop = NULL , wbut ;
Position xx,yy ;
XmString xstr ;
int ww,hh , sw,sh ;
char * def ;
#ifndef USE_LOCATE
XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) call_data ;
#endif
if( w == NULL ){
if( wpop != NULL ) XtUnmapWidget(wpop) ;
return ;
}
if( wpop == NULL || ! XtIsWidget(wpop) ){
Widget wpar = w ;
while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ; /* find top */
wpop = XtVaCreatePopupShell(
"help" , xmDialogShellWidgetClass , wpar ,
XmNmappedWhenManaged , False ,
XmNallowShellResize , True ,
XmNdeleteResponse , XmDO_NOTHING ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
#if 0
def = XGetDefault(XtDisplay(wpar),"AFNI","helpborder") ;
#else
def = RWC_getname(XtDisplay(wpar),"helpborder") ;
#endif
if( def != NULL && strcmp(def,"False") == 0 ){
XtVaSetValues( wpop ,
XmNoverrideRedirect , True ,
NULL ) ;
} else if( MCW_isitmwm(wpar) ){
XtVaSetValues( wpop ,
XmNmwmDecorations , MWM_DECOR_BORDER ,
XmNmwmFunctions , MWM_FUNC_MOVE ,
NULL ) ;
}
wbut = XtVaCreateManagedWidget(
"help" , xmPushButtonWidgetClass , wpop ,
XmNalignment , XmALIGNMENT_BEGINNING ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
XtAddCallback( wbut , XmNactivateCallback , MCW_unhelp_CB , wpop ) ;
XmUpdateDisplay( wpar ) ;
RWC_XtPopdown( wpop ) ;
XmAddWMProtocolCallback(
wpop ,
XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
MCW_unhelp_CB , wpop ) ;
if( ! XtIsRealized(wpar) ) return ;
}
if( msg == NULL || strlen(msg) == 0 ) return ; /* no popup if no message */
xstr = XmStringCreateLtoR( msg , XmFONTLIST_DEFAULT_TAG ) ;
XtVaSetValues( wbut , XmNlabelString , xstr , NULL ) ;
XmStringFree( xstr ) ;
#ifndef USE_LOCATE
if( cbs != NULL && cbs->event != NULL
&& cbs->event->type == ButtonRelease ){
XButtonEvent * xev = (XButtonEvent *) cbs->event ;
xx = xev->x_root ;
yy = xev->y_root ;
} else
#endif
XtTranslateCoords( w , 15,15 , &xx , &yy ) ; /* coordinates on root */
MCW_widget_geom( wpop , &ww,&hh , NULL,NULL ) ; /* widget width and height */
sw = WidthOfScreen (XtScreen(wpop)) ; /* screen width and height */
sh = HeightOfScreen(XtScreen(wpop)) ;
if( xx+ww+3 >= sw && ww <= sw ) xx = sw-ww ; /* make sure is on screen */
if( yy+hh+3 >= sh && hh <= sh ) yy = sh-hh ;
XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ;
XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
RWC_visibilize(wpop) ; /* 27 Sep 2000 */
NORMAL_cursorize(wpop) ;
return ;
}
/*---------------------------------------------------------------------*/
void MCW_unhelp_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
Widget wpop = (Widget) client_data ;
RWC_XtPopdown(wpop) ;
return ;
}
/*---------------------------------------------------------------------*/
int MCW_filetype( char * fname )
{
FILE * fff ;
if( fname == NULL || strlen(fname) == 0 ) return MCW_nofile ;
fff = fopen( fname , "r+" ) ; /* open for read-update */
fclose( fff ) ;
if( fff != NULL ) return MCW_readwrite ;
fff = fopen( fname , "r" ) ; /* open for read-only */
fclose(fff) ;
if( fff != NULL ) return MCW_readonly ;
return MCW_nofile ;
}
/*-------------------------------------------------------------------*/
#if 0
Boolean MCW_isitmwm( Widget w )
{
Widget wsh ;
if( w == NULL || ! XtIsWidget(w) ) return False ;
wsh = w ;
while( ! XtIsShell(wsh) ){
wsh = XtParent(wsh) ;
if( wsh == NULL ) return False ;
}
#if 1
return XmIsMotifWMRunning(wsh) ;
#else
{ int immm = -73 ;
XtVaGetValues( wsh , XmNmwmDecorations , &immm , NULL ) ;
if( immm == -73 ) return False ;
else return True ;
}
#endif
}
#endif
/*------------------------------------------------------------------
Popup a scale that will serve as a progress meter.
The meter is set initially to 0, and can later be set to any
value from 0 to 100 using MCW_set_meter().
wparent is the widget the meter will be attached to
position is one of
METER_TOP = meter on top of wparent, default width
METER_TOP_WIDE = meter on top of parent, width of parent
METER_BOT = similar, but on bottom of parent
METER_BOT_WIDE
--------------------------------------------------------------------*/
#define METER_HEIGHT 10
#define METER_WIDTH 200
Widget MCW_popup_meter( Widget wparent , int position )
{
Widget wmsg , wscal ;
int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , wid ;
Screen * scr ;
XEvent ev ;
Position xroot , yroot ;
ENTRY("MCW_popup_meter") ;
if( wparent == NULL || ! XtIsRealized( wparent ) ) RETURN(NULL) ;
/* set position parent and screen geometry */
MCW_widget_geom( wparent , &wx,&hy,&xx,&yy ) ; /* geometry of parent */
XtTranslateCoords( wparent, 0,0, &xroot,&yroot ) ; /* root coords of parent */
xr = (int) xroot ; yr = (int) yroot ;
scr = XtScreen( wparent ) ;
scr_width = WidthOfScreen( scr ) ;
scr_height = HeightOfScreen( scr ) ;
switch( position ){
default:
case METER_TOP:
case METER_TOP_WIDE:
xpr = xr ;
ypr = yr - METER_HEIGHT-2 ;
wid = (position==METER_TOP_WIDE) ? wx : METER_WIDTH ;
if( ypr < 0 ) ypr = yr+hy+1 ;
break ;
case METER_BOT:
case METER_BOT_WIDE:
xpr = xr ;
ypr = yr+hy+1 ;
wid = (position==METER_BOT_WIDE) ? wx : METER_WIDTH ;
if( ypr+METER_HEIGHT > scr_height ) ypr = yr - METER_HEIGHT-2 ;
break ;
}
/* create a popup shell with a scale */
wmsg = XtVaCreatePopupShell(
"menu" , xmDialogShellWidgetClass , wparent ,
XmNx , xpr ,
XmNy , ypr ,
XmNborderWidth , 0 ,
XmNoverrideRedirect , True ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
#if 0
if( MCW_isitmwm( wparent ) ){
XtVaSetValues( wmsg ,
XmNmwmDecorations , MWM_DECOR_BORDER ,
XmNmwmFunctions , MWM_FUNC_MOVE ,
NULL ) ;
}
#endif
wscal = XtVaCreateManagedWidget(
"menu" , xmScaleWidgetClass , wmsg ,
XmNminimum , 0 ,
XmNmaximum , 100 ,
XmNshowValue , False ,
XmNvalue , 0 ,
XmNorientation , XmHORIZONTAL ,
XmNscaleWidth , wid ,
XmNscaleHeight , METER_HEIGHT ,
XmNborderWidth , 0 ,
XmNhighlightThickness , 0 ,
XmNshadowThickness , 0 ,
XmNtraversalOn , True ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
XtPopup( wmsg , XtGrabNone ) ; RWC_sleep(1);
RETURN(wscal) ;
}
/*--------------------------------------------------------------------*/
void MCW_popdown_meter( Widget wscal )
{
if( wscal == NULL ) return ;
XtDestroyWidget( XtParent(wscal) ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_set_meter( Widget wscal , int percent )
{
int val , old ;
#undef NCOL
#define NCOL 30
#ifdef NCOL
static int icol=0 ;
static char *cname[] = {
"#0000ff", "#3300ff", "#6600ff", "#9900ff", "#cc00ff",
"#ff00ff", "#ff00cc", "#ff0099", "#ff0066", "#ff0033",
"#ff0000", "#ff3300", "#ff6600", "#ff9900", "#ffcc00",
"#ffff00", "#ccff00", "#99ff00", "#66ff00", "#33ff00",
"#00ff00", "#00ff33", "#00ff66", "#00ff99", "#00ffcc",
"#00ffff", "#00ccff", "#0099ff", "#0066ff", "#0033ff"
} ;
#endif
val = percent ;
if( wscal == NULL || val < 0 || val > 100 ) return ;
XmScaleGetValue( wscal , &old ) ; if( val == old ) return ;
XtVaSetValues( wscal , XmNvalue , val , NULL ) ;
#ifdef NCOL
{ Widget ws = XtNameToWidget(wscal,"Scrollbar") ;
if( ws != NULL )
XtVaSetValues( ws ,
XtVaTypedArg , XmNtroughColor , XmRString ,
cname[icol] , strlen(cname[icol])+1 ,
NULL ) ;
icol = (icol+1) % NCOL ;
}
#endif
XmUpdateDisplay(wscal) ;
return ;
}
/*------------------------------------------------------------------------*/
#if 0
static void MCW_textwin_timer_CB( XtPointer client_data , XtIntervalId *id )
{
Widget ws = (Widget)client_data ;
XtVaSetValues( ws , XmNincrement , 1 ,
XmNpageIncrement , 1 ,
XmNmaximum , 100 , NULL ) ;
}
#endif
/*-----------------------------------------------------------------------*/
#define RONLY_NUM 1
#define EDIT_NUM 2
static MCW_action_item TWIN_act[] = {
{ "Quit" , MCW_textwin_CB , NULL , NULL , "Close window" , 0 } ,
{ "Set" , MCW_textwin_CB , NULL , NULL , "Apply choice and close window" , 0 }
} ;
MCW_textwin * new_MCW_textwin( Widget wpar, char * msg, int type )
{
return new_MCW_textwin_2001( wpar,msg,type , NULL,NULL ) ;
}
/*-----------------------------------------------------------------------
Modified 10 Jul 2001 to include killing callback
-------------------------------------------------------------------------*/
MCW_textwin * new_MCW_textwin_2001( Widget wpar, char *msg, int type,
void_func *kill_func , XtPointer kill_data )
{
MCW_textwin *tw ;
int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , ii,nact ;
int swid , shi ;
Position xroot , yroot ;
Screen *scr ;
Boolean editable , cursorable ;
Arg wa[64] ; int na ; Widget ws ;
ENTRY("new_MCW_textwin_2001") ;
/*-- sanity check --*/
if( ! XtIsRealized(wpar) ) RETURN(NULL) ;
/* set position based on parent and screen geometry */
MCW_widget_geom( wpar , &wx,&hy,&xx,&yy ) ; /* geometry of parent */
XtTranslateCoords( wpar, 0,0, &xroot,&yroot ) ; /* root coords */
xr = (int) xroot ; yr = (int) yroot ;
scr = XtScreen(wpar) ;
scr_width = WidthOfScreen(scr) ;
scr_height = HeightOfScreen(scr) ;
xp = xx+8 ; xpr = xr+8 ;
if( xpr+50 > scr_width ){ xp -= 100 ; xpr -= 100 ; } /* too right */
else if( xpr+10 < 0 ) { xpr = xp = 1 ; } /* too left */
yp = yy+hy+8 ; ypr = yr+hy+8 ;
if( ypr+50 > scr_height ){ yp = yy-8 ; ypr = yr-100 ;} /* too down */
else if( ypr+10 < 0 ) { ypr = yp = 1 ; } /* too up */
/* create a popup shell */
tw = myXtNew(MCW_textwin) ;
tw->kill_func = kill_func ; /* 10 Jul 2001 */
tw->kill_data = kill_data ;
tw->wshell = XtVaCreatePopupShell(
"menu" , xmDialogShellWidgetClass , wpar ,
XmNx , xpr ,
XmNy , ypr ,
XmNborderWidth , 0 ,
XmNborderColor , 0 ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
XmAddWMProtocolCallback(
tw->wshell ,
XmInternAtom( XtDisplay(tw->wshell) , "WM_DELETE_WINDOW" , False ) ,
MCW_textwinkill_CB , (XtPointer) tw ) ;
/* create a form to hold everything else */
tw->wtop = XtVaCreateWidget(
"menu" , xmFormWidgetClass , tw->wshell ,
XmNborderWidth , 0 ,
XmNborderColor , 0 ,
XmNtraversalOn , True ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
/* create action area */
editable = (Boolean) (type == TEXT_EDITABLE) ;
cursorable = True ; /* 26 Feb 2007 */
nact = (editable) ? EDIT_NUM : RONLY_NUM ;
for( ii=0 ; ii < nact ; ii++ ){
TWIN_act[ii].data = (XtPointer) tw ;
TWIN_act[ii].make_red = 0 ;
}
TWIN_act[nact-1].make_red = 1 ;
tw->wactar = MCW_action_area( tw->wtop , TWIN_act , nact ) ;
/* create text area */
tw->wscroll = XtVaCreateManagedWidget(
"menu" , xmScrolledWindowWidgetClass , tw->wtop ,
XmNscrollingPolicy , XmAUTOMATIC ,
XmNvisualPolicy , XmVARIABLE ,
XmNscrollBarDisplayPolicy , XmAS_NEEDED ,
XmNleftAttachment , XmATTACH_FORM ,
XmNrightAttachment , XmATTACH_FORM ,
XmNbottomAttachment, XmATTACH_FORM ,
XmNtopAttachment , XmATTACH_WIDGET ,
XmNtopWidget , tw->wactar ,
XmNtopOffset , 7 ,
XmNinitialResourcesPersistent , False ,
NULL ) ;
XtVaSetValues( tw->wactar ,
XmNleftAttachment , XmATTACH_FORM ,
XmNrightAttachment, XmATTACH_FORM ,
XmNtopAttachment , XmATTACH_FORM ,
XmNtopOffset , 7 ,
NULL ) ;
tw->wtext = XtVaCreateManagedWidget(
"menu" , xmTextWidgetClass , tw->wscroll ,
XmNeditMode , XmMULTI_LINE_EDIT ,
XmNautoShowCursorPosition , cursorable ,
XmNeditable , editable ,
XmNcursorPositionVisible , cursorable ,
NULL ) ;
if( msg == NULL ) msg = "\0" ; /* 27 Sep 2000 */
if( msg != NULL ){
int cmax = 20 , ll , nlin ;
char *cpt , *cold , cbuf[128] ;
XmString xstr ;
XmFontList xflist ;
XtVaSetValues( tw->wtext , XmNvalue , msg , NULL ) ;
XtVaGetValues( tw->wtext , XmNfontList , &xflist , NULL ) ;
cmax = 20 ; nlin = 1 ;
for( cpt=msg,cold=msg ; *cpt != '\0' ; cpt++ ){
if( *cpt == '\n' ){
ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
cold = cpt ; nlin++ ;
}
}
ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
if( cmax > 100 ) cmax = 100 ;
cmax +=3 ;
for( ll=0 ; ll < cmax ; ll++ ) cbuf[ll] = 'x' ;
cbuf[cmax] = '\0' ;
xstr = XmStringCreateLtoR( cbuf , XmFONTLIST_DEFAULT_TAG ) ;
swid = XmStringWidth ( xflist , xstr ) + 44 ;
shi = XmStringHeight( xflist , xstr ) * nlin + 66 ;
XmStringFree( xstr ) ;
cmax = WidthOfScreen(XtScreen(wpar)) - 128 ;
if( swid > cmax ) swid = cmax ;
cmax = HeightOfScreen(XtScreen(wpar)) - 128 ;
if( shi > cmax ) shi = cmax ;
} else {
swid = shi = 100 ;
}
XtManageChild( tw->wtop ) ;
XtVaSetValues( tw->wshell , XmNwidth,swid , XmNheight,shi , NULL ) ;
XtPopup( tw->wshell , XtGrabNone ) ; RWC_sleep(1);
RWC_visibilize_widget( tw->wshell ) ; /* 09 Nov 1999 */
RWC_xineramize( XtDisplay(tw->wshell) ,
xpr,ypr,swid,shi , &xpr,&ypr ); /* 27 Sep 2000 */
XtVaSetValues( tw->wshell, XmNx,xpr , XmNy,ypr , NULL ) ;
tw->shell_width = swid ; tw->shell_height = shi ; /* 10 Jul 2001 */
NORMAL_cursorize( tw->wshell ) ;
ws = XtNameToWidget(tw->wscroll,"VertScrollBar") ;
if( ws != NULL ){
#ifdef DARWIN
XtVaSetValues( ws , XmNshowArrows , XmMIN_SIDE , NULL ) ;
#endif
(void)XmProcessTraversal( ws , XmTRAVERSE_CURRENT ) ;
#if 0
(void)XtAppAddTimeOut( XtWidgetToApplicationContext(ws) ,
66 , MCW_textwin_timer_CB , ws ) ;
#endif
}
#ifdef DARWIN
ws = XtNameToWidget(tw->wscroll,"HorScrollBar") ;
if( ws != NULL )
XtVaSetValues( ws , XmNshowArrows , XmMIN_SIDE , NULL ) ;
#endif
RETURN(tw) ;
}
/*--------------------------------------------------------------------*/
void MCW_textwin_alter( MCW_textwin * tw , char * mmm ) /* 10 Jul 2001 */
{
int swid , shi ;
char * msg = mmm ;
int cmax = 20 , ll , nlin ;
char * cpt , *cold , cbuf[128] ;
XmString xstr ;
XmFontList xflist ;
ENTRY("MCW_textwin_alter") ;
if( tw == NULL ) EXRETURN ; /* bad */
if( msg == NULL ) msg = " " ; /* don't let user be so stupid */
#if 0
/*-- compute size of text window with new message in it --*/
XtVaGetValues( tw->wtext , XmNfontList , &xflist , NULL ) ;
/* find longest line in msg */
cmax = 20 ; nlin = 1 ;
for( cpt=msg,cold=msg ; *cpt != '\0' ; cpt++ ){
if( *cpt == '\n' ){
ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
cold = cpt ; nlin++ ;
}
}
ll = cpt - cold - 1 ; if( cmax < ll ) cmax = ll ;
if( cmax > 100 ) cmax = 100 ;
/* fill a dummy string of that length, plus a bit */
cmax+=3 ;
for( ll=0 ; ll < cmax ; ll++ ) cbuf[ll] = 'x' ;
cbuf[cmax] = '\0' ;
/* find width, height of the dummy string */
xstr = XmStringCreateLtoR( cbuf , XmFONTLIST_DEFAULT_TAG ) ;
swid = XmStringWidth ( xflist , xstr ) + 44 ;
shi = XmStringHeight( xflist , xstr ) * nlin + 66 ;
XmStringFree( xstr ) ;
/* find width, height of screen */
cmax = WidthOfScreen(XtScreen(tw->wshell)) - 128 ;
if( swid > cmax ) swid = cmax ;
cmax = HeightOfScreen(XtScreen(tw->wshell)) - 128 ;
if( shi > cmax ) shi = cmax ;
#endif
/*-- actually set new text --*/
XtVaSetValues( tw->wtext , XmNvalue , msg , NULL ) ;
#if 1
MCW_widget_geom( tw->wtext , &swid , &shi , NULL,NULL ) ;
XtVaSetValues( tw->wshell , XmNwidth,swid+29 , XmNheight,shi+59 , NULL ) ;
tw->shell_width = swid+29 ; tw->shell_height = shi+59 ;
#endif
#if 0
/*-- maybe set new window size --*/
if( swid > tw->shell_width || shi > tw->shell_height ){
tw->shell_width = swid = MAX( swid , tw->shell_width ) ;
tw->shell_height = shi = MAX( shi , tw->shell_height ) ;
XtVaSetValues( tw->wshell , XmNwidth,swid , XmNheight,shi , NULL ) ;
}
#endif
EXRETURN ;
}
/*--------------------------------------------------------------------*/
void MCW_textwin_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
MCW_textwin * tw = (MCW_textwin *) client_data ;
char * wname = XtName(w) ;
if( client_data == NULL ) return ;
if( strcmp(wname,"Quit") == 0 ){
if( tw->kill_func != NULL )
#if 0
tw->kill_func(tw->kill_data); /* 10 Jul 2001 */
#else
AFNI_CALL_VOID_1ARG( tw->kill_func , XtPointer , tw->kill_data ) ;
#endif
XtDestroyWidget( tw->wshell ) ;
myXtFree( tw ) ;
return ;
}
XBell( XtDisplay(w) , 100 ) ;
return ;
}
/*--------------------------------------------------------------------*/
void MCW_textwinkill_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
MCW_textwin * tw = (MCW_textwin *) client_data ;
if( tw->kill_func != NULL )
#if 0
tw->kill_func(tw->kill_data); /* 10 Jul 2001 */
#else
AFNI_CALL_VOID_1ARG( tw->kill_func , XtPointer , tw->kill_data ) ;
#endif
XtDestroyWidget( tw->wshell ) ;
myXtFree( tw ) ;
return ;
}
/*-----------------------------------------------------------------------
03 Jan 1999: Check if a widget is potentially visible
-- return 0 if not, 1 if yes.
-------------------------------------------------------------------------*/
int MCW_widget_visible( Widget w )
{
Window ww ;
XWindowAttributes wa ;
if( w == (Widget) NULL ) return 0 ;
ww = XtWindow(w) ;
if( ww == (Window) NULL ) return 0 ;
XGetWindowAttributes( XtDisplay(w) , ww , &wa ) ;
return ( (wa.map_state == IsViewable) ? 1 : 0 ) ;
}
/*------------------------------------------------------------------
June 1999: routine to get string constants either from X defaults
or from Unix environment variables. Returns a pointer
to static storage -- do not free()!
--------------------------------------------------------------------*/
#include <ctype.h>
char * RWC_getname( Display * display , char * name )
{
char * cval , qqq[256] ;
int nn , ii ;
if( name == NULL || name[0] == '\0' ) return NULL ;
/* try X11 */
if( display != NULL ){
cval = XGetDefault(display,"AFNI",name) ;
if( cval != NULL ) return cval ;
}
/* try AFNI_name */
strcpy(qqq,"AFNI_") ; strcat(qqq,name) ;
cval = my_getenv(qqq) ;
if( cval != NULL ) return cval ;
/* try AFNI_NAME (uppercase it) */
strcpy(qqq,"AFNI_") ; nn = strlen(name) ;
for( ii=0 ; ii < nn && ii < 250 ; ii++ ) qqq[ii+5] = toupper(name[ii]) ;
qqq[ii+5] = '\0' ;
cval = my_getenv(qqq) ;
return cval ;
}
/*-------------------------------------------------------------------
09 Nov 1999: move a widget to make sure it is visible
---------------------------------------------------------------------*/
void RWC_visibilize_widget( Widget w )
{
Position xroot , yroot ;
int wx,hy,xx,yy , scr_width,scr_height , xo,yo ;
Screen *scr ;
ENTRY("RWC_visibilize_widget") ;
if( w == NULL || !XtIsWidget(w) ) EXRETURN ;
MCW_widget_geom( w , &wx,&hy,&xx,&yy ) ; /* geometry of widget */
scr = XtScreen( w ) ;
scr_width = WidthOfScreen( scr ) ;
scr_height = HeightOfScreen( scr ) ;
xo = xx ; yo = yy ; /* save original position */
if( xx+wx > scr_width ) xx = scr_width - wx ;
if( xx < 0 ) xx = 0 ;
if( yy+hy > scr_height ) yy = scr_height - hy ;
if( yy < 0 ) yy = 0 ;
RWC_xineramize( XtDisplay(w) , xx,yy,wx,hy , &xx,&yy ); /* 27 Sep 2000 */
if( xx != xo || yy != yo )
XtVaSetValues( w , XmNx , xx , XmNy , yy , NULL ) ;
EXRETURN ;
}
/*----------------------------------------------------------------------
A callback version of the above (for use when menus are mapped, say)
------------------------------------------------------------------------*/
static void RWC_visibilize_timeout_CB( XtPointer cd , XtIntervalId * id )
{
Widget w = (Widget) cd ;
ENTRY("RWC_visibilize_timeout_CB") ;
RWC_visibilize_widget(w) ; EXRETURN ;
}
/*--------------------------------------------------------------------*/
void RWC_visibilize_CB( Widget w , XtPointer cd , XtPointer cb )
{
Widget wpar = w ;
ENTRY("RWC_visibilize_CB") ;
if( AFNI_yesenv("AFNI_DONT_MOVE_MENUS") ) return ; /* 08 Aug 2001 */
while( !XtIsShell(wpar) ){ wpar = XtParent(w); } /* find 1st shell parent */
/* must wait for the thing to actually appear, dammit */
(void) XtAppAddTimeOut( XtWidgetToApplicationContext(wpar) ,
1 , RWC_visibilize_timeout_CB , wpar ) ;
EXRETURN ;
}
/*----------------------------------------------------------------------
Given a rectangle (xx..xx+ww,yy..yy+hh), return the new origin
(xn,yn) so that the rectangle (xn..xn+ww,yn..yn+hh) fits onto
a single Xinerama sub-screen. If the AFNI.xinerama X11 resource is
not found, then this routine uses the display size.
-- RWCox -- 27 Sep 2000
------------------------------------------------------------------------*/
#define BUF 5 /* buffer around the rectangle */
void RWC_xineramize( Display * dpy,
int xx, int yy, int ww, int hh, int *xn, int *yn )
{
static int first=1 ;
static int nxsi=0 , *xbot,*ybot,*xtop,*ytop ;
int ii , ss ;
ENTRY("RWC_xineramize") ;
if( dpy==NULL || xn==NULL || yn==NULL || ww<0 || hh<0 ) EXRETURN; /* ERROR */
/*--- first time in: check AFNI.xinerama X resource
load boundaries of sub-screens from resource ---*/
if( first ){
char * xdef , * xp ;
int nn,xorg,yorg,wide,high ;
first = 0 ; /* never again */
xdef = getenv( "AFNI_XINERAMA" ) ;
if( xdef != NULL && (xdef[0] == 'N' || xdef[0] == 'n') ){ /* skip Xinerama */
nxsi = 0 ;
STATUS("AFNI_XINERAMA is NO") ;
} else {
xdef = XGetDefault(dpy,"AFNI","xinerama") ; /* get resource */
if( xdef == NULL ) xdef = getenv("AFNI_xinerama") ; /* 27 Oct 2003 */
if( xdef != NULL ){
char *qdef = strdup(xdef) ;
for( nn=0 ; qdef[nn] != '\0' ; nn++ )
if( qdef[nn] == '_' || qdef[nn] == ':' ) qdef[nn] = ' ' ;
nn = 0 ; sscanf(qdef,"%d%n",&nxsi,&nn) ; /* number of sub-screens */
if( nn <= 0 || nxsi <= 1 ){ /* ERROR */
nxsi = 0 ;
} else {
xbot = (int *) malloc(sizeof(int)*nxsi) ; /* make arrays to */
ybot = (int *) malloc(sizeof(int)*nxsi) ; /* store sub-screen */
xtop = (int *) malloc(sizeof(int)*nxsi) ; /* coordinate ranges */
ytop = (int *) malloc(sizeof(int)*nxsi) ;
xp = qdef + nn ;
for( ii=0 ; ii < nxsi ; ii++ ){ /* scan for sub-screen info */
nn = 0 ;
sscanf(xp,"%d%d%d%d%d%n",&ss,&xorg,&yorg,&wide,&high,&nn) ;
if( nn <= 0 ) break ; /* ERROR */
xbot[ii] = xorg ; xtop[ii] = xorg+wide ;
ybot[ii] = yorg ; ytop[ii] = yorg+high ;
xp += nn ;
if(PRINT_TRACING){
char str[256] ;
sprintf(str," Screen %d: xbot=%4d ybot=%4d xtop=%4d ytop=%4d",
ii,xbot[ii],ybot[ii],xtop[ii],ytop[ii] ) ;
STATUS(str) ;
}
}
nxsi = ii ; /* in case the scan aborted */
}
}
}
/* if nothing found yet, use the display size */
if( nxsi <= 0 ){
nxsi = 1 ;
xbot = (int *) malloc(sizeof(int)*nxsi) ;
ybot = (int *) malloc(sizeof(int)*nxsi) ;
xtop = (int *) malloc(sizeof(int)*nxsi) ;
ytop = (int *) malloc(sizeof(int)*nxsi) ;
xbot[0] = ybot[0] = 0 ;
xtop[0] = WidthOfScreen(DefaultScreenOfDisplay(dpy)) ;
ytop[0] = HeightOfScreen(DefaultScreenOfDisplay(dpy)) ;
}
}
#if 0 /* doesn't occur anymore */
if( nxsi == 0 ){ *xn=xx; *yn=yy; EXRETURN; } /* not setup? change nothing */
#endif
/*--- find the Xinerama sub-screen that (xx,yy) is on (if any) ---*/
if( nxsi > 1 ){
for( ss=0 ; ss < nxsi ; ss++ ){
if( xx >= xbot[ss] && xx < xtop[ss] &&
yy >= ybot[ss] && yy < ytop[ss] ) break ;
}
} else {
ss = 0 ; /* must use #0 - what else is there? */
}
if(PRINT_TRACING){
char str[256] ;
sprintf(str,"Rect: xx=%d yy=%d ww=%d hh=%d; On ss=%d",xx,yy,ww,hh,ss); STATUS(str);
}
/*--- if not inside any screen, find one it is closest to ---*/
if( ss >= nxsi ){
int dleft,dright,dtop,dbot,dd , dmin , xdif,ydif ;
dmin = 123456789 ; ss = 0 ;
for( ii=0 ; ii < nxsi; ii++ ){
xdif = (xx < xbot[ii]) ? (xbot[ii]-xx) /* x dist to */
:(xx > xtop[ii]) ? (xx-xtop[ii]) : 0 ; /* [xbot..xtop] */
ydif = (yy < ybot[ii]) ? (ybot[ii]-yy)
:(yy > ytop[ii]) ? (yy-ytop[ii]) : 0 ;
dleft = abs(xx-xbot[ii]) + ydif ; /* L1 dist to left edge */
dright = abs(xx-xtop[ii]) + ydif ;
dbot = abs(yy-ybot[ii]) + xdif ;
dtop = abs(yy-ytop[ii]) + xdif ;
dd = dleft ; /* find smallest dist */
if( dright < dd ) dd = dright ;
if( dbot < dd ) dd = dbot ;
if( dtop < dd ) dd = dtop ;
if( dd < dmin ){ dmin = dd; ss = ii; } /* smallest so far? */
}
if(PRINT_TRACING){
char str[256] ; sprintf(str,"New ss=%d",ss) ; STATUS(str) ;
}
}
/*--- now adjust position so all of rectangle
(xx..xx+ww,yy..yy+hh) fits on that screen (if possible) ---*/
if( xx+ww+BUF >= xtop[ss] ){ xx = xtop[ss]-ww-1-2*BUF; } /* move left */
if( yy+hh+BUF >= ytop[ss] ){ yy = ytop[ss]-hh-1-2*BUF; } /* move up */
if( xx < xbot[ss]+BUF ){ xx = xbot[ss]+BUF; } /* move right */
if( yy < ybot[ss]+BUF ){ yy = ybot[ss]+BUF; } /* move down */
if(PRINT_TRACING){
char str[256] ; sprintf(str,"New xx=%d yy=%d",xx,yy) ; STATUS(str) ;
}
*xn = xx ; *yn = yy ; EXRETURN ;
}
/*----------------------------------------------------------------------
NULL out a pointer when a widget is destroyed -- 31 Jul 2001 - RWCox
------------------------------------------------------------------------*/
void RWC_destroy_nullify_CB( Widget w, XtPointer xp, XtPointer cd )
{
void ** p = (void **) xp ;
ENTRY("RWC_destroy_nullify_CB") ;
if( p != NULL ) *p = NULL ;
EXRETURN ;
}
void RWC_destroy_nullify( Widget w, void **p )
{
if( p != NULL && w != NULL )
XtAddCallback( w, XmNdestroyCallback, RWC_destroy_nullify_CB, p ) ;
return ;
}
void RWC_destroy_nullify_cancel( Widget w, void **p )
{
if( w != NULL )
XtRemoveCallback( w, XmNdestroyCallback, RWC_destroy_nullify_CB, p ) ;
return ;
}
/*---------------------------------------------------------------------------*/
static RWC_draw_rect( Display *dis, Window win, GC gc,
int x1, int y1, int x2, int y2 )
{
int xb,yb , xt,yt ;
unsigned int short w,h ;
if( x1 < x2 ){ xb=x1; xt=x2; } else { xb=x2; xt=x1; }
if( y1 < y2 ){ yb=y1; yt=y2; } else { yb=y2; yt=y1; }
w = xt-xb ; h = yt-yb ;
if( w || h )
XDrawRectangle( dis,win,gc , xb,yb,w,h ) ;
else
XDrawPoint( dis,win,gc , xb,yb ) ;
}
/*---------------------------------------------------------------------------*/
static Cursor cur = None ; /* 17 Jun 2002 */
static void RWC_drag_cursor( Display *dis )
{
XColor fg , bg ;
Colormap cmap ;
Boolean good ;
if( cur == None ){
cur = XCreateFontCursor( dis , XC_arrow ) ;
cmap = DefaultColormap( dis , DefaultScreen(dis) ) ;
good = XParseColor( dis, cmap, "yellow" , &fg )
&& XParseColor( dis, cmap, "red" , &bg ) ;
if( good ) XRecolorCursor( dis , cur , &fg , &bg ) ;
}
}
void RWC_drag_rectangle( Widget w, int x1, int y1, int *x2, int *y2 )
{
Display *dis ;
Window win , rW,cW ;
int grab , xold,yold , x,y, rx,ry , first=1 ;
unsigned int mask ; /* which buttons */
unsigned int bmask=Button1Mask|Button2Mask|Button3Mask ; /* all buttons */
XGCValues gcv;
GC myGC ;
ENTRY("RWC_drag_rectangle") ;
/** make a GC for invert drawing **/
gcv.function = GXinvert ;
myGC = XtGetGC( w , GCFunction , &gcv ) ;
/** grab the pointer (so no one else gets events from it),
and confine it to the window in question **/
dis = XtDisplay(w) ; win = XtWindow(w) ;
RWC_drag_cursor(dis) ;
grab = !XGrabPointer(dis, win, False, 0, GrabModeAsync,
GrabModeAsync, win, cur , (Time)CurrentTime);
/* grab fails => exit */
if( !grab ){ XBell(dis,100); *x2=x1; *y2=y1; EXRETURN; }
xold = x1 ; yold = y1 ; /* current location of pointer */
/** loop and find out where the pointer is (while button is down) **/
while( XQueryPointer(dis,win,&rW,&cW,&rx,&ry,&x,&y,&mask) ){
/* check if all buttons are released */
if( !(mask & bmask) ) break ; /* no button down => done! */
/* pointer now at (x,y) in the window */
/* if it has moved, redraw rectangle */
if( x != xold || y != yold ){
if( !first ) /* undraw old rectangle */
RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
/* draw new rectangle */
xold = x ; yold = y ; first = 0 ;
RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
} /* end of new (x,y) position */
} /* end of loop while button is pressed */
if( !first ) /* undraw old rectangle */
RWC_draw_rect( dis,win,myGC , x1,y1 , xold,yold ) ;
/* clean up */
XtReleaseGC( w , myGC ) ;
if (grab) XUngrabPointer(dis, (Time)CurrentTime) ;
*x2 = xold ; *y2 = yold ; /* output values */
EXRETURN ;
}
/*---------------------------------------------------------------------------*/
static RWC_draw_circle( Display *dis, Window win, GC gc, int xc, int yc, int rad )
{
int xb,yb ;
unsigned int ww ;
if( rad < 0 ) rad = 0 ;
xb = xc-rad ; yb = yc-rad ; ww = 2*rad ;
XDrawArc( dis,win,gc , xb,yb , ww,ww , 0,360*64 ) ;
}
/*---------------------------------------------------------------------------*/
void RWC_drag_circle( Widget w, int x1, int y1, int *radius )
{
Display *dis ;
Window win , rW,cW ;
int grab , xold,yold , x,y, rx,ry , first=1 , rrr=0 ;
unsigned int mask ; /* which buttons */
unsigned int bmask=Button1Mask|Button2Mask|Button3Mask ; /* all buttons */
XGCValues gcv;
GC myGC ;
ENTRY("RWC_drag_circle") ;
/** make a GC for invert drawing **/
gcv.function = GXinvert ;
myGC = XtGetGC( w , GCFunction , &gcv ) ;
/** grab the pointer (so no one else gets events from it),
and confine it to the window in question **/
dis = XtDisplay(w) ; win = XtWindow(w) ;
RWC_drag_cursor(dis) ;
grab = !XGrabPointer(dis, win, False, 0, GrabModeAsync,
GrabModeAsync, win, cur , (Time)CurrentTime);
/* grab fails => exit */
if( !grab ){ XBell(dis,100); *radius=0; EXRETURN; }
xold = x1 ; yold = y1 ; /* current location of pointer */
/** loop and find out where the pointer is (while button is down) **/
while( XQueryPointer(dis,win,&rW,&cW,&rx,&ry,&x,&y,&mask) ){
/* check if all buttons are released */
if( !(mask & bmask) ) break ; /* no button down => done! */
/* pointer now at (x,y) in the window */
/* if it has moved, redraw rectangle */
if( x != xold || y != yold ){
if( !first ) /* undraw old circle */
RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
/* draw new circle */
xold = x ; yold = y ; first = 0 ;
rrr = (int)rint(sqrt( (x-x1)*(x-x1) + (y-y1)*(y-y1) )) ;
RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
} /* end of new (x,y) position */
} /* end of loop while button is pressed */
if( !first ) /* undraw old circle */
RWC_draw_circle( dis,win,myGC , x1,y1 , rrr ) ;
/* clean up */
XtReleaseGC( w , myGC ) ;
if (grab) XUngrabPointer(dis, (Time)CurrentTime) ;
*radius = rrr ;
EXRETURN ;
}
/*-------------------------------------------------------------------*/
/*! Sleep a given # of milliseconds (uses the Unix select routine).
---------------------------------------------------------------------*/
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void RWC_sleep( int msec )
{
struct timeval tv ;
if( msec <= 0 ) return ; /* can't wait into the past */
tv.tv_sec = msec/1000 ;
tv.tv_usec = (msec%1000)*1000 ;
select( 1 , NULL,NULL,NULL , &tv ) ;
return ;
}
/*-----------------------------------------------------------------*/
/*! Popdown a widget that may not be a shell. [30 Jun 2003]
-------------------------------------------------------------------*/
void RWC_XtPopdown( Widget w )
{
Widget wpar = w ;
ENTRY("RWC_XtPopdown") ;
if( wpar == NULL ) EXRETURN ;
while( XtIsShell(wpar)==0 && XtParent(wpar)!=NULL ) wpar = XtParent(wpar);
XtPopdown(wpar) ; RWC_sleep(1) ;
EXRETURN ;
}
/*-----------------------------------------------------------------*/
/******************** Speech stuff (for Mac OS X) ******************/
#if !defined(NO_FRIVOLITIES) && defined(DARWIN)
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
static int have_say = -1 ;
static char voice[128] = "Cellos" ;
/*-----------------------------------------------------------------*/
/*! Set the voice for the Apple speech synthesizer. */
void AFNI_speak_setvoice( char *vvv )
{
int ll ;
if( vvv == NULL || *vvv == '\0' ) return ;
ll = strlen(vvv) ; if( ll > 100 ) return ;
strcpy(voice,vvv) ; return ;
}
/*-----------------------------------------------------------------*/
/*! Speak a string using Apple's say command:
- string = Apple text-to-speech code
- nofork = 1 if you want to wait for the speech to finish;
= 0 if you want the function to return immediately,
before speech finishes (or perhaps even starts). */
void AFNI_speak( char *string , int nofork )
{
char *buf ; pid_t ppp ;
/* bad input ==> quit */
if( string == NULL || *string == '\0' ) return ;
/* user says "don't talk" ==> quit */
buf = getenv("AFNI_SPEECH") ;
#if 1
if( buf == NULL || toupper(*buf) != 'Y' ) return ; /* 02 Apr 2004 */
#else
if( buf != NULL && toupper(*buf) == 'N' ) return ;
#endif
/* don't have "say" program ==> quit */
if( have_say == -1 ) have_say = (THD_find_executable("say") != NULL) ;
if( have_say == 0 ) return ;
/* if want speech to run in a separate process ... */
if( !nofork ){
ppp = fork() ;
if( ppp < 0 ) return ; /* fork failed */
/* parent: wait for child to exit (happens almost instantly) */
if( ppp > 0 ){ waitpid(ppp,NULL,0); return; }
/* child: fork again immediately, then this child exits;
this is to prevent zombie processes from hanging around */
ppp = fork() ; if( ppp != 0 ) _exit(0) ; /* child exits now */
/* grandchild continues on to actually do something */
}
/* Run the say program using system() */
buf = (char *)malloc(strlen(string)+32) ;
sprintf(buf,"say -v%s '%s'",voice,string) ;
system(buf) ; free(buf) ;
if( !nofork ) _exit(0) ; /* grandchild exits */
return ; /* no forking ==> return to caller */
}
#else
void AFNI_speak( char *string , int nofork ){ return; } /* dummy function */
void AFNI_speak_setvoice( char *vvv ){ return; }
#endif
syntax highlighted by Code2HTML, v. 0.9.1