Changeset 1278 for trunk/packages/vizservers/pymolproxy/pymolproxy.c
- Timestamp:
- Feb 19, 2009, 3:48:11 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/packages/vizservers/pymolproxy/pymolproxy.c
r1258 r1278 17 17 * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. 18 18 * ====================================================================== 19 */ 20 21 /* 22 * +--------------+ +------------+ +--------+ 23 * | | output | | input | | 24 * | |------->| |-------->| | 25 * | molvisviewer | | pymolproxy | output | pymol | 26 * | client | | |<--------| server | 27 * | | input | | errors | | 28 * | |<-------| |<--------| | 29 * +--------------+ +------------+ +--------+ 30 * 31 * The communication between the pymol server and proxy is completely 32 * synchronous. The proxy relays/translates commands from the client to the 33 * server and then wait for the responses. It also watches the server's 34 * stdout and stderr changes so that extraneous writes don't block the 35 * the server. (I don't know exactly what those responses are) 36 * 37 * The communication between the client and the proxy is different. The 38 * client commands are read when they become available on the socket. Proxy 39 * writes to the client (image output) are non-blocking so that we don't 40 * deadlock with the client. The client may be busy sending the next command 41 * when we want to write the resulting image from the last command. 42 * 43 * FIXME: Need to fix the reads from the pymol server. We want to check for 44 * an expected string within the pymol server output. Right now it's doing 45 * single character reads to stop when we hit a newline. We should create a 46 * read buffer that lets us do block reads. This problem only really affects 47 * the echoing back of commands (waiting for the pymol command prompt). Most 48 * command lines are small. Still it's a good area for improvement. 49 * 50 * FIXME: Might be a problem if another image is received from the server 51 * before the last one is transmitted. 19 52 */ 20 53 … … 61 94 size_t nBytes; /* # of bytes for all frames. */ 62 95 size_t nCommands; /* # of commands executed */ 63 double cmdTime; /* Ela sped time spend executing commands. */96 double cmdTime; /* Elapsed time spend executing commands. */ 64 97 struct timeval start; /* Start of elapsed time. */ 65 98 } Stats; … … 69 102 static FILE *flog; 70 103 static int debug = 0; 104 #ifdef notdef 105 static long _flags = 0; 106 #endif 71 107 72 108 typedef struct { … … 74 110 int used; 75 111 int allocated; 112 ssize_t nWritten; 113 size_t bytesLeft; 76 114 } DyBuffer; 77 115 116 #define BUFFER_SIZE 4096 117 78 118 typedef struct { 79 int p_stdin; 80 int p_stdout; 81 int p_stderr; 82 int c_stdin; 83 int c_stdout; 119 char bytes[BUFFER_SIZE]; 120 int fill; 121 int mark; 122 int fd; 123 } ReadBuffer; 124 125 #define BUFFER_OK 0 126 #define BUFFER_ERROR -1 127 #define BUFFER_CONTINUE -2 128 #define BUFFER_SHORT_READ -3 129 130 typedef struct { 131 int serverInput; 132 int serverOutput; 133 int serverError; 134 int clientInput; 135 int clientOutput; 84 136 DyBuffer image; 85 int need_update; 137 Tcl_Interp *interp; 138 int updatePending; 139 int rotatePending; 140 int scalePending; 141 int forceUpdate; 86 142 int can_update; 87 int immediate_update;88 143 int sync; 89 int labels;144 int showLabels; 90 145 int frame; 91 146 int rock_offset; … … 94 149 int error; 95 150 int status; 151 ReadBuffer client; 152 ReadBuffer server; 153 float xAngle, yAngle, zAngle; 154 float atomScale; 96 155 } PymolProxy; 97 156 157 static void PollForEvents(PymolProxy *proxyPtr); 98 158 static void 99 159 trace TCL_VARARGS_DEF(char *, arg1) … … 109 169 fflush(flog); 110 170 } 171 } 172 173 static void 174 InitBuffer(ReadBuffer *readPtr, int f) 175 { 176 readPtr->fd = f; 177 readPtr->fill = 0; 178 readPtr->mark = 0; 179 } 180 181 static void 182 FlushBuffer(ReadBuffer *readPtr) 183 { 184 readPtr->fill = 0; 185 readPtr->mark = 0; 186 } 187 188 static int 189 FillBuffer(ReadBuffer *readPtr) 190 { 191 size_t bytesLeft; 192 ssize_t nRead; 193 194 #ifdef notdef 195 trace("Entering FillBuffer (mark=%d, fill=%d)\n", readPtr->mark, 196 readPtr->fill); 197 #endif 198 if (readPtr->mark >= readPtr->fill) { 199 readPtr->mark = readPtr->fill = 0; 200 } 201 if (readPtr->mark > 0) { 202 size_t i, j; 203 204 for (i = 0, j = readPtr->mark; j < readPtr->fill; i++, j++) { 205 readPtr->bytes[i] = readPtr->bytes[j]; 206 } 207 readPtr->mark = 0; 208 readPtr->fill = i; 209 } 210 bytesLeft = BUFFER_SIZE - readPtr->fill - 1; 211 nRead = read(readPtr->fd, readPtr->bytes + readPtr->fill, bytesLeft); 212 if (nRead == 0) { 213 return BUFFER_ERROR; 214 } 215 if (nRead <= 0) { 216 if (errno != EAGAIN) { 217 #ifdef notdef 218 trace("in FillBuffer: read failed %d: %s", errno, strerror(errno)); 219 trace("Leaving FillBuffer FAIL(read %d bytes) mark=%d, fill=%d\n", 220 nRead, readPtr->mark, readPtr->fill); 221 #endif 222 return BUFFER_ERROR; 223 } 224 return BUFFER_SHORT_READ; 225 } 226 readPtr->fill += nRead; 227 #ifdef notdef 228 trace("Leaving FillBuffer (read %d bytes) mark=%d, fill=%d\n", 229 nRead, readPtr->mark, readPtr->fill); 230 #endif 231 return (nRead == bytesLeft) ? BUFFER_OK : BUFFER_SHORT_READ; 232 } 233 234 static char * 235 GetLine(ReadBuffer *readPtr, int *nBytesPtr) 236 { 237 int i; 238 int status; 239 240 #ifdef notdef 241 trace("Entering GetLine (mark=%d, fill=%d)\n",readPtr->mark, readPtr->fill); 242 #endif 243 status = BUFFER_OK; 244 for (;;) { 245 /* Look for the next newline (the next full line). */ 246 trace("in GetLine: mark=%d fill=%d\n", readPtr->mark, readPtr->fill); 247 for (i = readPtr->mark; i < readPtr->fill; i++) { 248 if (readPtr->bytes[i] == '\n') { 249 char *p; 250 251 /* Save the start of the line. */ 252 p = readPtr->bytes + readPtr->mark; 253 i++; 254 *nBytesPtr = i - readPtr->mark; 255 readPtr->mark = i; 256 #ifdef notdef 257 trace("Leaving GetLine(%.*s)\n", *nBytesPtr, p); 258 #endif 259 return p; 260 } 261 } 262 /* Couldn't find a newline, so it may be that we need to read some 263 * more. Check first that last read wasn't a short read. */ 264 if (status == BUFFER_SHORT_READ) { 265 break; 266 } 267 status = FillBuffer(readPtr); 268 if (status == BUFFER_ERROR) { 269 *nBytesPtr = BUFFER_ERROR; 270 return NULL; /* EOF or error on read. */ 271 } 272 } 273 #ifdef notdef 274 trace("Leaving GetLine failed to read line\n"); 275 #endif 276 *nBytesPtr = BUFFER_CONTINUE; 277 return NULL; 278 } 279 280 static int 281 GetBytes(ReadBuffer *readPtr, char *out, int nBytes) 282 { 283 #ifdef notdef 284 trace("Entering GetBytes(%d)\n", nBytes); 285 #endif 286 while (nBytes > 0) { 287 int bytesLeft; 288 int status; 289 290 bytesLeft = readPtr->fill - readPtr->mark; 291 if (bytesLeft > 0) { 292 int size; 293 294 size = (bytesLeft > nBytes) ? nBytes : bytesLeft; 295 memcpy(out, readPtr->bytes + readPtr->mark, size); 296 readPtr->mark += size; 297 nBytes -= size; 298 out += size; 299 } 300 if (nBytes == 0) { 301 /* Received requested # bytes. */ 302 #ifdef notdef 303 trace("Leaving GetBytes(%d)\n", nBytes); 304 #endif 305 return BUFFER_OK; 306 } 307 /* Didn't get enough bytes, need to read some more. */ 308 status = FillBuffer(readPtr); 309 if (status == BUFFER_ERROR) { 310 return BUFFER_ERROR; 311 } 312 #ifdef notdef 313 trace("in GetBytes: mark=%d fill=%d\n", readPtr->mark, readPtr->fill); 314 #endif 315 } 316 #ifdef notdef 317 trace("Leaving GetBytes(%d)\n", nBytes); 318 #endif 319 return BUFFER_OK; 320 } 321 322 INLINE static void 323 clear_error(PymolProxy *proxyPtr) 324 { 325 proxyPtr->error = 0; 326 proxyPtr->status = TCL_OK; 327 } 328 329 static int 330 Expect(PymolProxy *proxyPtr, char *match, char *out, int maxSize) 331 { 332 char c; 333 size_t length; 334 335 if (proxyPtr->status != TCL_OK) { 336 return proxyPtr->status; 337 } 338 trace("Entering Expect(match=%s, maxSize=%d)\n", match, maxSize); 339 c = match[0]; 340 length = strlen(match); 341 for (;;) { 342 int nBytes; 343 char *line; 344 345 line = GetLine(&proxyPtr->server, &nBytes); 346 if (line != NULL) { 347 trace("pymol says:%.*s", nBytes, out); 348 if ((c == line[0]) && (strncmp(line, match, length) == 0)) { 349 if (maxSize < nBytes) { 350 nBytes = maxSize; 351 } 352 memcpy(out, line, nBytes); 353 clear_error(proxyPtr); 354 trace("Leaving Expect: match is (%.*s)\n", nBytes, out); 355 return BUFFER_OK; 356 } 357 continue; 358 } 359 if (nBytes != BUFFER_CONTINUE) { 360 return BUFFER_ERROR; 361 } 362 } 363 trace("Leaving Expect: failed to find (%s)\n", match); 364 proxyPtr->error = 2; 365 proxyPtr->status = TCL_ERROR; 366 return BUFFER_ERROR; 111 367 } 112 368 … … 234 490 235 491 static int 236 ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)492 ExecuteCommand(Tcl_Interp *interp, const char *cmd) 237 493 { 238 494 struct timeval tv; … … 243 499 start = CVT2SECS(tv); 244 500 245 result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr)); 246 trace("Executed (%s)", Tcl_DStringValue(dsPtr)); 247 Tcl_DStringSetLength(dsPtr, 0); 501 result = Tcl_Eval(interp, cmd); 502 trace("Executed (%s)", cmd); 248 503 249 504 gettimeofday(&tv, NULL); … … 255 510 } 256 511 257 258 512 INLINE static void 259 dyBufferInit(DyBuffer *buffer) 260 { 261 buffer->data = NULL; 262 buffer->used = 0; 263 buffer->allocated = 0; 513 dyBufferInit(DyBuffer *imgPtr) 514 { 515 imgPtr->data = NULL; 516 imgPtr->used = 0; 517 imgPtr->allocated = 0; 518 imgPtr->nWritten = 0; 519 imgPtr->bytesLeft = 0; 264 520 } 265 521 266 522 INLINE static void 267 dyBufferFree(DyBuffer *buffer) 268 { 269 assert(buffer != NULL); 270 free(buffer->data); 271 dyBufferInit(buffer); 523 dyBufferFree(DyBuffer *imgPtr) 524 { 525 assert(imgPtr != NULL); 526 if (imgPtr->data != NULL) { 527 free(imgPtr->data); 528 } 529 dyBufferInit(imgPtr); 272 530 } 273 531 … … 303 561 } 304 562 305 static int 306 bwrite(int sock, char *buffer, int size) 307 { 308 int result; 309 int total = 0; 310 int left = size; 311 312 trace("bwrite: want to write %d bytes.", size); 313 while(1) { 314 result = write(sock,buffer+total,left); 315 316 if (result <= 0) 317 break; 318 319 total += result; 320 left -= result; 321 322 if (total == size) 323 break; 324 } 325 trace("bwrite: wrote %d bytes.", total); 326 return total; 327 } 328 329 static int 330 bread(int sock, char *buffer, int size) 563 static void 564 WriteImage(PymolProxy *proxyPtr, int fd) 565 { 566 DyBuffer *imgPtr; 567 ssize_t bytesLeft; 568 569 imgPtr = &proxyPtr->image; 570 trace("WriteImage: want to write %d bytes.", imgPtr->bytesLeft); 571 for (bytesLeft = imgPtr->bytesLeft; bytesLeft > 0; /*empty*/) { 572 ssize_t nWritten; 573 574 trace("WriteImage: try to write %d bytes.", bytesLeft); 575 nWritten = write(fd, imgPtr->data + imgPtr->nWritten, bytesLeft); 576 trace("WriteImage: wrote %d bytes.", nWritten); 577 if (nWritten < 0) { 578 trace("Error writing fd(%d), %d/%s.", fd, errno, 579 strerror(errno)); 580 return; 581 } 582 bytesLeft -= nWritten; 583 if (bytesLeft > 0) { 584 /* Wrote a short buffer, means we would block. */ 585 imgPtr->nWritten += nWritten; 586 imgPtr->bytesLeft = bytesLeft; 587 return; 588 } 589 imgPtr->nWritten += nWritten; 590 } 591 dyBufferFree(imgPtr); 592 } 593 594 595 #ifdef notdef 596 static int 597 ReadImage(PymolProxy *proxyPtr, int fd, size) 331 598 { 332 599 int result, total, left; 333 600 334 601 for( total = 0, left = size; left > 0; left -= result) { 335 result = read( sock,buffer+total,left);602 result = read(fd, buffer+total, left); 336 603 337 604 if (result > 0) { … … 341 608 342 609 if ((result < 0) && (errno != EAGAIN) && (errno != EINTR)) { 343 trace("Error reading sock(%d), %d/%s.", sock, errno,610 trace("Error reading fd(%d), %d/%s.", fd, errno, 344 611 strerror(errno)); 345 612 break; … … 350 617 return total; 351 618 } 619 #endif 620 621 static int 622 bwrite(int fd, char *buffer, int size) 623 { 624 int result; 625 int total = 0; 626 int left = size; 627 628 trace("bwrite: want to write %d bytes.", size); 629 while(1) { 630 result = write(fd,buffer+total,left); 631 632 if (result <= 0) 633 break; 634 635 total += result; 636 left -= result; 637 638 if (total == size) 639 break; 640 } 641 trace("bwrite: wrote %d bytes.", total); 642 return total; 643 } 644 645 static int 646 bread(int fd, char *buffer, int size) 647 { 648 int result, total, left; 649 650 for( total = 0, left = size; left > 0; left -= result) { 651 result = read(fd, buffer+total, left); 652 653 if (result > 0) { 654 total += result; 655 continue; 656 } 657 658 if ((result < 0) && (errno != EAGAIN) && (errno != EINTR)) { 659 trace("Error reading fd(%d), %d/%s.", fd, errno, 660 strerror(errno)); 661 break; 662 } 663 664 result = 0; 665 } 666 return total; 667 } 352 668 353 669 #ifdef notdef 354 670 355 671 static int 356 bflush(int sock, char *buffer, int size, int bytes)672 bflush(int fd, char *buffer, int size, int bytes) 357 673 { 358 674 int bsize; … … 364 680 bsize = bytes; 365 681 366 bsize = bread( sock,buffer,bsize);682 bsize = bread(fd,buffer,bsize); 367 683 368 684 bytes -= bsize; … … 421 737 } 422 738 423 INLINE static void 424 clear_error(PymolProxy *proxyPtr) 425 { 426 proxyPtr->error = 0; 427 proxyPtr->status = TCL_OK; 428 } 429 430 static int 431 getline(int sock, char *buffer, int size, int timeout) 739 740 static int 741 getline(int fd, char *buffer, int size, int timeout) 432 742 { 433 743 int pos = 0, status, timeo; … … 439 749 timeradd(&now,&tmo,&end); 440 750 441 ufd.fd = sock;751 ufd.fd = fd; 442 752 ufd.events = POLLIN; 443 753 … … 455 765 456 766 if (status > 0) 457 status = read( sock,&buffer[pos],1);767 status = read(fd,&buffer[pos],1); 458 768 459 769 if ( (status < 0) && ( (errno == EINTR) || (errno == EAGAIN) ) ) … … 475 785 } 476 786 477 static int 478 Expect(PymolProxy *proxyPtr, char *match, char *buffer, int length) 479 { 480 int sock; 481 char c; 482 size_t mlen; 483 484 assert(buffer != NULL); 485 if (proxyPtr->status != TCL_OK) 486 return proxyPtr->status; 487 488 sock = proxyPtr->p_stdout; 489 trace("Expect(%s)", match); 490 c = match[0]; 491 mlen = strlen(match); 492 for (;;) { 493 if (getline(sock, buffer, length, IO_TIMEOUT) == 0) { 494 proxyPtr->error = 2; 495 proxyPtr->status = TCL_ERROR; 496 break; 497 } 498 trace("stdout-u>read(%s)", buffer); 499 if ((c == buffer[0]) && (strncmp(buffer, match, mlen) == 0)) { 500 trace("stdout-e> %s", buffer); 501 clear_error(proxyPtr); 502 break; 503 } 504 } 505 506 return proxyPtr->status; 507 } 508 509 static int 510 Send(PymolProxy *proxyPtr, char *format, ...) 511 { 512 va_list ap; 513 char iobuffer[BUFSIZ]; 787 788 static int 789 Pymol(PymolProxy *proxyPtr, char *format, ...) 790 { 514 791 515 792 if (proxyPtr->error) { 516 793 return TCL_ERROR; 517 794 } 518 va_start(ap, format); 519 vsnprintf(iobuffer, 800, format, ap); 520 va_end(ap); 521 522 trace("to-pymol>(%s)", iobuffer); 523 524 /* Write the command out to the server. */ 525 write(proxyPtr->p_stdin, iobuffer, strlen(iobuffer)); 526 527 /* Now wait for the "PyMOL>" prompt. */ 528 if (Expect(proxyPtr, "PyMOL>", iobuffer, BUFSIZ)) { 529 trace("timeout reading data (iobuffer=%s)", iobuffer); 530 proxyPtr->error = 1; 531 proxyPtr->status = TCL_ERROR; 532 return proxyPtr->status; 533 } 534 return proxyPtr->status; 795 { 796 va_list ap; 797 char cmd[BUFSIZ]; 798 ssize_t nWritten; 799 size_t length; 800 801 va_start(ap, format); 802 vsnprintf(cmd, BUFSIZ-1, format, ap); 803 va_end(ap); 804 805 trace("to-pymol>(%s)", cmd); 806 807 /* Write the command out to the server. */ 808 length = strlen(cmd); 809 nWritten = write(proxyPtr->serverInput, cmd, length); 810 if (nWritten != length) { 811 trace("short write to pymol (wrote=%d, should have been %d)", 812 nWritten, length); 813 } 814 } 815 { 816 char out[BUFSIZ]; 817 int result; 818 819 /* Now wait for the "PyMOL>" prompt. */ 820 result = Expect(proxyPtr, "PyMOL>", out, BUFSIZ); 821 if (result == BUFFER_ERROR) { 822 trace("timeout reading data (buffer=%s)", out); 823 proxyPtr->error = 1; 824 proxyPtr->status = TCL_ERROR; 825 return proxyPtr->status; 826 } 827 return proxyPtr->status; 828 } 829 } 830 831 static void 832 DoRotate(PymolProxy *proxyPtr) 833 { 834 if (proxyPtr->rotatePending) { 835 /* Every pymol command line generates a new rendering. Execute all 836 * three turns as a single command line. */ 837 Pymol(proxyPtr,"turn x,%f; turn y,%f; turn z,%f\n", 838 proxyPtr->xAngle, proxyPtr->yAngle, proxyPtr->zAngle); 839 proxyPtr->xAngle = proxyPtr->yAngle = proxyPtr->zAngle = 0.0f; 840 proxyPtr->rotatePending = FALSE; 841 } 842 } 843 844 static void 845 DoAtomScale(PymolProxy *proxyPtr) 846 { 847 if (proxyPtr->scalePending) { 848 proxyPtr->scalePending = FALSE; 849 Pymol(proxyPtr, "set sphere_scale,%f,all\n", proxyPtr->atomScale); 850 } 851 } 852 853 static int 854 AtomscaleCmd(ClientData clientData, Tcl_Interp *interp, int argc, 855 const char *argv[]) 856 { 857 int defer = 0, push = 0, arg; 858 double scale; 859 const char *model = "all"; 860 PymolProxy *proxyPtr = clientData; 861 862 clear_error(proxyPtr); 863 scale = 0.25f; 864 for(arg = 1; arg < argc; arg++) { 865 if ( strcmp(argv[arg],"-defer") == 0 ) { 866 defer = 1; 867 } else if (strcmp(argv[arg],"-push") == 0) { 868 push = 1; 869 } else if (strcmp(argv[arg],"-model") == 0) { 870 if (++arg < argc) 871 model = argv[arg]; 872 } else { 873 if (Tcl_GetDouble(interp, argv[arg], &scale) != TCL_OK) { 874 return TCL_ERROR; 875 } 876 } 877 } 878 proxyPtr->invalidate_cache = TRUE; /* Spheres */ 879 proxyPtr->updatePending = !defer || push; 880 proxyPtr->forceUpdate = push; 881 882 if (strcmp(model, "all") == 0) { 883 proxyPtr->scalePending = TRUE; 884 proxyPtr->atomScale = scale; 885 } else { 886 Pymol(proxyPtr, "set sphere_scale,%f,%s\n", scale, model); 887 } 888 return proxyPtr->status; 535 889 } 536 890 … … 563 917 } 564 918 565 proxyPtr->invalidate_cache = 1;566 proxyPtr-> need_update= !defer || push;567 proxyPtr-> immediate_update |= push;568 569 Send(proxyPtr, "hide everything,%s\n",model);570 Send(proxyPtr, "set stick_color,white,%s\n",model);919 proxyPtr->invalidate_cache = TRUE; /* Ball 'n Stick */ 920 proxyPtr->updatePending = !defer || push; 921 proxyPtr->forceUpdate = push; 922 923 Pymol(proxyPtr, "hide everything,%s\n",model); 924 Pymol(proxyPtr, "set stick_color,white,%s\n",model); 571 925 if (ghost) { 572 926 radius = 0.1f; … … 576 930 transparency = 0.0f; 577 931 } 578 Send(proxyPtr, "set stick_radius,%g,%s\n", radius, model); 579 Send(proxyPtr, "set sphere_scale=0.25,%s\n", model); 580 Send(proxyPtr, "set sphere_transparency,%g,%s\n", transparency, model); 581 Send(proxyPtr, "set stick_transparency,%g,%s\n", transparency, model); 582 Send(proxyPtr, "show sticks,%s\n",model); 583 Send(proxyPtr, "show spheres,%s\n",model); 584 585 if (proxyPtr->labels) 586 Send(proxyPtr, "show labels,%s\n", model); 587 932 Pymol(proxyPtr, "set stick_radius,%g,%s\n", radius, model); 933 #ifdef notdef 934 Pymol(proxyPtr, "set sphere_scale=0.25,%s\n", model); 935 #endif 936 Pymol(proxyPtr, "set sphere_transparency,%g,%s\n", transparency, model); 937 Pymol(proxyPtr, "set stick_transparency,%g,%s\n", transparency, model); 938 Pymol(proxyPtr, "show sticks,%s\n", model); 939 Pymol(proxyPtr, "show spheres,%s\n", model); 940 941 if (proxyPtr->showLabels) { 942 Pymol(proxyPtr, "show labels,%s\n", model); 943 } 588 944 return proxyPtr->status; 589 945 } 590 946 591 static int 592 SpheresCmd(ClientData clientData, Tcl_Interp *interp, int argc, 947 948 static int 949 BmpCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) 950 { 951 char buffer[BUFSIZ]; 952 unsigned int nBytes=0; 953 PymolProxy *proxyPtr = clientData; 954 DyBuffer *imgPtr; 955 int nScanned; 956 size_t length; 957 #ifdef notdef 958 float samples = 10.0; 959 ssize_t nWritten; 960 #endif 961 clear_error(proxyPtr); 962 963 if (proxyPtr->invalidate_cache) 964 proxyPtr->cacheid++; 965 966 proxyPtr->updatePending = FALSE; 967 proxyPtr->forceUpdate = FALSE; 968 proxyPtr->invalidate_cache = FALSE; 969 970 /* Force pymol to update the current scene. */ 971 Pymol(proxyPtr,"refresh\n"); 972 Pymol(proxyPtr,"bmp -\n"); 973 if (Expect(proxyPtr, "image follows: ", buffer, BUFSIZ) != BUFFER_OK) { 974 trace("can't find image follows line (%s)", buffer); 975 } 976 nScanned = sscanf(buffer, "image follows: %d\n", &nBytes); 977 if (nScanned != 1) { 978 trace("can't scan image follows buffer (%s)", buffer); 979 return TCL_ERROR; 980 981 } 982 #ifdef notdef 983 nWritten = write(3,&samples,sizeof(samples)); 984 #endif 985 sprintf(buffer, "nv>image %d %d %d %d\n", nBytes, proxyPtr->cacheid, 986 proxyPtr->frame, proxyPtr->rock_offset); 987 988 length = strlen(buffer); 989 imgPtr = &proxyPtr->image; 990 dyBufferSetLength(imgPtr, nBytes + length); 991 strcpy(imgPtr->data, buffer); 992 if (GetBytes(&proxyPtr->server, imgPtr->data + length, nBytes)!=BUFFER_OK){ 993 trace("can't read %d bytes for \"image follows\" buffer", nBytes); 994 return TCL_ERROR; 995 } 996 imgPtr->bytesLeft = nBytes + length; 997 imgPtr->nWritten = 0; 998 stats.nFrames++; 999 stats.nBytes += nBytes; 1000 return proxyPtr->status; 1001 } 1002 1003 static int 1004 DisableCmd(ClientData clientData, Tcl_Interp *interp, int argc, 593 1005 const char *argv[]) 594 1006 { 595 int defer = 0, ghost = 0, push = 0, arg; 1007 PymolProxy *proxyPtr = clientData; 1008 const char *model = "all"; 1009 int arg, defer = 0, push = 0; 1010 1011 clear_error(proxyPtr); 1012 1013 for(arg = 1; arg < argc; arg++) { 1014 1015 if (strcmp(argv[arg], "-defer") == 0 ) 1016 defer = 1; 1017 else if (strcmp(argv[arg], "-push") == 0 ) 1018 push = 1; 1019 else 1020 model = argv[arg]; 1021 1022 } 1023 1024 proxyPtr->updatePending = !defer || push; 1025 proxyPtr->forceUpdate = push; 1026 proxyPtr->invalidate_cache = TRUE; /* Disable */ 1027 1028 Pymol( proxyPtr, "disable %s\n", model); 1029 1030 return proxyPtr->status; 1031 } 1032 1033 1034 static int 1035 EnableCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1036 const char *argv[]) 1037 { 1038 PymolProxy *proxyPtr = clientData; 1039 const char *model = "all"; 1040 int arg, defer = 0, push = 0; 1041 1042 clear_error(proxyPtr); 1043 1044 for(arg = 1; arg < argc; arg++) { 1045 1046 if (strcmp(argv[arg],"-defer") == 0) 1047 defer = 1; 1048 else if (strcmp(argv[arg], "-push") == 0 ) 1049 push = 1; 1050 else 1051 model = argv[arg]; 1052 1053 } 1054 1055 proxyPtr->updatePending = !defer || push; 1056 proxyPtr->forceUpdate = push; 1057 proxyPtr->invalidate_cache = TRUE; /* Enable */ 1058 1059 Pymol( proxyPtr, "enable %s\n", model); 1060 1061 return proxyPtr->status; 1062 } 1063 1064 static int 1065 FrameCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1066 const char *argv[]) 1067 { 1068 PymolProxy *proxyPtr = clientData; 1069 int frame = 0; 1070 int arg, push = 0, defer = 0; 1071 1072 clear_error(proxyPtr); 1073 1074 for(arg = 1; arg < argc; arg++) { 1075 if ( strcmp(argv[arg],"-defer") == 0 ) 1076 defer = 1; 1077 else if (strcmp(argv[arg],"-push") == 0 ) 1078 push = 1; 1079 else 1080 frame = atoi(argv[arg]); 1081 } 1082 1083 proxyPtr->updatePending = !defer || push; 1084 proxyPtr->forceUpdate = push; 1085 proxyPtr->frame = frame; 1086 1087 /* Does not invalidate cache? */ 1088 1089 Pymol(proxyPtr,"frame %d\n", frame); 1090 1091 return proxyPtr->status; 1092 } 1093 1094 1095 static int 1096 LabelCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1097 const char *argv[]) 1098 { 1099 PymolProxy *proxyPtr = clientData; 1100 int state = 1; 1101 int arg, push = 0, defer = 0; 1102 1103 clear_error(proxyPtr); 1104 1105 for(arg = 1; arg < argc; arg++) { 1106 if ( strcmp(argv[arg],"-defer") == 0 ) 1107 defer = 1; 1108 else if (strcmp(argv[arg],"-push") == 0 ) 1109 push = 1; 1110 else if (strcmp(argv[arg],"on") == 0 ) 1111 state = 1; 1112 else if (strcmp(argv[arg],"off") == 0 ) 1113 state = 0; 1114 else if (strcmp(argv[arg],"toggle") == 0 ) 1115 state = !proxyPtr->showLabels; 1116 } 1117 1118 proxyPtr->updatePending = !defer || push; 1119 proxyPtr->forceUpdate = push; 1120 proxyPtr->invalidate_cache = TRUE; /* Label */ 1121 1122 if (state) { 1123 Pymol(proxyPtr, "set label_color,white,all\n"); 1124 Pymol(proxyPtr, "set label_size,14,all\n"); 1125 Pymol(proxyPtr, "label all,\"%%s%%s\" %% (ID,name)\n"); 1126 } 1127 else 1128 Pymol(proxyPtr, "label all\n"); 1129 1130 proxyPtr->showLabels = state; 1131 1132 return proxyPtr->status; 1133 } 1134 1135 static int 1136 LinesCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1137 const char *argv[]) 1138 { 1139 int ghost = 0, defer = 0, push = 0, arg; 596 1140 const char *model = "all"; 597 1141 PymolProxy *proxyPtr = clientData; 1142 float lineWidth; 598 1143 599 1144 clear_error(proxyPtr); … … 616 1161 } 617 1162 618 proxyPtr->invalidate_cache = 1; 619 proxyPtr->need_update = !defer || push; 620 proxyPtr->immediate_update |= push; 621 622 Send(proxyPtr, "hide everything, %s\n", model); 623 Send(proxyPtr, "set sphere_scale,0.41,%s\n", model); 624 //Send(proxyPtr, "set sphere_quality,2,%s\n", model); 625 Send(proxyPtr, "set ambient,.2,%s\n", model); 626 627 if (ghost) 628 Send(proxyPtr, "set sphere_transparency,.75,%s\n", model); 629 else 630 Send(proxyPtr, "set sphere_transparency,0,%s\n", model); 631 632 Send(proxyPtr, "show spheres,%s\n", model); 633 634 if (proxyPtr->labels) 635 Send(proxyPtr, "show labels,%s\n", model); 636 1163 proxyPtr->invalidate_cache = TRUE; /* Lines */ 1164 proxyPtr->updatePending = !defer || push; 1165 proxyPtr->forceUpdate = push; 1166 1167 Pymol(proxyPtr, "hide everything,%s\n",model); 1168 1169 lineWidth = (ghost) ? 0.25f : 1.0f; 1170 Pymol(proxyPtr, "set line_width,%g,%s\n", lineWidth, model); 1171 Pymol(proxyPtr, "show lines,%s\n", model); 1172 if (proxyPtr->showLabels) { 1173 Pymol(proxyPtr, "show labels,%s\n", model); 1174 } 637 1175 return proxyPtr->status; 638 1176 } 639 1177 640 1178 static int 641 LinesCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1179 LoadPDBCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1180 const char *argv[]) 1181 { 1182 const char *pdbdata, *name; 1183 PymolProxy *proxyPtr = clientData; 1184 int state = 1; 1185 int arg, defer = 0, push = 0, varg = 1; 1186 1187 if (proxyPtr == NULL) 1188 return TCL_ERROR; 1189 clear_error(proxyPtr); 1190 pdbdata = name = NULL; /* Suppress compiler warning. */ 1191 for(arg = 1; arg < argc; arg++) { 1192 if ( strcmp(argv[arg],"-defer") == 0 ) 1193 defer = 1; 1194 else if (strcmp(argv[arg],"-push") == 0) 1195 push = 1; 1196 else if (varg == 1) { 1197 pdbdata = argv[arg]; 1198 varg++; 1199 } else if (varg == 2) { 1200 name = argv[arg]; 1201 varg++; 1202 } else if (varg == 3) { 1203 state = atoi( argv[arg] ); 1204 varg++; 1205 } 1206 } 1207 1208 proxyPtr->updatePending = !defer || push; 1209 proxyPtr->forceUpdate = push; 1210 1211 /* Does not invalidate cache? */ 1212 1213 { 1214 char fileName[200]; 1215 FILE *f; 1216 size_t nBytes; 1217 ssize_t nWritten; 1218 1219 sprintf(fileName, "/tmp/pymol%d.pdb", getpid()); 1220 f = fopen(fileName, "w"); 1221 if (f == NULL) { 1222 trace("can't open `%s': %s", fileName, strerror(errno)); 1223 perror("pymolproxy"); 1224 } 1225 nBytes = strlen(pdbdata); 1226 nWritten = fwrite(pdbdata, sizeof(char), nBytes, f); 1227 if (nBytes != nWritten) { 1228 trace("short write %d wanted %d bytes", nWritten, nBytes); 1229 perror("pymolproxy"); 1230 } 1231 fclose(f); 1232 Pymol(proxyPtr, "load %s, %s, %d\n", fileName, name, state); 1233 Pymol(proxyPtr, "zoom complete=1\n"); 1234 } 1235 return proxyPtr->status; 1236 } 1237 1238 static int 1239 OrthoscopicCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1240 const char *argv[]) 1241 { 1242 int bool, defer, push, i; 1243 PymolProxy *proxyPtr = clientData; 1244 1245 clear_error(proxyPtr); 1246 defer = push = FALSE; 1247 bool = FALSE; 1248 for(i = 1; i < argc; i++) { 1249 if (strcmp(argv[i],"-defer") == 0) { 1250 defer = TRUE; 1251 } else if (strcmp(argv[i],"-push") == 0) { 1252 push = TRUE; 1253 } else { 1254 if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) { 1255 return TCL_ERROR; 1256 } 1257 } 1258 } 1259 proxyPtr->invalidate_cache = TRUE; 1260 proxyPtr->updatePending = !defer || push; 1261 proxyPtr->forceUpdate = push; 1262 Pymol(proxyPtr, "set orthoscopic=%d\n", bool); 1263 return proxyPtr->status; 1264 } 1265 1266 /* 1267 * PanCmd -- 1268 * 1269 * Issue "move" commands for changes in the x and y coordinates of the 1270 * camera. The problem here is that there is no event compression. 1271 * Consecutive "pan" commands are not compressed into a single 1272 * directive. The means that the pymol server will render scenes that 1273 * are not used by the client. 1274 * 1275 * Need to 1) defer the "move" commands until we find the next command 1276 * isn't a "pan". 2) Track the x and y coordinates as they are 1277 * compressed. 1278 */ 1279 static int 1280 PanCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1281 const char *argv[]) 1282 { 1283 PymolProxy *proxyPtr = clientData; 1284 double x, y; 1285 int i; 1286 int defer, push; 1287 1288 clear_error(proxyPtr); 1289 defer = push = FALSE; 1290 for (i = 1; i < argc; i++) { 1291 if (strcmp(argv[i],"-defer") == 0) { 1292 defer = 1; 1293 } else if (strcmp(argv[i],"-push") == 0) { 1294 push = 1; 1295 } else { 1296 break; 1297 } 1298 } 1299 if ((Tcl_GetDouble(interp, argv[i], &x) != TCL_OK) || 1300 (Tcl_GetDouble(interp, argv[i+1], &y) != TCL_OK)) { 1301 return TCL_ERROR; 1302 } 1303 proxyPtr->updatePending = !defer || push; 1304 proxyPtr->forceUpdate = push; 1305 proxyPtr->invalidate_cache = TRUE; /* Pan */ 1306 1307 if ((x != 0.0f) || (y != 0.0f)) { 1308 /* Every pymol command line generates a new rendering. Execute both 1309 * moves as a single command line. */ 1310 Pymol(proxyPtr,"move x,%f; move y,%f\n", x * 0.05, -y * 0.05); 1311 } 1312 return proxyPtr->status; 1313 } 1314 1315 static int 1316 PngCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) 1317 { 1318 char buffer[800]; 1319 unsigned int nBytes=0; 1320 PymolProxy *proxyPtr = clientData; 1321 #ifdef notdef 1322 float samples = 10.0; 1323 ssize_t nWritten; 1324 #endif 1325 clear_error(proxyPtr); 1326 1327 if (proxyPtr->invalidate_cache) 1328 proxyPtr->cacheid++; 1329 1330 proxyPtr->updatePending = FALSE; 1331 proxyPtr->forceUpdate = FALSE; 1332 proxyPtr->invalidate_cache = FALSE; 1333 1334 /* Force pymol to update the current scene. */ 1335 Pymol(proxyPtr,"refresh\n"); 1336 1337 Pymol(proxyPtr,"png -\n"); 1338 1339 Expect(proxyPtr, "image follows: ", buffer, 800); 1340 1341 sscanf(buffer, "image follows: %d\n", &nBytes); 1342 1343 #ifdef notdef 1344 nWritten = write(3, &samples, sizeof(samples)); 1345 #endif 1346 dyBufferSetLength(&proxyPtr->image, nBytes); 1347 1348 bread(proxyPtr->serverOutput, proxyPtr->image.data, proxyPtr->image.used); 1349 proxyPtr->image.bytesLeft = proxyPtr->image.used; 1350 proxyPtr->image.nWritten = 0; 1351 1352 Expect(proxyPtr, " ScenePNG", buffer,800); 1353 1354 if ((nBytes > 0) && (proxyPtr->image.used == nBytes)) { 1355 ssize_t nWritten; 1356 1357 sprintf(buffer, "nv>image %d %d %d %d\n", 1358 nBytes, proxyPtr->cacheid, proxyPtr->frame, proxyPtr->rock_offset); 1359 trace("to-molvis> %s", buffer); 1360 /* Write the header */ 1361 nWritten = write(proxyPtr->clientInput, buffer, strlen(buffer)); 1362 /* and the data. */ 1363 bwrite(proxyPtr->clientInput, proxyPtr->image.data, nBytes); 1364 1365 stats.nFrames++; 1366 stats.nBytes += nBytes; 1367 } 1368 return proxyPtr->status; 1369 } 1370 1371 static int 1372 RawCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) 1373 { 1374 PymolProxy *proxyPtr = clientData; 1375 DyBuffer buffer; 1376 int arg, defer = 0, push = 0; 1377 const char *cmd; 1378 clear_error(proxyPtr); 1379 1380 dyBufferInit(&buffer); 1381 1382 cmd = NULL; 1383 for(arg = 1; arg < argc; arg++) { 1384 if (strcmp(argv[arg], "-defer") == 0) 1385 defer = 1; 1386 else if (strcmp(argv[arg], "-push") == 0) 1387 push = 1; 1388 else { 1389 cmd = argv[arg]; 1390 } 1391 } 1392 1393 proxyPtr->updatePending = !defer || push; 1394 proxyPtr->forceUpdate = push; 1395 proxyPtr->invalidate_cache = TRUE; /* Raw */ 1396 1397 Pymol(proxyPtr,"%s\n", cmd); 1398 dyBufferFree(&buffer); 1399 1400 return proxyPtr->status; 1401 } 1402 1403 static int 1404 ResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, 642 1405 const char *argv[]) 643 1406 { 644 int ghost = 0, defer = 0, push = 0, arg;645 const char *model = "all";646 1407 PymolProxy *proxyPtr = clientData; 647 float lineWidth;1408 int arg, push = 0, defer = 0; 648 1409 649 1410 clear_error(proxyPtr); … … 652 1413 if ( strcmp(argv[arg],"-defer") == 0 ) 653 1414 defer = 1; 654 else if (strcmp(argv[arg],"-push") == 0 )1415 else if (strcmp(argv[arg],"-push") == 0 ) 655 1416 push = 1; 656 else if (strcmp(argv[arg],"-ghost") == 0) 1417 } 1418 1419 proxyPtr->updatePending = !defer || push; 1420 proxyPtr->forceUpdate = push; 1421 proxyPtr->invalidate_cache = TRUE; /* Reset */ 1422 1423 Pymol(proxyPtr, "reset\n"); 1424 Pymol(proxyPtr, "zoom complete=1\n"); 1425 1426 return proxyPtr->status; 1427 } 1428 1429 static int 1430 RockCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1431 const char *argv[]) 1432 { 1433 PymolProxy *proxyPtr = clientData; 1434 float y = 0.0; 1435 int arg, push = 0, defer = 0; 1436 1437 clear_error(proxyPtr); 1438 1439 for(arg = 1; arg < argc; arg++) { 1440 if ( strcmp(argv[arg],"-defer") == 0 ) 1441 defer = 1; 1442 else if (strcmp(argv[arg],"-push") == 0 ) 1443 push = 1; 1444 else 1445 y = atof( argv[arg] ); 1446 } 1447 1448 /* Does not invalidate cache. */ 1449 1450 proxyPtr->updatePending = !defer || push; 1451 proxyPtr->forceUpdate = push; 1452 1453 Pymol(proxyPtr,"turn y, %f\n", y - proxyPtr->rock_offset); 1454 1455 proxyPtr->rock_offset = y; 1456 1457 return proxyPtr->status; 1458 } 1459 1460 /* 1461 * RotateCmd -- 1462 * 1463 * Issue "turn" commands for changes in the angle of the camera. The 1464 * problem here is that there is no event compression. Consecutive 1465 * "rotate" commands are not compressed into a single directive. The 1466 * means that the pymol server will render many scene that are not used 1467 * by the client. 1468 * 1469 * Need to 1) defer the "turn" commands until we find the next command 1470 * isn't a "rotate". 2) Track the rotation angles as they are compressed. 1471 */ 1472 static int 1473 RotateCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1474 const char *argv[]) 1475 { 1476 float xAngle, yAngle, zAngle; 1477 PymolProxy *proxyPtr = clientData; 1478 int defer = 0, push = 0, arg, varg = 1; 1479 1480 clear_error(proxyPtr); 1481 1482 xAngle = yAngle = zAngle = 0.0f; 1483 for(arg = 1; arg < argc; arg++) { 1484 if (strcmp(argv[arg],"-defer") == 0) { 1485 defer = 1; 1486 } else if (strcmp(argv[arg],"-push") == 0) { 1487 push = 1; 1488 } else if (varg == 1) { 1489 double value; 1490 if (Tcl_GetDouble(interp, argv[arg], &value) != TCL_OK) { 1491 return TCL_ERROR; 1492 } 1493 xAngle = (float)value; 1494 varg++; 1495 } else if (varg == 2) { 1496 double value; 1497 if (Tcl_GetDouble(interp, argv[arg], &value) != TCL_OK) { 1498 return TCL_ERROR; 1499 } 1500 yAngle = (float)value; 1501 varg++; 1502 } else if (varg == 3) { 1503 double value; 1504 if (Tcl_GetDouble(interp, argv[arg], &value) != TCL_OK) { 1505 return TCL_ERROR; 1506 } 1507 zAngle = (float)value; 1508 varg++; 1509 } 1510 } 1511 proxyPtr->updatePending = !defer || push; 1512 proxyPtr->forceUpdate = push; 1513 proxyPtr->invalidate_cache = TRUE; /* Rotate */ 1514 1515 if ((xAngle != 0.0f) || (yAngle != 0.0f) || (zAngle != 0.0f)) { 1516 proxyPtr->xAngle += xAngle; 1517 proxyPtr->yAngle += yAngle; 1518 proxyPtr->zAngle += zAngle; 1519 proxyPtr->rotatePending = TRUE; 1520 } 1521 return proxyPtr->status; 1522 } 1523 1524 static int 1525 SpheresCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1526 const char *argv[]) 1527 { 1528 int defer = 0, ghost = 0, push = 0, arg; 1529 float scale; 1530 const char *model = "all"; 1531 PymolProxy *proxyPtr = clientData; 1532 1533 clear_error(proxyPtr); 1534 scale = 0.41f; 1535 for(arg = 1; arg < argc; arg++) { 1536 if ( strcmp(argv[arg],"-defer") == 0 ) { 1537 defer = 1; 1538 } else if (strcmp(argv[arg],"-push") == 0) { 1539 push = 1; 1540 } else if (strcmp(argv[arg],"-ghost") == 0) { 657 1541 ghost = 1; 658 else if (strcmp(argv[arg],"-normal") == 0) 1542 } else if (strcmp(argv[arg],"-normal") == 0) { 659 1543 ghost = 0; 660 1544 } else if (strcmp(argv[arg],"-model") == 0) { 661 1545 if (++arg < argc) 662 1546 model = argv[arg]; 1547 } else if (strcmp(argv[arg],"-scale") == 0) { 1548 if (++arg < argc) 1549 scale = atof(argv[arg]); 663 1550 } 664 1551 else … … 666 1553 } 667 1554 668 proxyPtr->invalidate_cache = 1; 669 proxyPtr->need_update = !defer || push; 670 proxyPtr->immediate_update |= push; 671 672 Send(proxyPtr, "hide everything,%s\n",model); 673 674 lineWidth = (ghost) ? 0.25f : 1.0f; 675 Send(proxyPtr, "set line_width,%g,%s\n", lineWidth, model); 676 Send(proxyPtr, "show lines,%s\n",model); 677 if (proxyPtr->labels) 678 Send(proxyPtr, "show labels,%s\n",model); 679 1555 proxyPtr->invalidate_cache = TRUE; /* Spheres */ 1556 proxyPtr->updatePending = !defer || push; 1557 proxyPtr->forceUpdate = push; 1558 1559 Pymol(proxyPtr, "hide everything, %s\n", model); 1560 #ifdef notdef 1561 Pymol(proxyPtr, "set sphere_scale,%f,%s\n", scale, model); 1562 #endif 1563 //Pymol(proxyPtr, "set sphere_quality,2,%s\n", model); 1564 Pymol(proxyPtr, "set ambient,.2,%s\n", model); 1565 1566 if (ghost) 1567 Pymol(proxyPtr, "set sphere_transparency,.75,%s\n", model); 1568 else 1569 Pymol(proxyPtr, "set sphere_transparency,0,%s\n", model); 1570 1571 Pymol(proxyPtr, "show spheres,%s\n", model); 1572 1573 if (proxyPtr->showLabels) { 1574 Pymol(proxyPtr, "show labels,%s\n", model); 1575 } 680 1576 return proxyPtr->status; 681 1577 } 682 1578 683 1579 static int 684 DisableCmd(ClientData clientData, Tcl_Interp *interp, int argc,685 1580 ScreenCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1581 const char *argv[]) 686 1582 { 687 1583 PymolProxy *proxyPtr = clientData; 688 const char *model = "all";689 int arg, defer = 0, push = 0;1584 int width = 640, height = 480; 1585 int defer = 0, push = 0, arg, varg = 1; 690 1586 691 1587 clear_error(proxyPtr); 692 1588 693 1589 for(arg = 1; arg < argc; arg++) { 694 695 if (strcmp(argv[arg], "-defer") == 0 ) 1590 if ( strcmp(argv[arg],"-defer") == 0 ) 696 1591 defer = 1; 697 else if ( strcmp(argv[arg], "-push") == 0 )1592 else if ( strcmp(argv[arg], "-push") == 0 ) 698 1593 push = 1; 699 else 700 model = argv[arg]; 1594 else if (varg == 1) { 1595 width = atoi(argv[arg]); 1596 height = width; 1597 varg++; 1598 } 1599 else if (varg == 2) { 1600 height = atoi(argv[arg]); 1601 varg++; 1602 } 1603 } 1604 1605 proxyPtr->updatePending = !defer || push; 1606 proxyPtr->forceUpdate = push; 1607 proxyPtr->invalidate_cache = TRUE; /* viewport */ 1608 1609 Pymol(proxyPtr, "viewport %d,%d\n", width, height); 1610 1611 //usleep(205000); // .2s delay for pymol to update its geometry *HACK ALERT* 701 1612 702 }703 704 proxyPtr->need_update = !defer || push;705 proxyPtr->immediate_update |= push;706 proxyPtr->invalidate_cache = 1;707 708 Send( proxyPtr, "disable %s\n", model);709 710 return proxyPtr->status;711 }712 713 static int714 EnableCmd(ClientData clientData, Tcl_Interp *interp, int argc,715 const char *argv[])716 {717 PymolProxy *proxyPtr = clientData;718 const char *model = "all";719 int arg, defer = 0, push = 0;720 721 clear_error(proxyPtr);722 723 for(arg = 1; arg < argc; arg++) {724 725 if (strcmp(argv[arg],"-defer") == 0)726 defer = 1;727 else if (strcmp(argv[arg], "-push") == 0 )728 push = 1;729 else730 model = argv[arg];731 732 }733 734 proxyPtr->need_update = !defer || push;735 proxyPtr->immediate_update |= push;736 proxyPtr->invalidate_cache = 1;737 738 Send( proxyPtr, "enable %s\n", model);739 740 1613 return proxyPtr->status; 741 1614 } … … 778 1651 } 779 1652 780 proxyPtr-> need_update= !defer || push;781 proxyPtr-> immediate_update |= push;782 proxyPtr->invalidate_cache = 1;783 784 Send(proxyPtr, "vmouse %d,%d,%d,%d,%d\n", arg1, arg2, arg3,1653 proxyPtr->updatePending = !defer || push; 1654 proxyPtr->forceUpdate = push; 1655 proxyPtr->invalidate_cache = TRUE; /* vmouse */ 1656 1657 Pymol(proxyPtr, "vmouse %d,%d,%d,%d,%d\n", arg1, arg2, arg3, 785 1658 arg4, arg5); 786 1659 … … 788 1661 } 789 1662 790 static int 791 RawCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) 792 { 793 PymolProxy *proxyPtr = clientData; 794 DyBuffer buffer; 795 int arg, defer = 0, push = 0; 796 const char *cmd; 797 clear_error(proxyPtr); 798 799 dyBufferInit(&buffer); 800 801 cmd = NULL; 802 for(arg = 1; arg < argc; arg++) { 803 if (strcmp(argv[arg], "-defer") == 0) 804 defer = 1; 805 else if (strcmp(argv[arg], "-push") == 0) 806 push = 1; 807 else { 808 cmd = argv[arg]; 809 } 810 } 811 812 proxyPtr->need_update = !defer || push; 813 proxyPtr->immediate_update |= push; 814 proxyPtr->invalidate_cache = 1; 815 816 Send(proxyPtr,"%s\n", cmd); 817 dyBufferFree(&buffer); 818 819 return proxyPtr->status; 820 } 821 822 static int 823 LabelCmd(ClientData clientData, Tcl_Interp *interp, int argc, 824 const char *argv[]) 825 { 826 PymolProxy *proxyPtr = clientData; 827 int state = 1; 828 int arg, push = 0, defer = 0; 829 830 clear_error(proxyPtr); 831 832 for(arg = 1; arg < argc; arg++) { 833 if ( strcmp(argv[arg],"-defer") == 0 ) 834 defer = 1; 835 else if (strcmp(argv[arg],"-push") == 0 ) 836 push = 1; 837 else if (strcmp(argv[arg],"on") == 0 ) 838 state = 1; 839 else if (strcmp(argv[arg],"off") == 0 ) 840 state = 0; 841 else if (strcmp(argv[arg],"toggle") == 0 ) 842 state = !proxyPtr->labels; 843 } 844 845 proxyPtr->need_update = !defer || push; 846 proxyPtr->immediate_update |= push; 847 proxyPtr->invalidate_cache = 1; 848 849 if (state) { 850 Send(proxyPtr, "set label_color,white,all\n"); 851 Send(proxyPtr, "set label_size,14,all\n"); 852 Send(proxyPtr, "label all,\"%%s%%s\" %% (ID,name)\n"); 853 } 854 else 855 Send(proxyPtr, "label all\n"); 856 857 proxyPtr->labels = state; 858 859 return proxyPtr->status; 860 } 861 862 static int 863 FrameCmd(ClientData clientData, Tcl_Interp *interp, int argc, 864 const char *argv[]) 865 { 866 PymolProxy *proxyPtr = clientData; 867 int frame = 0; 868 int arg, push = 0, defer = 0; 869 870 clear_error(proxyPtr); 871 872 for(arg = 1; arg < argc; arg++) { 873 if ( strcmp(argv[arg],"-defer") == 0 ) 874 defer = 1; 875 else if (strcmp(argv[arg],"-push") == 0 ) 876 push = 1; 877 else 878 frame = atoi(argv[arg]); 879 } 880 881 proxyPtr->need_update = !defer || push; 882 proxyPtr->immediate_update |= push; 883 884 proxyPtr->frame = frame; 885 886 Send(proxyPtr,"frame %d\n", frame); 887 888 return proxyPtr->status; 889 } 890 891 static int 892 ResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, 893 const char *argv[]) 894 { 895 PymolProxy *proxyPtr = clientData; 896 int arg, push = 0, defer = 0; 897 898 clear_error(proxyPtr); 899 900 for(arg = 1; arg < argc; arg++) { 901 if ( strcmp(argv[arg],"-defer") == 0 ) 902 defer = 1; 903 else if (strcmp(argv[arg],"-push") == 0 ) 904 push = 1; 905 } 906 907 proxyPtr->need_update = !defer || push; 908 proxyPtr->immediate_update |= push; 909 proxyPtr->invalidate_cache = 1; 910 911 Send(proxyPtr, "reset\n"); 912 Send(proxyPtr, "zoom buffer=2\n"); 913 914 return proxyPtr->status; 915 } 916 917 static int 918 RockCmd(ClientData clientData, Tcl_Interp *interp, int argc, 919 const char *argv[]) 920 { 921 PymolProxy *proxyPtr = clientData; 922 float y = 0.0; 923 int arg, push = 0, defer = 0; 924 925 clear_error(proxyPtr); 926 927 for(arg = 1; arg < argc; arg++) { 928 if ( strcmp(argv[arg],"-defer") == 0 ) 929 defer = 1; 930 else if (strcmp(argv[arg],"-push") == 0 ) 931 push = 1; 932 else 933 y = atof( argv[arg] ); 934 } 935 936 proxyPtr->need_update = !defer || push; 937 proxyPtr->immediate_update |= push; 938 939 Send(proxyPtr,"turn y, %f\n", y - proxyPtr->rock_offset); 940 941 proxyPtr->rock_offset = y; 942 943 return proxyPtr->status; 944 } 945 946 static int 947 ViewportCmd(ClientData clientData, Tcl_Interp *interp, int argc, 948 const char *argv[]) 949 { 950 PymolProxy *proxyPtr = clientData; 951 int width = 640, height = 480; 952 int defer = 0, push = 0, arg, varg = 1; 953 954 clear_error(proxyPtr); 955 956 for(arg = 1; arg < argc; arg++) { 957 if ( strcmp(argv[arg],"-defer") == 0 ) 958 defer = 1; 959 else if ( strcmp(argv[arg], "-push") == 0 ) 960 push = 1; 961 else if (varg == 1) { 962 width = atoi(argv[arg]); 963 height = width; 964 varg++; 965 } 966 else if (varg == 2) { 967 height = atoi(argv[arg]); 968 varg++; 969 } 970 } 971 972 proxyPtr->need_update = !defer || push; 973 proxyPtr->immediate_update |= push; 974 proxyPtr->invalidate_cache = 1; 975 976 Send(proxyPtr, "viewport %d,%d\n", width, height); 977 978 //usleep(205000); // .2s delay for pymol to update its geometry *HACK ALERT* 979 980 return proxyPtr->status; 981 } 982 983 static int 984 LoadPDBCmd(ClientData clientData, Tcl_Interp *interp, int argc, 985 const char *argv[]) 986 { 987 const char *pdbdata, *name; 988 PymolProxy *proxyPtr = clientData; 989 int state = 1; 990 int arg, defer = 0, push = 0, varg = 1; 991 992 if (proxyPtr == NULL) 993 return TCL_ERROR; 994 clear_error(proxyPtr); 995 pdbdata = name = NULL; /* Suppress compiler warning. */ 996 for(arg = 1; arg < argc; arg++) { 997 if ( strcmp(argv[arg],"-defer") == 0 ) 998 defer = 1; 999 else if (strcmp(argv[arg],"-push") == 0) 1000 push = 1; 1001 else if (varg == 1) { 1002 pdbdata = argv[arg]; 1003 varg++; 1004 } else if (varg == 2) { 1005 name = argv[arg]; 1006 varg++; 1007 } else if (varg == 3) { 1008 state = atoi( argv[arg] ); 1009 varg++; 1010 } 1011 } 1012 1013 proxyPtr->need_update = !defer || push; 1014 proxyPtr->immediate_update |= push; 1015 1016 { 1017 char fileName[200]; 1018 FILE *f; 1019 ssize_t nBytes, nWritten; 1020 1021 sprintf(fileName, "/tmp/pymol%d.pdb", getpid()); 1022 f = fopen(fileName, "w"); 1023 if (f == NULL) { 1024 trace("can't open `%s': %s", fileName, strerror(errno)); 1025 perror("pymolproxy"); 1026 } 1027 nBytes = strlen(pdbdata); 1028 nWritten = fwrite(pdbdata, sizeof(char), nBytes, f); 1029 if (nBytes != nWritten) { 1030 trace("short write %d wanted %d bytes", nWritten, nBytes); 1031 perror("pymolproxy"); 1032 } 1033 fclose(f); 1034 Send(proxyPtr, "load %s, %s, %d\n", fileName, name, state); 1035 } 1036 Send(proxyPtr, "zoom buffer=2\n"); 1037 return proxyPtr->status; 1038 } 1039 1040 static int 1041 RotateCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1042 const char *argv[]) 1043 { 1044 double turnx = 0.0; 1045 double turny = 0.0; 1046 double turnz = 0.0; 1047 PymolProxy *proxyPtr = clientData; 1048 int defer = 0, push = 0, arg, varg = 1; 1049 1050 clear_error(proxyPtr); 1051 1052 for(arg = 1; arg < argc; arg++) { 1053 if (strcmp(argv[arg],"-defer") == 0) { 1054 defer = 1; 1055 } else if (strcmp(argv[arg],"-push") == 0) { 1056 push = 1; 1057 } else if (varg == 1) { 1058 turnx = atof(argv[arg]); 1059 varg++; 1060 } else if (varg == 2) { 1061 turny = atof(argv[arg]); 1062 varg++; 1063 } else if (varg == 3) { 1064 turnz = atof(argv[arg]); 1065 varg++; 1066 } 1067 } 1068 proxyPtr->need_update = !defer || push; 1069 proxyPtr->immediate_update |= push; 1070 proxyPtr->invalidate_cache = 1; 1071 1072 if (turnx != 0.0) 1073 Send(proxyPtr,"turn x, %f\n", turnx); 1074 1075 if (turny != 0.0) 1076 Send(proxyPtr,"turn y, %f\n", turny); 1077 1078 if (turnz != 0.0) 1079 Send(proxyPtr,"turn z, %f\n", turnz); 1080 1081 return proxyPtr->status; 1082 } 1083 1084 static int 1085 ZoomCmd(ClientData clientData, Tcl_Interp *interp, int argc, 1086 const char *argv[]) 1663 1664 /* 1665 * ZoomCmd -- 1666 * 1667 * Issue "move" commands for changes in the z-coordinate of the camera. 1668 * The problem here is that there is no event compression. Consecutive 1669 * "zoom" commands are not compressed into a single directive. The means 1670 * that the pymol server will render scenes that are not used by the 1671 * client. 1672 * 1673 * Need to 1) defer the "move" commands until we find the next command 1674 * isn't a "zoom". 2) Track the z-coordinate as they are compressed. 1675 */ 1676 static int 1677 ZoomCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) 1087 1678 { 1088 1679 double factor = 0.0; … … 1098 1689 push = 1; 1099 1690 else if (varg == 1) { 1100 factor = atof(argv[arg]); 1691 double value; 1692 if (Tcl_GetDouble(interp, argv[arg], &value) != TCL_OK) { 1693 return TCL_ERROR; 1694 } 1695 factor = (float)value; 1101 1696 varg++; 1102 1697 } 1103 1698 } 1104 proxyPtr->need_update = !defer || push; 1105 proxyPtr->immediate_update |= push; 1106 proxyPtr->invalidate_cache = 1; 1699 proxyPtr->updatePending = !defer || push; 1700 proxyPtr->forceUpdate = push; 1701 proxyPtr->invalidate_cache = TRUE; /* Zoom */ 1702 1107 1703 if (factor != 0.0) { 1108 Send(proxyPtr,"move z,%f\n", factor);1704 Pymol(proxyPtr,"move z,%f\n", factor); 1109 1705 } 1110 1706 return proxyPtr->status; 1111 1707 } 1112 1708 1113 static int1114 PanCmd(ClientData clientData, Tcl_Interp *interp, int argc,1115 const char *argv[])1116 {1117 PymolProxy *proxyPtr = clientData;1118 double x, y;1119 int i;1120 int defer, push;1121 1122 clear_error(proxyPtr);1123 defer = push = FALSE;1124 for (i = 1; i < argc; i++) {1125 if (strcmp(argv[i],"-defer") == 0) {1126 defer = 1;1127 } else if (strcmp(argv[i],"-push") == 0) {1128 push = 1;1129 } else {1130 break;1131 }1132 }1133 if ((Tcl_GetDouble(interp, argv[i], &x) != TCL_OK) ||1134 (Tcl_GetDouble(interp, argv[i+1], &y) != TCL_OK)) {1135 return TCL_ERROR;1136 }1137 proxyPtr->need_update = !defer || push;1138 proxyPtr->immediate_update |= push;1139 proxyPtr->invalidate_cache = 1;1140 if (x != 0.0) {1141 Send(proxyPtr,"move x,%f\n", x * 0.05);1142 }1143 if (y != 0.0) {1144 Send(proxyPtr,"move y,%f\n", -y * 0.05);1145 }1146 return proxyPtr->status;1147 }1148 1149 static int1150 PNGCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])1151 {1152 char buffer[800];1153 unsigned int nBytes=0;1154 float samples = 10.0;1155 PymolProxy *proxyPtr = clientData;1156 1157 clear_error(proxyPtr);1158 1159 if (proxyPtr->invalidate_cache)1160 proxyPtr->cacheid++;1161 1162 proxyPtr->need_update = 0;1163 proxyPtr->immediate_update = 0;1164 proxyPtr->invalidate_cache = 0;1165 1166 Send(proxyPtr,"png -\n");1167 1168 Expect(proxyPtr, "image follows: ", buffer, 800);1169 1170 sscanf(buffer, "image follows: %d\n", &nBytes);1171 1172 write(3, &samples, sizeof(samples));1173 1174 dyBufferSetLength(&proxyPtr->image, nBytes);1175 1176 bread(proxyPtr->p_stdout, proxyPtr->image.data, proxyPtr->image.used);1177 1178 Expect(proxyPtr, " ScenePNG", buffer,800);1179 1180 if ((nBytes > 0) && (proxyPtr->image.used == nBytes)) {1181 sprintf(buffer, "nv>image %d %d %d %d\n",1182 nBytes, proxyPtr->cacheid, proxyPtr->frame, proxyPtr->rock_offset);1183 trace("to-molvis> %s", buffer);1184 write(proxyPtr->c_stdin, buffer, strlen(buffer));1185 bwrite(proxyPtr->c_stdin, proxyPtr->image.data, nBytes);1186 stats.nFrames++;1187 stats.nBytes += nBytes;1188 }1189 return proxyPtr->status;1190 }1191 1192 static int1193 BMPCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])1194 {1195 char buffer[800];1196 unsigned int nBytes=0;1197 float samples = 10.0;1198 PymolProxy *proxyPtr = clientData;1199 1200 clear_error(proxyPtr);1201 1202 if (proxyPtr->invalidate_cache)1203 proxyPtr->cacheid++;1204 1205 proxyPtr->need_update = 0;1206 proxyPtr->immediate_update = 0;1207 proxyPtr->invalidate_cache = 0;1208 1209 Send(proxyPtr,"bmp -\n");1210 1211 Expect(proxyPtr, "image follows: ", buffer, 800);1212 1213 sscanf(buffer, "image follows: %d\n", &nBytes);1214 write(3,&samples,sizeof(samples));1215 1216 dyBufferSetLength(&proxyPtr->image, nBytes);1217 1218 bread(proxyPtr->p_stdout, proxyPtr->image.data, proxyPtr->image.used);1219 1220 if ((nBytes > 0) && (proxyPtr->image.used == nBytes)) {1221 sprintf(buffer, "nv>image %d %d %d %d\n",1222 nBytes, proxyPtr->cacheid, proxyPtr->frame, proxyPtr->rock_offset);1223 write(proxyPtr->c_stdin, buffer, strlen(buffer));1224 trace("to-molvis buffer=%s", buffer);1225 bwrite(proxyPtr->c_stdin, proxyPtr->image.data, nBytes);1226 stats.nFrames++;1227 stats.nBytes += nBytes;1228 }1229 return proxyPtr->status;1230 }1231 1709 1232 1710 static int 1233 1711 ProxyInit(int c_in, int c_out, char *const *argv) 1234 1712 { 1235 int flags,status, result = 0;1236 int pairIn[2];1237 int pairOut[2];1238 int pairErr[2];1713 int status, result = 0; 1714 int serverIn[2]; 1715 int serverOut[2]; 1716 int serverErr[2]; 1239 1717 Tcl_Interp *interp; 1240 Tcl_DString cmdbuffer; 1241 DyBuffer dybuffer, dybuffer2; 1242 struct pollfd ufd[3]; 1243 int pid; 1718 int child; 1244 1719 PymolProxy proxy; 1245 struct timeval now, end; 1246 int timeout; 1720 struct timeval end; 1247 1721 1248 1722 /* Create three pipes for communication with the external application. One 1249 1723 * each for the applications's: stdin, stdout, and stderr */ 1250 1724 1251 if (pipe( pairIn) == -1)1725 if (pipe(serverIn) == -1) 1252 1726 return -1; 1253 1727 1254 if (pipe( pairOut) == -1) {1255 close( pairIn[0]);1256 close( pairIn[1]);1728 if (pipe(serverOut) == -1) { 1729 close(serverIn[0]); 1730 close(serverIn[1]); 1257 1731 return -1; 1258 1732 } 1259 1733 1260 if (pipe( pairErr) == -1) {1261 close( pairIn[0]);1262 close( pairIn[1]);1263 close( pairOut[0]);1264 close( pairOut[1]);1734 if (pipe(serverErr) == -1) { 1735 close(serverIn[0]); 1736 close(serverIn[1]); 1737 close(serverOut[0]); 1738 close(serverOut[1]); 1265 1739 return -1; 1266 1740 } … … 1268 1742 /* Fork the new process. Connect i/o to the new socket. */ 1269 1743 1270 pid = fork();1744 child = fork(); 1271 1745 1272 if ( pid < 0) {1746 if (child < 0) { 1273 1747 fprintf(stderr, "can't fork process: %s\n", strerror(errno)); 1274 1748 return -3; 1275 1749 } 1276 if ( pid == 0) {1277 int f d;1750 if (child == 0) { 1751 int f; 1278 1752 1279 1753 /* Child process */ … … 1284 1758 * one. 1285 1759 */ 1286 setpgid( pid, 0);1760 setpgid(child, 0); 1287 1761 1288 1762 /* Redirect stdin, stdout, and stderr to pipes before execing */ 1289 dup2(pairIn[0] ,0); // stdin 1290 dup2(pairOut[1],1); // stdout 1291 dup2(pairErr[1],2); // stderr 1763 1764 dup2(serverIn[0], 0); // stdin 1765 dup2(serverOut[1],1); // stdout 1766 dup2(serverErr[1],2); // stderr 1292 1767 1293 for(fd = 3; fd < FD_SETSIZE; fd++) /* close all other descriptors */ 1294 close(fd); 1768 /* Close all other descriptors */ 1769 for (f = 3; f < FD_SETSIZE; f++) { 1770 close(f); 1771 } 1295 1772 1296 1773 execvp(argv[0], argv); … … 1298 1775 exit(-1); 1299 1776 } 1300 stats.child = pid; 1301 1302 /* close opposite end of pipe, these now belong to the child process */ 1303 close(pairIn[0]); 1304 close(pairOut[1]); 1305 close(pairErr[1]); 1306 1307 signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE (ie if nanoscale terminates) 1308 1309 proxy.p_stdin = pairIn[1]; 1310 proxy.p_stdout = pairOut[0]; 1311 proxy.p_stderr = pairErr[0]; 1312 proxy.c_stdin = c_in; 1313 proxy.c_stdout = c_out; 1314 proxy.labels = 0; 1315 proxy.need_update = 0; 1316 proxy.can_update = 1; 1317 proxy.immediate_update = 0; 1777 stats.child = child; 1778 1779 /* close opposite end of pipe, these now belong to the child process */ 1780 close(serverIn[0]); 1781 close(serverOut[1]); 1782 close(serverErr[1]); 1783 1784 signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE (e.g. nanoscale terminates)*/ 1785 1786 proxy.serverInput = serverIn[1]; 1787 proxy.serverOutput = serverOut[0]; 1788 proxy.serverError = serverErr[0]; 1789 proxy.clientInput = c_in; 1790 proxy.clientOutput = c_out; 1791 proxy.showLabels = FALSE; 1792 proxy.updatePending = FALSE; 1793 proxy.forceUpdate = FALSE; 1794 proxy.rotatePending = FALSE; 1795 proxy.scalePending = FALSE; 1796 proxy.can_update = TRUE; 1318 1797 proxy.sync = 0; 1319 1798 proxy.frame = 1; 1320 1799 proxy.rock_offset = 0; 1321 1800 proxy.cacheid = 0; 1322 proxy.invalidate_cache = 0; 1323 1324 ufd[0].fd = proxy.c_stdout; 1325 ufd[0].events = POLLIN | POLLHUP; /* ensure catching EOF */ 1326 ufd[1].fd = proxy.p_stdout; 1327 ufd[1].events = POLLIN | POLLHUP; 1328 ufd[2].fd = proxy.p_stderr; 1329 ufd[2].events = POLLIN | POLLHUP; 1330 1331 flags = fcntl(proxy.p_stdout, F_GETFL); 1332 fcntl(proxy.p_stdout, F_SETFL, flags|O_NONBLOCK); 1333 1801 proxy.invalidate_cache = FALSE; 1334 1802 interp = Tcl_CreateInterp(); 1335 1803 Tcl_MakeSafe(interp); 1336 1337 Tcl_DStringInit(&cmdbuffer);1804 proxy.interp = interp; 1805 proxy.xAngle = proxy.yAngle = proxy.zAngle = 0.0f; 1338 1806 dyBufferInit(&proxy.image); 1339 dyBufferInit(&dybuffer); 1340 dyBufferInit(&dybuffer2); 1341 1342 Tcl_CreateCommand(interp, "bmp", BMPCmd, &proxy, NULL); 1343 Tcl_CreateCommand(interp, "png", PNGCmd, &proxy, NULL); 1344 Tcl_CreateCommand(interp, "screen", ViewportCmd, &proxy, NULL); 1345 Tcl_CreateCommand(interp, "viewport",ViewportCmd, &proxy, NULL); 1346 Tcl_CreateCommand(interp, "rotate", RotateCmd, &proxy, NULL); 1347 Tcl_CreateCommand(interp, "zoom", ZoomCmd, &proxy, NULL); 1348 Tcl_CreateCommand(interp, "loadpdb", LoadPDBCmd, &proxy, NULL); 1349 Tcl_CreateCommand(interp, "ballnstick",BallNStickCmd, &proxy, NULL); 1350 Tcl_CreateCommand(interp, "spheres", SpheresCmd, &proxy, NULL); 1351 Tcl_CreateCommand(interp, "lines", LinesCmd, &proxy, NULL); 1352 Tcl_CreateCommand(interp, "raw", RawCmd, &proxy, NULL); 1353 Tcl_CreateCommand(interp, "label", LabelCmd, &proxy, NULL); 1354 Tcl_CreateCommand(interp, "reset", ResetCmd, &proxy, NULL); 1355 Tcl_CreateCommand(interp, "rock", RockCmd, &proxy, NULL); 1356 Tcl_CreateCommand(interp, "frame", FrameCmd, &proxy, NULL); 1357 Tcl_CreateCommand(interp, "vmouse", VMouseCmd, &proxy, NULL); 1358 Tcl_CreateCommand(interp, "disable", DisableCmd, &proxy, NULL); 1359 Tcl_CreateCommand(interp, "enable", EnableCmd, &proxy, NULL); 1360 Tcl_CreateCommand(interp, "pan", PanCmd, &proxy, NULL); 1807 1808 Tcl_CreateCommand(interp, "atomscale", AtomscaleCmd, &proxy, NULL); 1809 Tcl_CreateCommand(interp, "ballnstick", BallNStickCmd, &proxy, NULL); 1810 Tcl_CreateCommand(interp, "bmp", BmpCmd, &proxy, NULL); 1811 Tcl_CreateCommand(interp, "disable", DisableCmd, &proxy, NULL); 1812 Tcl_CreateCommand(interp, "enable", EnableCmd, &proxy, NULL); 1813 Tcl_CreateCommand(interp, "frame", FrameCmd, &proxy, NULL); 1814 Tcl_CreateCommand(interp, "label", LabelCmd, &proxy, NULL); 1815 Tcl_CreateCommand(interp, "lines", LinesCmd, &proxy, NULL); 1816 Tcl_CreateCommand(interp, "loadpdb", LoadPDBCmd, &proxy, NULL); 1817 Tcl_CreateCommand(interp, "orthoscopic", OrthoscopicCmd, &proxy, NULL); 1818 Tcl_CreateCommand(interp, "pan", PanCmd, &proxy, NULL); 1819 Tcl_CreateCommand(interp, "png", PngCmd, &proxy, NULL); 1820 Tcl_CreateCommand(interp, "raw", RawCmd, &proxy, NULL); 1821 Tcl_CreateCommand(interp, "reset", ResetCmd, &proxy, NULL); 1822 Tcl_CreateCommand(interp, "rock", RockCmd, &proxy, NULL); 1823 Tcl_CreateCommand(interp, "rotate", RotateCmd, &proxy, NULL); 1824 Tcl_CreateCommand(interp, "screen", ScreenCmd, &proxy, NULL); 1825 Tcl_CreateCommand(interp, "spheres", SpheresCmd, &proxy, NULL); 1826 Tcl_CreateCommand(interp, "viewport", ScreenCmd, &proxy, NULL); 1827 Tcl_CreateCommand(interp, "vmouse", VMouseCmd, &proxy, NULL); 1828 Tcl_CreateCommand(interp, "zoom", ZoomCmd, &proxy, NULL); 1829 1830 1831 gettimeofday(&end, NULL); 1832 stats.start = end; 1361 1833 1362 1834 // Main Proxy Loop … … 1364 1836 // translate them into pyMol commands, and issue them to child proccess 1365 1837 // send images back 1366 1367 gettimeofday(&end, NULL); 1368 stats.start = end; 1369 while(1) { 1370 gettimeofday(&now,NULL); 1371 1372 if ( (!proxy.need_update) ) 1373 timeout = -1; 1374 else if ((now.tv_sec > end.tv_sec) || ( (now.tv_sec == end.tv_sec) && (now.tv_usec >= end.tv_usec)) ) 1375 timeout = 0; 1376 else { 1377 timeout = (end.tv_sec - now.tv_sec) * 1000; 1378 1379 if (end.tv_usec > now.tv_usec) 1380 timeout += (end.tv_usec - now.tv_usec) / 1000; 1381 else 1382 timeout += (((1000000 + end.tv_usec) - now.tv_usec) / 1000) - 1000; 1383 1384 } 1385 1386 status = 0; 1387 errno = 0; 1388 if (!proxy.immediate_update) { 1389 status = poll(ufd, 3, timeout); 1390 } 1391 if ( status < 0 ) { 1392 trace("POLL ERROR: status = %d: %s", status, strerror(errno)); 1393 } else if (status > 0) { 1394 1395 gettimeofday(&now,NULL); 1396 if (ufd[0].revents & POLLIN) { 1397 /* Client Stdout Connection: command input */ 1398 ssize_t nRead; 1399 char ch; 1400 1401 nRead = read(ufd[0].fd, &ch, 1); 1402 if (nRead <= 0) { 1403 trace("unexpected read error from client (stdout): %s", 1404 strerror(errno)); 1405 if (errno != EINTR) { 1406 trace("lost client connection: %s", strerror(errno)); 1407 break; 1408 } 1409 } else { 1410 Tcl_DStringAppend(&cmdbuffer, &ch, 1); 1411 1412 if (ch == '\n' && 1413 Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) { 1414 int result; 1415 1416 result = ExecuteCommand(interp, &cmdbuffer); 1417 if (timeout == 0) { 1418 status = 0; // send update 1419 } 1420 } 1421 } 1422 } else if (ufd[0].revents & POLLHUP) { 1423 trace("received hangup on stdout from client."); 1424 break; 1425 } 1426 1427 if (ufd[1].revents & POLLIN) { 1428 ssize_t nRead; 1429 char ch; 1430 1431 /* This is supposed to suck up all the extra output from the 1432 * pymol server output after we've matched the command 1433 * prompt. */ 1434 1435 /* pyMol Stdout Connection: pymol (unexpected) output */ 1436 nRead = read(ufd[1].fd, &ch, 1); 1437 if (nRead <= 0) { 1438 /* It's possible to have already drained the channel in 1439 * response to a client command handled above. Skip 1440 * it if we're blocking. */ 1441 if ((errno == EAGAIN) || (errno == EINTR)) { 1442 trace("try again to read (stdout) to pymol server."); 1443 goto nextchannel; 1444 } 1445 trace("lost connection (stdout) from pymol server."); 1446 break; 1447 } else { 1448 dyBufferAppend(&dybuffer, &ch, 1); 1449 1450 if (ch == '\n') { 1451 ch = 0; 1452 dyBufferAppend(&dybuffer, &ch, 1); 1453 trace("STDOUT>%s",dybuffer.data); 1454 dyBufferSetLength(&dybuffer,0); 1455 } 1456 } 1457 } else if (ufd[1].revents & POLLHUP) { 1458 trace("received hangup on stdout to pymol server."); 1459 break; 1460 } 1461 nextchannel: 1462 if (ufd[2].revents & POLLIN) { 1463 ssize_t nRead; 1464 char ch; 1465 1466 /* pyMol Stderr Connection: pymol standard error output */ 1467 1468 nRead = read(ufd[2].fd, &ch, 1); 1469 if (nRead <= 0) { 1470 trace("unexpected read error from server (stderr): %s", 1471 strerror(errno)); 1472 if (errno != EINTR) { 1473 trace("lost connection (stderr) to pymol server."); 1474 break; 1475 } 1476 } else { 1477 dyBufferAppend(&dybuffer2, &ch, 1); 1478 if (ch == '\n') { 1479 ch = 0; 1480 dyBufferAppend(&dybuffer2, &ch, 1); 1481 trace("stderr>%s", dybuffer2.data); 1482 dyBufferSetLength(&dybuffer2,0); 1483 } 1484 } 1485 } else if (ufd[2].revents & POLLHUP) { 1486 trace("received hangup on stderr from pymol server."); 1487 break; 1488 } 1489 } 1490 1491 if (status == 0) { 1492 gettimeofday(&now,NULL); 1493 1494 if (proxy.need_update && proxy.can_update) 1495 Tcl_Eval(interp, "bmp -\n"); 1496 1497 end.tv_sec = now.tv_sec; 1498 end.tv_usec = now.tv_usec + 150000; 1499 1500 if (end.tv_usec >= 1000000) { 1501 end.tv_sec++; 1502 end.tv_usec -= 1000000; 1503 } 1504 1505 } 1506 1507 } 1508 1509 status = waitpid(pid, &result, WNOHANG); 1838 PollForEvents(&proxy); 1839 1840 close(proxy.clientOutput); 1841 close(proxy.serverOutput); 1842 close(proxy.serverError); 1843 close(proxy.clientInput); 1844 close(proxy.serverInput); 1845 1846 status = waitpid(child, &result, WNOHANG); 1510 1847 if (status == -1) { 1511 1848 trace("error waiting on pymol server to exit: %s", strerror(errno)); 1512 1849 } else if (status == 0) { 1513 1850 trace("attempting to signal (SIGTERM) pymol server."); 1514 kill(- pid, SIGTERM); // kill process group1851 kill(-child, SIGTERM); // kill process group 1515 1852 alarm(5); 1516 status = waitpid( pid, &result, 0);1853 status = waitpid(child, &result, 0); 1517 1854 alarm(0); 1518 1855 1519 1856 while ((status == -1) && (errno == EINTR)) { 1520 1857 trace("Attempting to signal (SIGKILL) pymol server."); 1521 kill(- pid, SIGKILL); // kill process group1858 kill(-child, SIGKILL); // kill process group 1522 1859 alarm(10); 1523 status = waitpid( pid, &result, 0);1860 status = waitpid(child, &result, 0); 1524 1861 alarm(0); 1525 1862 } … … 1547 1884 char fileName[200]; 1548 1885 sprintf(fileName, "/tmp/pymolproxy%d.log", getpid()); 1886 sprintf(fileName, "/tmp/pymolproxy.log"); 1549 1887 flog = fopen(fileName, "w"); 1550 1888 } … … 1555 1893 #endif 1556 1894 1895 1896 static void 1897 PollForEvents(PymolProxy *proxyPtr) 1898 { 1899 DyBuffer *imgPtr; 1900 Tcl_DString clientCmds; 1901 struct pollfd pollResults[4]; 1902 int flags; 1903 1904 flags = fcntl(proxyPtr->clientInput, F_GETFL); 1905 fcntl(proxyPtr->clientInput, F_SETFL, flags|O_NONBLOCK); 1906 1907 #ifdef notdef 1908 flags = fcntl(proxyPtr->serverOutput, F_GETFL); 1909 fcntl(proxyPtr->serverOutput, F_SETFL, flags|O_NONBLOCK); 1910 #endif 1911 1912 pollResults[0].fd = proxyPtr->clientOutput; 1913 pollResults[1].fd = proxyPtr->serverOutput; 1914 pollResults[2].fd = proxyPtr->serverError; 1915 pollResults[0].events = pollResults[1].events = 1916 pollResults[2].events = POLLIN; 1917 1918 pollResults[3].fd = proxyPtr->clientInput; 1919 pollResults[3].events = POLLOUT; 1920 1921 InitBuffer(&proxyPtr->client, proxyPtr->clientOutput); 1922 InitBuffer(&proxyPtr->server, proxyPtr->serverOutput); 1923 1924 Tcl_DStringInit(&clientCmds); 1925 imgPtr = &proxyPtr->image; 1926 for (;;) { 1927 int timeout, nChannels; 1928 1929 nChannels = (imgPtr->bytesLeft > 0) ? 4 : 3; 1930 1931 #define PENDING_TIMEOUT 10 /* milliseconds. */ 1932 timeout = (proxyPtr->updatePending) ? PENDING_TIMEOUT : -1; 1933 nChannels = poll(pollResults, nChannels, timeout); 1934 if (nChannels < 0) { 1935 trace("POLL ERROR: %s", strerror(errno)); 1936 continue; /* or exit? */ 1937 } 1938 1939 /* 1940 * The next two sections are to drain any leftover data in 1941 * the pymol server process' stdout or stderr. We don't want the 1942 * the pymol server to block writing to stderr or stdout. 1943 */ 1944 if (pollResults[1].revents & POLLIN) { 1945 int nBytes; 1946 char *line; 1947 1948 trace("Reading pymol stdout\n"); 1949 /* Don't care what's in the server output buffer. */ 1950 FlushBuffer(&proxyPtr->server); 1951 line = GetLine(&proxyPtr->server, &nBytes); 1952 if (line != NULL) { 1953 trace("STDOUT>%.*s", nBytes, line); 1954 trace("Done with pymol stdout\n"); 1955 } else if (nBytes == BUFFER_CONTINUE) { 1956 trace("Done with pymol stdout\n"); 1957 } else { 1958 trace("Failed reading pymol stdout (nBytes=%d)\n", nBytes); 1959 goto error; /* Get out on EOF or error. */ 1960 } 1961 } 1962 1963 if (pollResults[2].revents & POLLIN) { 1964 ssize_t nRead; 1965 char buf[BUFSIZ]; 1966 1967 trace("Reading pymol stderr\n"); 1968 /* pyMol Stderr Connection: pymol standard error output */ 1969 1970 nRead = read(pollResults[2].fd, buf, BUFSIZ-1); 1971 if (nRead <= 0) { 1972 trace("unexpected read error from server (stderr): %s", 1973 strerror(errno)); 1974 if (errno != EINTR) { 1975 trace("lost connection (stderr) to pymol server."); 1976 return; 1977 } 1978 } 1979 buf[nRead] = '\0'; 1980 trace("stderr>%s", buf); 1981 trace("Done reading pymol stderr\n"); 1982 } 1983 1984 /* We have some descriptors ready. */ 1985 if (pollResults[0].revents & POLLIN) { 1986 trace("Reading client stdout\n"); 1987 for (;;) { 1988 int nBytes; 1989 char *line; 1990 1991 line = GetLine(&proxyPtr->client, &nBytes); 1992 if (line != NULL) { 1993 const char *cmd; 1994 1995 Tcl_DStringAppend(&clientCmds, line, nBytes); 1996 cmd = Tcl_DStringValue(&clientCmds); 1997 if (Tcl_CommandComplete(cmd)) { 1998 /* May execute more than one command. */ 1999 ExecuteCommand(proxyPtr->interp, cmd); 2000 Tcl_DStringSetLength(&clientCmds, 0); 2001 } 2002 continue; 2003 } 2004 if (nBytes == BUFFER_CONTINUE) { 2005 break; 2006 } 2007 trace("Failed reading client stdout (nBytes=%d)\n", nBytes); 2008 goto error; /* Get out on EOF or error. */ 2009 } 2010 trace("done with client stdout\n"); 2011 } 2012 /* 2013 * Write the currently queued image if there is one. 2014 * 2015 * We want to transmit the current image back to the client. But if 2016 * the client's busy (e.g. sending us another command), there's a 2017 * chance we'll deadlock. Therefore, the file descriptor is 2018 * non-blocking and we write only what we can. Must be careful not to 2019 * refresh the image until we're done. 2020 */ 2021 2022 if (proxyPtr->rotatePending) { 2023 DoRotate(proxyPtr); 2024 } 2025 if (proxyPtr->scalePending) { 2026 DoAtomScale(proxyPtr); 2027 } 2028 2029 /* Write the current image buffer. */ 2030 if (imgPtr->nWritten == 0) { 2031 /* We might want to refresh the image if we're not currently 2032 * transmitting an image back to the client. The image will be 2033 * refreshed after the image has been completely transmitted. */ 2034 if ((nChannels == 0) || (proxyPtr->forceUpdate)) { 2035 if (proxyPtr->updatePending) { 2036 Tcl_Eval(proxyPtr->interp, "bmp"); 2037 proxyPtr->updatePending = FALSE; 2038 } 2039 proxyPtr->forceUpdate = FALSE; 2040 continue; 2041 } 2042 } 2043 if ((imgPtr->bytesLeft > 0) && (pollResults[3].revents & POLLOUT)) { 2044 WriteImage(proxyPtr, pollResults[3].fd); 2045 } 2046 } 2047 error: 2048 Tcl_DStringFree(&clientCmds); 2049 return; 2050 }
Note: See TracChangeset
for help on using the changeset viewer.