00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: vmd.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.109 $ $Date: 2020年07月23日 04:37:20 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * 00019 * Main program entry points. 00020 * 00021 ***************************************************************************/ 00022 00023 #include <stdlib.h> 00024 #include <stdio.h> 00025 00026 #if defined(_MSC_VER) 00027 #include "win32vmdstart.h" 00028 #endif 00029 00030 #if !defined(VMDNOMACBUNDLE) && defined(__APPLE__) 00031 #include "macosxvmdstart.h" 00032 #endif 00033 00034 #include "vmd.h" 00035 #include "VMDApp.h" 00036 #include "utilities.h" // for TRUE, and for string processing utilities 00037 #include "config.h" // for compiled-in defaults 00038 #include "WKFThreads.h" 00039 #include "Inform.h" 00040 #include "CommandQueue.h" 00041 #include "TextEvent.h" 00042 #include "MaterialList.h" // for MAT_XXX definitions 00043 #include "SymbolTable.h" // for processing atomselection macros 00044 00045 #include "ProfileHooks.h" // NVTX profiling 00046 00047 #if defined(VMDTKCON) 00048 #include "vmdconsole.h" 00049 #endif 00050 00051 #ifdef VMDFLTK 00052 #include <FL/Fl.H> 00053 #endif 00054 00055 #ifdef VMDOPENGL // OpenGL-specific files 00056 #ifdef VMDCAVE // CAVE-specific files 00057 #include "cave_ogl.h" 00058 #include "CaveRoutines.h" 00059 #endif 00060 #ifdef VMDFREEVR // FreeVR-specific files 00061 #include "freevr.h" 00062 #include "FreeVRRoutines.h" 00063 #endif 00064 #endif 00065 00066 #ifdef VMDMPI 00067 #include "VMDMPI.h" 00068 #endif 00069 00070 #ifdef VMDTCL 00071 #include <tcl.h> 00072 #include <signal.h> 00073 00074 // 00075 // set up signal handlers 00076 // 00077 static Tcl_AsyncHandler tclhandler; 00078 00079 extern "C" { 00080 typedef void (*sighandler_t)(int); 00081 00082 void VMDTclSigHandler(int) { 00083 Tcl_AsyncMark(tclhandler); 00084 } 00085 00086 int VMDTclAsyncProc(ClientData, Tcl_Interp *, int) { 00087 signal(SIGINT, (sighandler_t) VMDTclSigHandler); 00088 return TCL_ERROR; 00089 } 00090 00091 } 00092 #endif // VMDTCL 00093 00094 00097 static const char *vmd_initialize_tcl(const char *argv0) { 00098 #ifdef VMDTCL 00099 00100 #if defined(_MSC_VER) 00101 static char buffer[MAX_PATH +1]; 00102 char *p; 00103 00104 // get full pathname to VMD executable 00105 GetModuleFileName(NULL, buffer, sizeof(buffer)); 00106 00107 // convert filename to Tcl-format 00108 for (p = buffer; *p != '0円'; p++) { 00109 if (*p == '\\') { 00110 *p = '/'; 00111 } 00112 } 00113 00114 Tcl_FindExecutable(buffer); 00115 return buffer; 00116 #else 00117 if (argv0) { 00118 Tcl_FindExecutable(argv0); 00119 } 00120 return argv0; 00121 #endif 00122 00123 #else // no Tcl 00124 return ""; 00125 #endif 00126 00127 } 00128 00131 static void vmd_finalize_tcl() { 00132 #ifdef VMDTCL 00133 Tcl_Finalize(); 00134 #endif 00135 } 00136 00137 00138 extern "C" { 00139 00140 // function pointer to shared memory allocator/deallocator 00141 void * (*vmd_alloc)(size_t); 00142 void (*vmd_dealloc)(void *); 00143 void * (*vmd_realloc)(void *, size_t); 00144 00145 // function to resize allocations depending on whether or not the allocator 00146 // provides a realloc() function or not. 00147 void * vmd_resize_alloc(void *ptr, size_t oldsize, size_t newsize) { 00148 void *newptr=NULL; 00149 00150 if (ptr == NULL) { 00151 newptr = vmd_alloc(newsize); 00152 return newptr; 00153 } 00154 00155 if (vmd_realloc != NULL) { 00156 newptr = vmd_realloc(ptr, newsize); 00157 } 00158 00159 if (newptr == NULL) { 00160 newptr = vmd_alloc(newsize); 00161 if (newptr != NULL) { 00162 memcpy(newptr, ptr, oldsize); 00163 vmd_dealloc(ptr); 00164 } 00165 } 00166 00167 return newptr; 00168 } 00169 00170 } // end of extern "C" 00171 00172 extern void VMDupdateFltk() { 00173 #ifdef VMDFLTK 00174 #if (defined(__APPLE__)) && defined(VMDTCL) 00175 // don't call wait(0) since this causes Tcl/Tk to mishandle events 00176 Fl::flush(); 00177 #else 00178 Fl::wait(0); 00179 #endif 00180 #endif 00181 } 00182 00183 /*************************************************************************** 00184 enumerates for different initial status variables, such as the type of 00185 display to use at startup 00186 ***************************************************************************/ 00187 00188 // display types at startup 00189 // For a complete case we should have: 00190 // FLTK on? (or Tk? or MFC?) 00191 // GL or OpenGL? (or other??) 00192 // use the CAVE? 00193 // and be smart about choosing the GL/OpenGL CAVE options, etc. 00194 enum DisplayTypes { 00195 DISPLAY_WIN, // standard display in a window. 00196 DISPLAY_WINOGL, // use OpenGL, if a valid option 00197 DISPLAY_OGLPBUFFER, // use OpenGL off-screen rendering, if a valid option 00198 DISPLAY_CAVE, // Display in the CAVE, no FLTK 00199 DISPLAY_TEXT, // Don't use a graphics display 00200 DISPLAY_CAVEFORMS, // Use the CAVE _and_ FLTK 00201 DISPLAY_FREEVR, // Use the FREEVR, no FLTK 00202 DISPLAY_FREEVRFORMS, // Use the CAVE _and_ FLTK 00203 NUM_DISPLAY_TYPES 00204 }; 00205 00206 static const char *displayTypeNames[NUM_DISPLAY_TYPES] = { 00207 "WIN", "OPENGL", "OPENGLPBUFFER", 00208 "CAVE", "TEXT", "CAVEFORMS", "FREEVR", "FREEVRFORMS" 00209 }; 00210 00211 #define DISPLAY_USES_WINDOW(d) ((d) == DISPLAY_WIN || (d) == DISPLAY_WINOGL) 00212 #define DISPLAY_USES_CAVE(d) ((d) == DISPLAY_CAVE || (d) == DISPLAY_CAVEFORMS) 00213 #define DISPLAY_USES_FREEVR(d) ((d) == DISPLAY_FREEVR || (d) == DISPLAY_FREEVRFORMS) 00214 #define DISPLAY_USES_GUI(d) (DISPLAY_USES_WINDOW(d) || (d) == DISPLAY_CAVEFORMS || (d) == DISPLAY_FREEVRFORMS) 00215 00216 // how to show the title 00217 enum TitleTypes { 00218 TITLE_OFF, TITLE_ON, NUM_TITLE_TYPES 00219 }; 00220 00221 static const char *titleTypeNames[NUM_TITLE_TYPES] = { 00222 "OFF", "ON" 00223 }; 00224 00225 // display options set at startup time 00226 static int showTitle = INIT_DEFTITLE; 00227 static int which_display = INIT_DEFDISPLAY; 00228 static float displayHeight = INIT_DEFHEIGHT; 00229 static float displayDist = INIT_DEFDIST; 00230 static int displaySize[2] = { -1, -1 }; 00231 static int displayLoc[2] = { -1, -1 }; 00232 00233 // filenames for init and startup files 00234 static const char *startupFileStr; 00235 static const char *beginCmdFile; 00236 00237 // Change the text interpreter to Python before processing commands. 00238 // (affects the "-e" file, not the .vmdrc or other files. 00239 static int cmdFileUsesPython; 00240 00241 // Filename parsing on the command line works as follows. The loadAsMolecules 00242 // flag is either on or off. When on, each filename parsed will be loaded as 00243 // a separate molecule. When off, all subsequent files will be loaded into 00244 // the same molecule. The flag is turned on with "-m" and off with 00245 // "-f". The default state is off. "-m" and "-f" can be 00246 // specified multiple times on the command line. 00247 static int loadAsMolecules = 0; 00248 static int startNewMolecule = 1; 00249 static ResizeArray<int> startNewMoleculeFlags; 00250 static ResizeArray<const char *> initFilenames; 00251 static ResizeArray<const char *> initFiletypes; 00252 00253 // Miscellaneous stuff 00254 static int eofexit = 0; 00255 static int just_print_help = 0; 00256 static ResizeArray<char *> customArgv; 00257 00258 // forward declaration of startup processing routines 00259 static void VMDtitle(); 00260 static void VMDGetOptions(int, char **, int mpienabled); 00261 00262 00263 int VMDinitialize(int *argc, char ***argv, int mpienabled) { 00264 int i; 00265 00266 PROFILE_PUSH_RANGE("VMDinitialize()", 1); 00267 00268 #if defined(VMDMPI) 00269 if (mpienabled) { 00270 // hack to fix up env vars if necessary 00271 for (i=0; i<(*argc); i++) { 00272 if(!strupcmp((*argv)[i], "-vmddir")) { 00273 if((*argc) > (i + 1)) { 00274 setenv("VMDDIR", (*argv)[++i], 1); 00275 } else { 00276 msgErr << "-vmddir must specify a fully qualified path." << sendmsg; 00277 } 00278 } 00279 } 00280 00281 vmd_mpi_init(argc, argv); // initialize MPI, fix up env vars, etc. 00282 } 00283 #endif 00284 00285 #if defined(_MSC_VER) && !defined(VMDSEPARATESTARTUP) 00286 win32vmdstart(); // get registry info etc 00287 #endif 00288 00289 #if !defined(VMDNOMACBUNDLE) && defined(__APPLE__) 00290 macosxvmdstart(*argc, *argv); // get env variables etc 00291 #endif 00292 00293 // Tell Tcl where the executable is located 00294 const char *argv0 = vmd_initialize_tcl((*argv)[0]); 00295 00296 #ifdef VMDTCL 00297 // register signal handler 00298 tclhandler = Tcl_AsyncCreate(VMDTclAsyncProc, (ClientData)NULL); 00299 signal(SIGINT, (sighandler_t) VMDTclSigHandler); 00300 #endif 00301 00302 // Let people know who we are. 00303 VMDtitle(); 00304 00305 // Read environment variables and command line options. 00306 // Initialize customArgv with just argv0 to avoid problems with 00307 // Tcl extension. 00308 customArgv.append((char *)argv0); 00309 VMDGetOptions(*argc, *argv, mpienabled); 00310 00311 #if (!defined(__APPLE__) && !defined(_MSC_VER)) && (defined(VMDOPENGL) || defined(VMDFLTK)) 00312 // If we're using X-windows, we autodetect if the DISPLAY environment 00313 // variable is unset, and automatically switch back to text mode without 00314 // requiring the user to pass the "-dispdev text" command line parameters 00315 if ((which_display == DISPLAY_WIN) && (getenv("DISPLAY") == NULL)) { 00316 which_display = DISPLAY_TEXT; 00317 } 00318 #endif 00319 00320 #if defined(VMDTKCON) 00321 vmdcon_init(); 00322 msgInfo << "Using VMD Console redirection interface." << sendmsg; 00323 // we default to a widget mode console, unless text mode is requested. 00324 // we don't have an tcl interpreter registered yet, so it is set to NULL. 00325 // flushing pending messages to the screen, is only in text mode possible. 00326 if ((which_display == DISPLAY_TEXT) || (which_display == DISPLAY_OGLPBUFFER) 00327 || just_print_help) { 00328 vmdcon_use_text(NULL); 00329 vmdcon_purge(); 00330 } else { 00331 vmdcon_use_widget(NULL); 00332 } 00333 #endif 00334 00335 #ifdef VMDFLTK 00336 // Do various special FLTK initialization stuff here 00337 if ((which_display != DISPLAY_TEXT) && (which_display != DISPLAY_OGLPBUFFER)) { 00338 // Cause FLTK to to use 24-bit color for all windows if possible 00339 // This must be done before any FLTK windows are shown for the first time. 00340 if (!Fl::visual(FL_DOUBLE | FL_RGB8)) { 00341 if (!Fl::visual(FL_RGB8)) { 00342 Fl::visual(FL_RGB); 00343 } 00344 } 00345 00346 // Disable the use of the arrow keys for navigating buttons and other 00347 // non-text widgets, we'll try it out and see how it pans out 00348 Fl::visible_focus(0); 00349 00350 // Disable Drag 'n Drop since the only text field in VMD is the 00351 // atomselection input and DND severely gets in the way there. 00352 Fl::dnd_text_ops(0); 00353 } 00354 #endif 00355 00356 // Quit now if the user just wanted a list of command line options. 00357 if (just_print_help) { 00358 vmd_sleep(10); // This is here so that the user can see the message 00359 // before the terminal/shell exits... 00360 00361 PROFILE_POP_RANGE(); 00362 return 0; 00363 } 00364 00365 // Set up default allocators; these may be overridden by cave or freevr. 00366 vmd_alloc = malloc; // system malloc() in the default case 00367 vmd_dealloc = free; // system free() in the default case 00368 vmd_realloc = realloc; // system realloc(), set to NULL when not available 00369 00370 // check for a CAVE display 00371 if (DISPLAY_USES_CAVE(which_display)) { 00372 #ifdef VMDCAVE 00373 // allocate shared memory pool used to communicate with child renderers 00374 int megs = 2048; 00375 if (getenv("VMDCAVEMEM") != NULL) { 00376 megs = atoi(getenv("VMDCAVEMEM")); 00377 } 00378 msgInfo << "Attempting to get " << megs << 00379 "MB of CAVE Shared Memory" << sendmsg; 00380 grab_CAVE_memory(megs); 00381 00382 CAVEConfigure(argc, *argv, NULL); // configure cave walls and memory use 00383 00384 // point VMD shared memory allocators to CAVE routines 00385 vmd_alloc = malloc_from_CAVE_memory; 00386 vmd_dealloc = free_to_CAVE_memory; 00387 vmd_realloc = NULL; // no realloc() functionality is available presently 00388 #else 00389 msgErr << "Not compiled with the CAVE options set." << sendmsg; 00390 which_display = DISPLAY_WIN; 00391 #endif 00392 } 00393 00394 // check for a FreeVR display 00395 if (DISPLAY_USES_FREEVR(which_display)) { 00396 #ifdef VMDFREEVR 00397 int megs = 2048; 00398 if (getenv("VMDFREEVRMEM") != NULL) { 00399 megs = atoi(getenv("VMDFREEVRMEM")); 00400 } 00401 msgInfo << "Attempting to get " << megs << 00402 "MB of FreeVR Shared Memory" << sendmsg; 00403 grab_FreeVR_memory(megs); // have to do this *before* vrConfigure() if 00404 // we want more than the default shared mem. 00405 vrConfigure(NULL, NULL, NULL); // configure FreeVR walls 00406 00407 // point shared memory allocators to FreeVR routines 00408 vmd_alloc = malloc_from_FreeVR_memory; 00409 vmd_dealloc = free_to_FreeVR_memory; 00410 vmd_realloc = NULL; // no realloc() functionality is available presently 00411 #else 00412 msgErr << "Not compiled with the FREEVR options set." << sendmsg; 00413 which_display = DISPLAY_WIN; 00414 #endif 00415 } 00416 00417 // return custom argc/argv 00418 *argc = customArgv.num(); 00419 for (i=0; i<customArgv.num(); i++) { 00420 (*argv)[i] = customArgv[i]; 00421 } 00422 00423 PROFILE_POP_RANGE(); 00424 00425 return 1; // successful startup 00426 } 00427 00428 const char *VMDgetDisplayTypeName() { 00429 return displayTypeNames[which_display]; 00430 } 00431 00432 void VMDgetDisplayFrame(int *loc, int *size) { 00433 for (int i=0; i<2; i++) { 00434 loc[i] = displayLoc[i]; 00435 size[i] = displaySize[i]; 00436 } 00437 } 00438 00439 void VMDshutdown(int mpienabled) { 00440 vmd_finalize_tcl(); // after all VMDApp instances are deleted 00441 00442 #ifdef VMDCAVE 00443 if (DISPLAY_USES_CAVE(which_display)) { // call the CAVE specific exit 00444 CAVEExit(); 00445 } 00446 #endif 00447 #ifdef VMDFREEVR 00448 if (DISPLAY_USES_FREEVR(which_display)) { // call the FreeVR specific exit 00449 vrExit(); 00450 } 00451 #endif 00452 #ifdef VMDMPI 00453 if (mpienabled) { 00454 vmd_mpi_fini(); 00455 } 00456 #endif 00457 } 00458 00459 static void VMDtitle() { 00460 msgInfo << VERSION_MSG << "\n"; 00461 msgInfo << "http://www.ks.uiuc.edu/Research/vmd/ \n"; 00462 msgInfo << "Email questions and bug reports to vmd@ks.uiuc.edu \n"; 00463 msgInfo << "Please include this reference in published work using VMD: \n"; 00464 msgInfo << " Humphrey, W., Dalke, A. and Schulten, K., `VMD - Visual \n"; 00465 msgInfo << " Molecular Dynamics', J. Molec. Graphics 1996, 14.1, 33-38.\n"; 00466 msgInfo << "-------------------------------------------------------------\n"; 00467 msgInfo << sendmsg; 00468 } 00469 00471 00472 // look for all environment variables VMD can use, and initialize the 00473 // proper variables. If an env variable is not found, use a default value. 00474 // ENVIRONMENT VARIABLES USED BY VMD (default values set in config.h): 00475 // VMDDIR directory with VMD data files and utility programs 00476 // VMDTMPDIR directory in which to put temporary files (def: /tmp) 00477 static void VMDGetOptions(int argc, char **argv, int mpienabled) { 00478 char *envtxt; 00479 00480 // 00481 // VMDDISPLAYDEVICE: which display device to use by default 00482 // 00483 if((envtxt = getenv("VMDDISPLAYDEVICE"))) { 00484 for(int i=0; i < NUM_DISPLAY_TYPES; i++) { 00485 if(!strupcmp(envtxt, displayTypeNames[i])) { 00486 which_display = i; 00487 break; 00488 } 00489 } 00490 } 00491 00492 // 00493 // VMDTITLE: whether to enable the title screen 00494 // 00495 if((envtxt = getenv("VMDTITLE"))) { 00496 for(int i=0; i < NUM_TITLE_TYPES; i++) { 00497 if(!strupcmp(envtxt, titleTypeNames[i])) { 00498 showTitle = i; 00499 break; 00500 } 00501 } 00502 } 00503 00504 // 00505 // VMDSCRHEIGHT: height of the screen 00506 // 00507 if((envtxt = getenv("VMDSCRHEIGHT"))) 00508 displayHeight = (float) atof(envtxt); 00509 00510 // 00511 // VMDSCRDIST: distance to the screen 00512 // 00513 if((envtxt = getenv("VMDSCRDIST"))) 00514 displayDist = (float) atof(envtxt); 00515 00516 // 00517 // VMDSCRPOS: graphics window location 00518 // 00519 if((envtxt = getenv("VMDSCRPOS"))) { 00520 char * dispStr = NULL; 00521 char * dispArgv[64]; 00522 int dispArgc; 00523 00524 if((dispStr = str_tokenize(envtxt, &dispArgc, dispArgv)) != NULL 00525 && dispArgc == 2) { 00526 displayLoc[0] = atoi(dispArgv[0]); 00527 displayLoc[1] = atoi(dispArgv[1]); 00528 } else { 00529 msgErr << "Illegal VMDSCRPOS environment variable setting '" 00530 << envtxt << "'." << sendmsg; 00531 } 00532 if(dispStr) delete [] dispStr; 00533 } 00534 00535 // 00536 // VMDSCRSIZE: graphics window size 00537 // 00538 if((envtxt = getenv("VMDSCRSIZE"))) { 00539 char * dispStr = NULL; 00540 char * dispArgv[64]; 00541 int dispArgc; 00542 if((dispStr = str_tokenize(envtxt, &dispArgc, dispArgv)) != NULL 00543 && dispArgc == 2) { 00544 displaySize[0] = atoi(dispArgv[0]); 00545 displaySize[1] = atoi(dispArgv[1]); 00546 00547 // force users to do something that makes sense 00548 if (displaySize[0] < 100) 00549 displaySize[0] = 100; // minimum sane width 00550 if (displaySize[1] < 100) 00551 displaySize[1] = 100; // minimum sane height 00552 00553 } else { 00554 msgErr << "Illegal VMDSCRSIZE environment variable setting '" 00555 << envtxt << "'." << sendmsg; 00556 } 00557 if(dispStr) delete [] dispStr; 00558 } 00559 00560 // initialize variables which indicate how VMD starts up, and 00561 // parse the command-line options 00562 00563 // go through the arguments 00564 int ev = 1; 00565 while(ev < argc) { 00566 if(!strupcmp(argv[ev], "-dist")) { 00567 if(argc > (ev + 1)) { 00568 displayDist = (float) atof(argv[++ev]); 00569 } else 00570 msgErr << "-dist must also specify a distance." << sendmsg; 00571 00572 } else if(!strupcmp(argv[ev], "-e")) { 00573 if(argc > (ev + 1)) { 00574 beginCmdFile = argv[++ev]; 00575 } else 00576 msgErr << "-e must also specify a filename." << sendmsg; 00577 00578 } else if(!strupcmp(argv[ev], "-height")) { 00579 if(argc > (ev + 1)) { 00580 displayHeight = (float) atof(argv[++ev]); 00581 } else 00582 msgErr << "-height must also specify a distance." << sendmsg; 00583 00584 } else if(!strupcmp(argv[ev], "-pos")) { 00585 if(argc > (ev + 2) && *(argv[ev+1]) != '-' && *(argv[ev+2]) != '-') { 00586 displayLoc[0] = atoi(argv[++ev]); 00587 displayLoc[1] = atoi(argv[++ev]); 00588 } else 00589 msgErr << "-pos must also specify an X Y pair." << sendmsg; 00590 00591 } else if(!strupcmp(argv[ev], "-size")) { 00592 if(argc > (ev + 2) && *(argv[ev+1]) != '-' && *(argv[ev+2]) != '-') { 00593 displaySize[0] = atoi(argv[++ev]); 00594 displaySize[1] = atoi(argv[++ev]); 00595 } else 00596 msgErr << "-size must also specify an X Y pair." << sendmsg; 00597 00598 } else if(!strupcmp(argv[ev], "-startup")) { 00599 // use next argument as startup config file name 00600 if(argc > (ev + 1)) 00601 startupFileStr = argv[++ev]; 00602 else 00603 msgErr << "-startup must also have a new file name specified." 00604 << sendmsg; 00605 00606 } else if(!strupcmp(argv[ev], "-nt")) { 00607 // do not print out the program title 00608 showTitle = TITLE_OFF; 00609 00610 } else if (!strupcmp(argv[ev], "-dispdev")) { // startup Display 00611 ev++; 00612 if (argc > ev) { 00613 if (!strupcmp(argv[ev], "cave")) { 00614 which_display = DISPLAY_CAVE; // use the CAVE 00615 } else if (!strupcmp(argv[ev], "win")) { 00616 which_display = DISPLAY_WIN; // use OpenGL, the default 00617 } else if (!strupcmp(argv[ev], "opengl")) { 00618 which_display = DISPLAY_WINOGL; // use OpenGL if available 00619 } else if (!strupcmp(argv[ev], "openglpbuffer")) { 00620 which_display = DISPLAY_OGLPBUFFER; // use OpenGLPbuffer if available 00621 } else if (!strupcmp(argv[ev], "text")) { 00622 which_display = DISPLAY_TEXT; // use text console only 00623 } else if (!strupcmp(argv[ev], "caveforms")) { 00624 which_display = DISPLAY_CAVEFORMS; // use CAVE+Forms 00625 } else if (!strupcmp(argv[ev], "freevr")) { 00626 which_display = DISPLAY_FREEVR; // use FreeVR 00627 } else if (!strupcmp(argv[ev], "freevrforms")) { 00628 which_display = DISPLAY_FREEVRFORMS; // use FreeVR+Forms 00629 } else if (!strupcmp(argv[ev], "none")) { 00630 which_display = DISPLAY_TEXT; // use text console only 00631 } else { 00632 msgErr << "-dispdev options are 'win' 'opengl' (default), 'openglpbuffer', 'cave', 'caveforms', 'freevr', 'freevrforms', or 'text | none'" << sendmsg; 00633 } 00634 } else { 00635 msgErr << "-dispdev options are 'win' 'opengl' (default), 'openglpbuffer', 'cave', 'caveforms', 'freevr', 'freevrforms', or 'text | none'" << sendmsg; 00636 } 00637 } else if (!strupcmp(argv[ev], "-h") || !strupcmp(argv[ev], "--help")) { 00638 // print out command-line option summary 00639 msgInfo << "Available command-line options:" << sendmsg; 00640 msgInfo << "\t-dispdev <win | cave | text | none> Specify display device"; 00641 msgInfo << sendmsg; 00642 msgInfo << "\t-dist <d> Distance from origin to screen"; 00643 msgInfo << sendmsg; 00644 msgInfo << "\t-e <filename> Execute commands in <filename>\n"; 00645 msgInfo << "\t-python Use Python for -e file and subsequent text input\n"; 00646 msgInfo << "\t-eofexit Exit when end-of-file occurs on input\n"; 00647 msgInfo << "\t-h | --help Display this command-line summary\n"; 00648 msgInfo << "\t-height <h> Height of display screen"; 00649 msgInfo << sendmsg; 00650 msgInfo << "\t-pos <X> <Y> Lower-left corner position of display"; 00651 msgInfo << sendmsg; 00652 msgInfo << "\t-nt No title display at start" << sendmsg; 00653 msgInfo << "\t-size <X> <Y> Size of display" << sendmsg; 00654 msgInfo << "\t-startup <filename> Specify startup script file" << sendmsg; 00655 msgInfo << "\t-m Load subsequent files as separate molecules\n"; 00656 msgInfo << "\t-f Load subsequent files into the same molecule\n"; 00657 msgInfo << "\t<filename> Load file using best-guess file type\n"; 00658 msgInfo << "\t-<type> <filename> Load file using specified file type\n"; 00659 msgInfo << "\t-args Pass subsequent arguments to text interpreter\n"; 00660 msgInfo << sendmsg; 00661 just_print_help = 1; 00662 } else if (!strupcmp(argv[ev], "-eofexit")) { // exit on EOF 00663 eofexit = 1; 00664 } else if (!strupcmp(argv[ev], "-node")) { 00665 // start VMD process on a cluster node, next parm is node ID.. 00666 ev++; // skip node ID parm 00667 } else if (!strupcmp(argv[ev], "-webhelper")) { 00668 // Unix startup script doesn't run VMD in the background, so that 00669 // web browsers won't delete files out from under us until it really 00670 // exits. We don't do anything special inside VMD itself presently 00671 // however. 00672 } else if (!strupcmp(argv[ev], "-python")) { 00673 cmdFileUsesPython = 1; 00674 } else if (!strupcmp(argv[ev], "-args")) { 00675 // pass the rest of the command line arguments, and only those, 00676 // to the embedded text interpreters. 00677 while (++ev < argc) 00678 customArgv.append(argv[ev]); 00679 00680 } else if (!strupcmp(argv[ev], "-m")) { 00681 loadAsMolecules = 1; 00682 startNewMolecule = 1; 00683 } else if (!strupcmp(argv[ev], "-f")) { 00684 loadAsMolecules = 0; 00685 startNewMolecule = 1; 00686 #ifdef VMDMPI 00687 } else if (mpienabled && !strupcmp(argv[ev], "-vmddir")) { 00688 ev++; // skip VMDDIR directory parm, since we already handled this 00689 // in MPI startup before we got to this loop... 00690 #endif 00691 } else { 00692 // any other argument is treated either as a filename or as a 00693 // filetype/filename pair of the form -filetype filename. 00694 const char *filename, *filetype; 00695 if (argv[ev][0] == '-') { 00696 // must be filetype/filename pair 00697 if (argc > ev+1) { 00698 filetype = argv[ev]+1; 00699 filename = argv[ev+1]; 00700 ev++; 00701 } else { 00702 msgErr << "filetype argument '" << argv[ev] << "' needs a filename." 00703 << sendmsg; 00704 ev++; // because we skip past the ev++ at the bottom of the loop. 00705 continue; 00706 } 00707 } else { 00708 // Given just a filename. The filetype will have to be guessed. 00709 filename = argv[ev]; 00710 filetype = NULL; 00711 } 00712 initFilenames.append(filename); 00713 initFiletypes.append(filetype); 00714 startNewMoleculeFlags.append(startNewMolecule); 00715 if (!loadAsMolecules) startNewMolecule = 0; 00716 } 00717 ev++; 00718 } 00719 00720 // command-line options have been parsed ... any init status variables that 00721 // have been given initial values will have flags saying so, and their 00722 // values will not be changed when the init file(s) is parsed. 00723 } 00724 00725 static int parseColorDefs(const char *path, VMDApp *app) { 00726 FILE *fd = fopen(path, "rt"); 00727 char buf[256]; 00728 memset(buf, 0, sizeof(buf)); 00729 00730 int success = TRUE; 00731 00732 if (!fd) { 00733 msgErr << "Color definitions file '" << path << "' does not exist." << sendmsg; 00734 return FALSE; 00735 } 00736 while (fgets(buf, sizeof(buf), fd)) { 00737 if (buf[0] == '0円' || buf[0] == '#') continue; 00738 char first[128], second[128], third[128], fourth[128]; 00739 memset(first, 0, sizeof(first)); 00740 memset(second, 0, sizeof(second)); 00741 memset(third, 0, sizeof(third)); 00742 memset(fourth, 0, sizeof(fourth)); 00743 00744 // handle cases like "Structure {Alpha Helix} purple 00745 int rc = sscanf(buf, "%s { %s %s %s", first, second, third, fourth); 00746 if (rc == 4) { 00747 char *right = strchr(third, '}'); 00748 if (right) *right = '0円'; 00749 strcat(second, " "); 00750 strcat(second, third); 00751 if (!app->color_add_item(first, second, fourth)) { 00752 msgErr << "Failed to add color definition: '" << buf << "'" << sendmsg; 00753 success = FALSE; 00754 } 00755 } else if (sscanf(buf, "%s %s %s", first, second, third) == 3) { 00756 if (!app->color_add_item(first, second, third)) { 00757 msgErr << "Failed to add color definition: '" << buf << "'" << sendmsg; 00758 success = FALSE; 00759 } 00760 } 00761 } 00762 fclose(fd); 00763 return success; 00764 } 00765 00766 static int parseMaterialDefs(const char *path, VMDApp *app) { 00767 FILE *fd = fopen(path, "rt"); 00768 char buf[256] = { 0 }; 00769 int success = TRUE; 00770 00771 if (!fd) { 00772 msgErr << "Material definitions file '" << path << "' does not exist." << sendmsg; 00773 return FALSE; 00774 } 00775 while (fgets(buf, sizeof(buf), fd)) { 00776 if (buf[0] == '0円' || buf[0] == '#') continue; 00777 char name[100] = { 0 }; 00778 float vals[10] = { 0 }; 00779 int readcount; 00780 00781 memset(vals, 0, sizeof(vals)); 00782 readcount=sscanf(buf, "%s %f %f %f %f %f %f %f %f %f", 00783 name, vals, vals+1, vals+2, vals+3, vals+4, 00784 vals+5, vals+6, vals+7, vals+8); 00785 if ((readcount < 7) || (readcount > 10)) 00786 continue; // skip bad material 00787 00788 if (!app->material_add(name, NULL)) { 00789 msgErr << "Failed to add material '" << name << "'" << sendmsg; 00790 success = FALSE; 00791 continue; 00792 } 00793 app->material_change(name, MAT_AMBIENT, vals[0]); 00794 app->material_change(name, MAT_DIFFUSE, vals[1]); 00795 app->material_change(name, MAT_SPECULAR, vals[2]); 00796 app->material_change(name, MAT_SHININESS, vals[3]); 00797 app->material_change(name, MAT_MIRROR, vals[4]); 00798 app->material_change(name, MAT_OPACITY, vals[5]); 00799 app->material_change(name, MAT_OUTLINE, vals[6]); 00800 app->material_change(name, MAT_OUTLINEWIDTH, vals[7]); 00801 app->material_change(name, MAT_TRANSMODE, vals[8]); 00802 } 00803 fclose(fd); 00804 return success; 00805 } 00806 00807 static int parseRestypes(const char *path, VMDApp *app) { 00808 FILE *fd = fopen(path, "rt"); 00809 char buf[256]; 00810 memset(buf, 0, sizeof(buf)); 00811 int success = TRUE; 00812 00813 if (!fd) { 00814 msgErr << "Residue types file '" << path << "' does not exist." << sendmsg; 00815 return FALSE; 00816 } 00817 while (fgets(buf, sizeof(buf), fd)) { 00818 if (buf[0] == '0円' || buf[0] == '#') continue; 00819 char name[64], type[64]; 00820 memset(name, 0, sizeof(name)); 00821 memset(type, 0, sizeof(type)); 00822 00823 if (sscanf(buf, "%s %s", name, type) != 2) continue; 00824 00825 if (!app->color_set_restype(name, type)) { 00826 msgErr << "Failed to add residue type '" << buf << "'" << sendmsg; 00827 success = FALSE; 00828 } 00829 } 00830 fclose(fd); 00831 return success; 00832 } 00833 00834 static int parseAtomselMacros(const char *path, VMDApp *app) { 00835 char buf[256]; 00836 memset(buf, 0, sizeof(buf)); 00837 00838 FILE *fd = fopen(path, "rt"); 00839 if (!fd) { 00840 msgErr << "Atomselection macro file '" << path << "' does not exist." << sendmsg; 00841 return FALSE; 00842 } 00843 int success= TRUE; 00844 while (fgets(buf, sizeof(buf), fd)) { 00845 if (buf[0] == '0円' || buf[0] == '#' || isspace(buf[0])) continue; 00846 char *macro = strchr(buf, ' '); 00847 if (!macro) continue; 00848 *macro = '0円'; 00849 macro++; 00850 00851 // Remove trailing newline characters 00852 macro[strcspn(macro, "\r\n")] = 0; 00853 00854 if (!app->atomSelParser->add_custom_singleword(buf, macro)) { 00855 msgErr << "Failed to add macro '" << buf << "'" << sendmsg; 00856 success = FALSE; 00857 } 00858 } 00859 fclose(fd); 00860 return success; 00861 } 00862 00863 // Read scripts in scripts/vmd 00864 void VMDreadInit(VMDApp *app) { 00865 char path[4096]; 00866 00867 const char *vmddir = getenv("VMDDIR"); 00868 if (vmddir == NULL) { 00869 msgErr << "VMDDIR undefined, startup failure likely." << sendmsg; 00870 #if defined(_MSC_VER) 00871 vmddir = "c:/program files/university of illinois/vmd"; 00872 #else 00873 vmddir = "/usr/local/lib/vmd"; 00874 #endif 00875 } 00876 sprintf(path, "%s/scripts/vmd/colordefs.dat", vmddir); 00877 if (!parseColorDefs(path, app)) { 00878 msgErr << "Parsing color definitions failed." << sendmsg; 00879 } 00880 sprintf(path, "%s/scripts/vmd/materials.dat", vmddir); 00881 if (!parseMaterialDefs(path, app)) { 00882 msgErr << "Parsing material definitions failed." << sendmsg; 00883 } 00884 sprintf(path, "%s/scripts/vmd/restypes.dat", vmddir); 00885 if (!parseRestypes(path, app)) { 00886 msgErr << "Parsing residue types failed." << sendmsg; 00887 } 00888 sprintf(path, "%s/scripts/vmd/atomselmacros.dat", vmddir); 00889 if (!parseAtomselMacros(path, app)) { 00890 msgErr << "Parsing atomselection macros failed." << sendmsg; 00891 } 00892 } 00893 00894 // read in the startup script, execute it, and then execute any other commands 00895 // which might be necessary (i.e. to load any molecules at start) 00896 // This searches for the startup file in the following 00897 // places (and in this order), reading only the FIRST one found: 00898 // 1. Current directory 00899 // 2. Home directory 00900 // 3. 'Default' directory (here, /usr/local/vmd) 00901 // If a name was given in the -startup switch, that file is checked for ONLY. 00902 void VMDreadStartup(VMDApp *app) { 00903 char namebuf[512] = { 0 }; 00904 char *envtxt; 00905 int found = FALSE; 00906 FILE * tfp; 00907 char *DataPath; // path of last resort to find a .vmdrc file 00908 00909 // These options were set by environment variables or command line options 00910 app->display_set_screen_height(displayHeight); 00911 app->display_set_screen_distance(displayDist); 00912 app->set_eofexit(eofexit); 00913 if (showTitle == TITLE_ON && (which_display != DISPLAY_TEXT) && 00914 (which_display != DISPLAY_OGLPBUFFER)) { 00915 app->display_titlescreen(); 00916 } 00917 00918 if ((envtxt = getenv("VMDDIR")) != NULL) 00919 DataPath = stringdup(envtxt); 00920 else 00921 DataPath = stringdup(DEF_VMDENVVAR); 00922 stripslashes(DataPath); // strip out ending '/' chars. 00923 00924 // check if the file is available 00925 if (startupFileStr) { // name specified by -startup 00926 if ((tfp = fopen(startupFileStr, "rb")) != NULL) { 00927 found = TRUE; 00928 fclose(tfp); 00929 strcpy(namebuf, startupFileStr); 00930 } 00931 } else { // search in different directories, for default file 00932 const char *def_startup = VMD_STARTUP; 00933 // first, look in current dir 00934 strcpy(namebuf, def_startup); 00935 if ((tfp = fopen(namebuf, "rb")) != NULL) { 00936 found = TRUE; 00937 fclose(tfp); 00938 } else { 00939 // not found in current dir; look in home dir 00940 if ((envtxt = getenv("HOME")) != NULL) 00941 strcpy(namebuf, envtxt); 00942 else 00943 strcpy(namebuf, "."); 00944 strcat(namebuf, "/"); 00945 strcat(namebuf, def_startup); 00946 if ((tfp = fopen(namebuf, "rb")) != NULL) { 00947 found = TRUE; 00948 fclose(tfp); 00949 } else { 00950 // not found in home dir; look in default dir 00951 strcpy(namebuf, DataPath); 00952 strcat(namebuf, "/"); 00953 strcat(namebuf, def_startup); 00954 if ((tfp = fopen(namebuf, "rb")) != NULL) { 00955 found = TRUE; 00956 fclose(tfp); 00957 } 00958 } 00959 } 00960 } 00961 delete [] DataPath; DataPath = NULL; 00962 00963 // 00964 // execute any commands needed at start 00965 // 00966 00967 PROFILE_PUSH_RANGE("VMDreadStartup(): process cmd args", 4); 00968 00969 // read in molecules requested via command-line switches 00970 FileSpec spec; 00971 spec.waitfor = -1; // wait for all files to load before proceeding 00972 int molid = -1; // set sentinel value to determine if files were loaded 00973 00974 if (startNewMoleculeFlags.num() > 0) { 00975 msgInfo << "File loading in progress, please wait." << sendmsg; 00976 } 00977 00978 for (int i=0; i<startNewMoleculeFlags.num(); i++) { 00979 const char *filename = initFilenames[i]; 00980 const char *filetype = initFiletypes[i]; 00981 if (!filetype) { 00982 filetype = app->guess_filetype(filename); 00983 if (!filetype) { 00984 // assume pdb 00985 msgErr << "Unable to determine file type for file '" 00986 << filename << "'. Assuming pdb." << sendmsg; 00987 filetype = "pdb"; 00988 } 00989 } 00990 if (startNewMoleculeFlags[i]) { 00991 molid = app->molecule_load(-1, filename, filetype, &spec); 00992 } else { 00993 molid = app->molecule_load(molid, filename, filetype, &spec); 00994 } 00995 if (molid < 0) { 00996 msgErr << "Loading of startup molecule files aborted." << sendmsg; 00997 break; 00998 } 00999 } 01000 01001 PROFILE_POP_RANGE(); 01002 PROFILE_PUSH_RANGE("VMDreadStartup(): process " VMD_STARTUP, 3); 01003 01004 // if the startup file was found, read in the text commands there 01005 if (found) { 01006 app->logfile_read(namebuf); 01007 } 01008 01009 PROFILE_POP_RANGE(); 01010 PROFILE_PUSH_RANGE("VMDreadStartup(): load plugins", 5); 01011 01012 // Load the extension packages here, _after_ reading the .vmdrc file, 01013 // so that the search path for extensions can be customized. 01014 app->commandQueue->runcommand( 01015 new TclEvalEvent("vmd_load_extension_packages")); 01016 01017 PROFILE_POP_RANGE(); 01018 PROFILE_PUSH_RANGE("VMDreadStartup(): start Python", 1); 01019 01020 // Switch to Python if requested, before reading beginCmdFile 01021 if (cmdFileUsesPython) { 01022 if (!app->textinterp_change("python")) { 01023 // bail out since Python scripts won't be readable by Tcl. 01024 msgErr << "Skipping startup script because Python could not be started." 01025 << sendmsg; 01026 return; 01027 } 01028 } 01029 01030 PROFILE_POP_RANGE(); 01031 PROFILE_PUSH_RANGE("VMDreadStartup(): process cmd scripts", 1); 01032 01033 // after reading in startup file and loading any molecule, the file 01034 // specified by the -e option is set up to be executed. 01035 if (beginCmdFile) { 01036 app->logfile_read(beginCmdFile); 01037 } 01038 01039 PROFILE_POP_RANGE(); 01040 } 01041