1 | |
---|
2 | /* |
---|
3 | * ---------------------------------------------------------------------- |
---|
4 | * proxypymol.c |
---|
5 | * |
---|
6 | * This module creates the Tcl interface to the pymol server. It acts as |
---|
7 | * a go-between establishing communication between a molvisviewer widget |
---|
8 | * and the pymol server. The communication protocol from the molvisviewer |
---|
9 | * widget is the Tcl language. Commands are then relayed to the pymol |
---|
10 | * server. Responses from the pymol server are translated into Tcl |
---|
11 | * commands * and send to the molvisviewer widget. For example, resulting |
---|
12 | * image rendered offscreen is returned as BMP-formatted image data. |
---|
13 | * |
---|
14 | * Copyright (c) 2004-2006 Purdue Research Foundation |
---|
15 | * |
---|
16 | * See the file "license.terms" for information on usage and |
---|
17 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
18 | * ====================================================================== |
---|
19 | */ |
---|
20 | |
---|
21 | #include <stdio.h> |
---|
22 | #include <time.h> |
---|
23 | #include <assert.h> |
---|
24 | #include <unistd.h> |
---|
25 | #include <stdlib.h> |
---|
26 | #include <string.h> |
---|
27 | #include <signal.h> |
---|
28 | #include <sys/types.h> |
---|
29 | #include <sys/socket.h> |
---|
30 | #include <sys/wait.h> |
---|
31 | #include <sys/select.h> |
---|
32 | #include <poll.h> |
---|
33 | #include <sys/time.h> |
---|
34 | #include <sys/times.h> |
---|
35 | #include <fcntl.h> |
---|
36 | #include <netinet/in.h> |
---|
37 | #include <getopt.h> |
---|
38 | #include <errno.h> |
---|
39 | #include <sys/ioctl.h> |
---|
40 | #include <net/if.h> |
---|
41 | #include <tcl.h> |
---|
42 | |
---|
43 | #undef INLINE |
---|
44 | #ifdef __GNUC__ |
---|
45 | # define INLINE __inline__ |
---|
46 | #else |
---|
47 | # define INLINE |
---|
48 | #endif |
---|
49 | |
---|
50 | #define FALSE 0 |
---|
51 | #define TRUE 1 |
---|
52 | |
---|
53 | #define IO_TIMEOUT (30000) |
---|
54 | #define STATSFILE "/var/tmp/visservers/data.xml" |
---|
55 | #define KEEPSTATS 1 |
---|
56 | #define CVT2SECS(x) ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6) |
---|
57 | |
---|
58 | typedef struct { |
---|
59 | pid_t child; /* Child process. */ |
---|
60 | size_t nFrames; /* # of frames sent to client. */ |
---|
61 | size_t nBytes; /* # of bytes for all frames. */ |
---|
62 | size_t nCommands; /* # of commands executed */ |
---|
63 | double cmdTime; /* Elasped time spend executing commands. */ |
---|
64 | struct timeval start; /* Start of elapsed time. */ |
---|
65 | } Stats; |
---|
66 | |
---|
67 | static Stats stats; |
---|
68 | |
---|
69 | static FILE *flog; |
---|
70 | static int debug = 1; |
---|
71 | |
---|
72 | |
---|
73 | typedef struct { |
---|
74 | char *data; |
---|
75 | int used; |
---|
76 | int allocated; |
---|
77 | } DyBuffer; |
---|
78 | |
---|
79 | typedef struct { |
---|
80 | int p_stdin; |
---|
81 | int p_stdout; |
---|
82 | int p_stderr; |
---|
83 | int c_stdin; |
---|
84 | int c_stdout; |
---|
85 | DyBuffer image; |
---|
86 | int need_update; |
---|
87 | int can_update; |
---|
88 | int immediate_update; |
---|
89 | int sync; |
---|
90 | int labels; |
---|
91 | int frame; |
---|
92 | int rock_offset; |
---|
93 | int cacheid; |
---|
94 | int invalidate_cache; |
---|
95 | int error; |
---|
96 | int status; |
---|
97 | } PymolProxy; |
---|
98 | |
---|
99 | static void |
---|
100 | trace TCL_VARARGS_DEF(char *, arg1) |
---|
101 | { |
---|
102 | if (debug) { |
---|
103 | char *format; |
---|
104 | va_list args; |
---|
105 | |
---|
106 | format = TCL_VARARGS_START(char *, arg1, args); |
---|
107 | vfprintf(flog, format, args); |
---|
108 | fprintf(flog, "\n"); |
---|
109 | fflush(flog); |
---|
110 | } |
---|
111 | } |
---|
112 | |
---|
113 | #ifdef KEEPSTATS |
---|
114 | |
---|
115 | static int |
---|
116 | WriteStats(const char *who, int code) |
---|
117 | { |
---|
118 | double start, finish; |
---|
119 | pid_t pid; |
---|
120 | char buf[BUFSIZ]; |
---|
121 | Tcl_DString ds; |
---|
122 | |
---|
123 | { |
---|
124 | struct timeval tv; |
---|
125 | |
---|
126 | /* Get ending time. */ |
---|
127 | gettimeofday(&tv, NULL); |
---|
128 | finish = CVT2SECS(tv); |
---|
129 | tv = stats.start; |
---|
130 | start = CVT2SECS(tv); |
---|
131 | } |
---|
132 | /* |
---|
133 | * Session information: |
---|
134 | * 1. Start date of session in seconds. |
---|
135 | * 2. Process ID |
---|
136 | * 3. Number of frames returned. |
---|
137 | * 4. Number of bytes total returned (in frames). |
---|
138 | * 5. Total elapsed time of all commands. |
---|
139 | * 6. Total elapsed time of session. |
---|
140 | * 7. Exit code of pymol server. |
---|
141 | * 8. User time. |
---|
142 | * 9. System time. |
---|
143 | * 10. Maximum resident size. |
---|
144 | */ |
---|
145 | pid = getpid(); |
---|
146 | Tcl_DStringInit(&ds); |
---|
147 | |
---|
148 | sprintf(buf, "<session server=\"%s\" ", who); |
---|
149 | Tcl_DStringAppend(&ds, buf, -1); |
---|
150 | |
---|
151 | strcpy(buf, ctime(&stats.start.tv_sec)); |
---|
152 | |
---|
153 | buf[strlen(buf) - 1] = '\0'; |
---|
154 | Tcl_DStringAppend(&ds, "date=\"", -1); |
---|
155 | Tcl_DStringAppend(&ds, buf, -1); |
---|
156 | Tcl_DStringAppend(&ds, "\" ", -1); |
---|
157 | |
---|
158 | sprintf(buf, "date_secs=\"%ld\" ", stats.start.tv_sec); |
---|
159 | Tcl_DStringAppend(&ds, buf, -1); |
---|
160 | |
---|
161 | sprintf(buf, "pid=\"%d\" ", pid); |
---|
162 | Tcl_DStringAppend(&ds, buf, -1); |
---|
163 | sprintf(buf, "num_frames=\"%lu\" ", (unsigned long int)stats.nFrames); |
---|
164 | Tcl_DStringAppend(&ds, buf, -1); |
---|
165 | sprintf(buf, "frame_bytes=\"%lu\" ", (unsigned long int)stats.nBytes); |
---|
166 | Tcl_DStringAppend(&ds, buf, -1); |
---|
167 | sprintf(buf, "num_commands=\"%lu\" ", (unsigned long int)stats.nCommands); |
---|
168 | Tcl_DStringAppend(&ds, buf, -1); |
---|
169 | sprintf(buf, "cmd_time=\"%g\" ", stats.cmdTime); |
---|
170 | Tcl_DStringAppend(&ds, buf, -1); |
---|
171 | sprintf(buf, "session_time=\"%g\" ", finish - start); |
---|
172 | Tcl_DStringAppend(&ds, buf, -1); |
---|
173 | sprintf(buf, "status=\"%d\" ", code); |
---|
174 | Tcl_DStringAppend(&ds, buf, -1); |
---|
175 | { |
---|
176 | long clocksPerSec = sysconf(_SC_CLK_TCK); |
---|
177 | double clockRes = 1.0 / clocksPerSec; |
---|
178 | struct tms tms; |
---|
179 | |
---|
180 | memset(&tms, 0, sizeof(tms)); |
---|
181 | if (times(&tms) < 0) { |
---|
182 | fprintf(flog, "can't get times: %s\n", strerror(errno)); |
---|
183 | } |
---|
184 | sprintf(buf, "utime=\"%g\" ", tms.tms_utime * clockRes); |
---|
185 | Tcl_DStringAppend(&ds, buf, -1); |
---|
186 | sprintf(buf, "stime=\"%g\" ", tms.tms_stime * clockRes); |
---|
187 | Tcl_DStringAppend(&ds, buf, -1); |
---|
188 | sprintf(buf, "cutime=\"%g\" ", tms.tms_cutime * clockRes); |
---|
189 | Tcl_DStringAppend(&ds, buf, -1); |
---|
190 | sprintf(buf, "cstime=\"%g\" ", tms.tms_cstime * clockRes); |
---|
191 | Tcl_DStringAppend(&ds, buf, -1); |
---|
192 | } |
---|
193 | Tcl_DStringAppend(&ds, "/>\n", -1); |
---|
194 | |
---|
195 | { |
---|
196 | int f; |
---|
197 | ssize_t length; |
---|
198 | int result; |
---|
199 | |
---|
200 | length = Tcl_DStringLength(&ds); |
---|
201 | f = open(STATSFILE, O_APPEND | O_CREAT | O_WRONLY, 0600); |
---|
202 | result = FALSE; |
---|
203 | if (f < 0) { |
---|
204 | goto error; |
---|
205 | } |
---|
206 | if (write(f, Tcl_DStringValue(&ds), length) != length) { |
---|
207 | goto error; |
---|
208 | } |
---|
209 | result = TRUE; |
---|
210 | error: |
---|
211 | if (f >= 0) { |
---|
212 | close(f); |
---|
213 | } |
---|
214 | Tcl_DStringFree(&ds); |
---|
215 | return result; |
---|
216 | } |
---|
217 | } |
---|
218 | #endif |
---|
219 | |
---|
220 | static void |
---|
221 | DoExit(int code) |
---|
222 | { |
---|
223 | char fileName[200]; |
---|
224 | #ifdef KEEPSTATS |
---|
225 | WriteStats("pymolproxy", code); |
---|
226 | #endif |
---|
227 | sprintf(fileName, "/tmp/pymol%d.pdb", getpid()); |
---|
228 | unlink(fileName); |
---|
229 | exit(code); |
---|
230 | } |
---|
231 | |
---|
232 | static int |
---|
233 | ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) |
---|
234 | { |
---|
235 | struct timeval tv; |
---|
236 | double start, finish; |
---|
237 | int result; |
---|
238 | |
---|
239 | gettimeofday(&tv, NULL); |
---|
240 | start = CVT2SECS(tv); |
---|
241 | |
---|
242 | result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr)); |
---|
243 | trace("Executed (%s)", Tcl_DStringValue(dsPtr)); |
---|
244 | Tcl_DStringSetLength(dsPtr, 0); |
---|
245 | |
---|
246 | gettimeofday(&tv, NULL); |
---|
247 | finish = CVT2SECS(tv); |
---|
248 | |
---|
249 | stats.cmdTime += finish - start; |
---|
250 | stats.nCommands++; |
---|
251 | return result; |
---|
252 | } |
---|
253 | |
---|
254 | |
---|
255 | INLINE static void |
---|
256 | dyBufferInit(DyBuffer *buffer) |
---|
257 | { |
---|
258 | buffer->data = NULL; |
---|
259 | buffer->used = 0; |
---|
260 | buffer->allocated = 0; |
---|
261 | } |
---|
262 | |
---|
263 | INLINE static void |
---|
264 | dyBufferFree(DyBuffer *buffer) |
---|
265 | { |
---|
266 | assert(buffer != NULL); |
---|
267 | free(buffer->data); |
---|
268 | dyBufferInit(buffer); |
---|
269 | } |
---|
270 | |
---|
271 | void |
---|
272 | dyBufferSetLength(DyBuffer *buffer, int length) |
---|
273 | { |
---|
274 | assert(buffer != NULL); |
---|
275 | if (length == 0) { |
---|
276 | dyBufferFree(buffer); |
---|
277 | } else if (length > buffer->used) { |
---|
278 | char *newdata; |
---|
279 | |
---|
280 | newdata = realloc(buffer->data, length); |
---|
281 | if (newdata != NULL) { |
---|
282 | buffer->data = newdata; |
---|
283 | buffer->used = length; |
---|
284 | buffer->allocated = length; |
---|
285 | } |
---|
286 | } else { |
---|
287 | buffer->used = length; |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | static void |
---|
292 | dyBufferAppend(DyBuffer *buffer, const char *data, int length) |
---|
293 | { |
---|
294 | int offset; |
---|
295 | |
---|
296 | assert(buffer != NULL); |
---|
297 | offset = buffer->used; |
---|
298 | dyBufferSetLength(buffer, offset + length); |
---|
299 | memcpy(buffer->data + offset, data, length); |
---|
300 | } |
---|
301 | |
---|
302 | static int |
---|
303 | bwrite(int sock, char *buffer, int size) |
---|
304 | { |
---|
305 | int result; |
---|
306 | int total = 0; |
---|
307 | int left = size; |
---|
308 | |
---|
309 | trace("bwrite: want to write %d bytes\n", size); |
---|
310 | while(1) { |
---|
311 | result = write(sock,buffer+total,left); |
---|
312 | |
---|
313 | if (result <= 0) |
---|
314 | break; |
---|
315 | |
---|
316 | total += result; |
---|
317 | left -= result; |
---|
318 | |
---|
319 | if (total == size) |
---|
320 | break; |
---|
321 | } |
---|
322 | trace("bwrite: wrote %d bytes\n", total); |
---|
323 | return(total); |
---|
324 | } |
---|
325 | |
---|
326 | static int |
---|
327 | bread(int sock, char *buffer, int size) |
---|
328 | { |
---|
329 | int result, total, left; |
---|
330 | |
---|
331 | for( total = 0, left = size; left > 0; left -= result) { |
---|
332 | result = read(sock,buffer+total,left); |
---|
333 | |
---|
334 | if (result > 0) { |
---|
335 | total += result; |
---|
336 | continue; |
---|
337 | } |
---|
338 | |
---|
339 | if ((result < 0) && (errno != EAGAIN) && (errno != EINTR)) { |
---|
340 | trace("pymolproxy: Error reading sock(%d), %d/%s\n", |
---|
341 | sock, errno,strerror(errno)); |
---|
342 | break; |
---|
343 | } |
---|
344 | |
---|
345 | result = 0; |
---|
346 | } |
---|
347 | return total; |
---|
348 | } |
---|
349 | |
---|
350 | #ifdef notdef |
---|
351 | |
---|
352 | static int |
---|
353 | bflush(int sock, char *buffer, int size, int bytes) |
---|
354 | { |
---|
355 | int bsize; |
---|
356 | |
---|
357 | while(bytes) { |
---|
358 | if (bytes > size) |
---|
359 | bsize = size; |
---|
360 | else |
---|
361 | bsize = bytes; |
---|
362 | |
---|
363 | bsize = bread(sock,buffer,bsize); |
---|
364 | |
---|
365 | bytes -= bsize; |
---|
366 | } |
---|
367 | } |
---|
368 | |
---|
369 | #undef timersub |
---|
370 | static void |
---|
371 | timersub(struct timeval *a, struct timeval *b, struct timeval *result) |
---|
372 | { |
---|
373 | result->tv_sec = a->tv_sec - b->tv_sec; |
---|
374 | result->tv_usec = a->tv_usec - b->tv_usec; |
---|
375 | |
---|
376 | while(result->tv_usec < 0) { |
---|
377 | result->tv_sec -= 1; |
---|
378 | result->tv_usec += 1000000; |
---|
379 | } |
---|
380 | } |
---|
381 | |
---|
382 | #endif |
---|
383 | |
---|
384 | static void |
---|
385 | timersub_ms(struct timeval *a, struct timeval *b, int *result) |
---|
386 | { |
---|
387 | struct timeval tmp; |
---|
388 | |
---|
389 | tmp.tv_sec = a->tv_sec - b->tv_sec; |
---|
390 | tmp.tv_usec = a->tv_usec - b->tv_usec; |
---|
391 | |
---|
392 | while(tmp.tv_usec < 0) { |
---|
393 | tmp.tv_sec -= 1; |
---|
394 | tmp.tv_usec += 1000000; |
---|
395 | } |
---|
396 | |
---|
397 | *result = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000); |
---|
398 | } |
---|
399 | |
---|
400 | #undef timeradd |
---|
401 | static void |
---|
402 | timeradd (struct timeval *a, struct timeval *b, struct timeval *result) |
---|
403 | { |
---|
404 | result->tv_sec = a->tv_sec + b->tv_sec; |
---|
405 | result->tv_usec = a->tv_usec + b->tv_usec; |
---|
406 | |
---|
407 | while (result->tv_usec >= 1000000) { |
---|
408 | result->tv_sec += 1; |
---|
409 | result->tv_usec -= 1000000; |
---|
410 | } |
---|
411 | } |
---|
412 | |
---|
413 | static void |
---|
414 | timerset_ms(struct timeval *result, int timeout) |
---|
415 | { |
---|
416 | result->tv_sec = timeout / 1000; |
---|
417 | result->tv_usec = (timeout % 1000) * 1000; |
---|
418 | } |
---|
419 | |
---|
420 | static int |
---|
421 | getline(int sock, char *buffer, int size, long timeout) |
---|
422 | { |
---|
423 | int pos = 0, status, timeo; |
---|
424 | struct timeval now, end, tmo; |
---|
425 | struct pollfd ufd; |
---|
426 | |
---|
427 | gettimeofday(&now,NULL); |
---|
428 | timerset_ms(&tmo, timeout); |
---|
429 | timeradd(&now,&tmo,&end); |
---|
430 | |
---|
431 | ufd.fd = sock; |
---|
432 | ufd.events = POLLIN; |
---|
433 | |
---|
434 | size--; |
---|
435 | |
---|
436 | while(pos < size) { |
---|
437 | if (timeout > 0) { |
---|
438 | gettimeofday(&now,NULL); |
---|
439 | timersub_ms(&now,&end,&timeo); |
---|
440 | } |
---|
441 | else |
---|
442 | timeo = -1; |
---|
443 | |
---|
444 | status = poll(&ufd, 1, timeo); |
---|
445 | |
---|
446 | if (status > 0) |
---|
447 | status = read(sock,&buffer[pos],1); |
---|
448 | |
---|
449 | if ( (status < 0) && ( (errno == EINTR) || (errno == EAGAIN) ) ) |
---|
450 | continue; /* try again, if interrupted/blocking */ |
---|
451 | |
---|
452 | if (status <= 0) |
---|
453 | break; |
---|
454 | |
---|
455 | if (buffer[pos] == '\n') { |
---|
456 | pos++; |
---|
457 | break; |
---|
458 | } |
---|
459 | pos++; |
---|
460 | } |
---|
461 | |
---|
462 | buffer[pos]=0; |
---|
463 | |
---|
464 | return(pos); |
---|
465 | } |
---|
466 | |
---|
467 | static int |
---|
468 | waitForString(PymolProxy *pymol, char *string, char *buffer, int length) |
---|
469 | { |
---|
470 | int sock; |
---|
471 | |
---|
472 | assert(buffer != NULL); |
---|
473 | if (pymol->status != TCL_OK) |
---|
474 | return pymol->status; |
---|
475 | |
---|
476 | sock = pymol->p_stdout; |
---|
477 | trace("want to match (%s)\n", string); |
---|
478 | while(1) { |
---|
479 | if (getline(sock,buffer,length,IO_TIMEOUT) == 0) { |
---|
480 | pymol->error = 2; |
---|
481 | pymol->status = TCL_ERROR; |
---|
482 | break; |
---|
483 | } |
---|
484 | trace("stdout-u>read(%s)", buffer); |
---|
485 | if (strncmp(buffer, string, strlen(string)) == 0) { |
---|
486 | trace("stdout-e> %s",buffer); |
---|
487 | pymol->error = 0; |
---|
488 | pymol->status = TCL_OK; |
---|
489 | break; |
---|
490 | } |
---|
491 | } |
---|
492 | |
---|
493 | return pymol->status; |
---|
494 | } |
---|
495 | |
---|
496 | INLINE static int |
---|
497 | clear_error(PymolProxy *pymol) |
---|
498 | { |
---|
499 | pymol->error = 0; |
---|
500 | pymol->status = TCL_OK; |
---|
501 | return pymol->status; |
---|
502 | } |
---|
503 | |
---|
504 | static int |
---|
505 | send_expect(PymolProxy *pymol, char *expect, char *cmd) |
---|
506 | { |
---|
507 | if (pymol->error) { |
---|
508 | return(TCL_ERROR); |
---|
509 | } |
---|
510 | trace("to-pymol>(%s)", cmd); |
---|
511 | write(pymol->p_stdin, cmd, strlen(cmd)); |
---|
512 | if (waitForString(pymol, expect, cmd, 800)) { |
---|
513 | trace("pymolproxy: Timeout reading data [%s]\n",cmd); |
---|
514 | pymol->error = 1; |
---|
515 | pymol->status = TCL_ERROR; |
---|
516 | return pymol->status; |
---|
517 | } |
---|
518 | return( pymol->status ); |
---|
519 | } |
---|
520 | |
---|
521 | static int |
---|
522 | sendf(PymolProxy *pymol, char *format, ...) |
---|
523 | { |
---|
524 | va_list ap; |
---|
525 | char buffer[800]; |
---|
526 | |
---|
527 | if (pymol->error) |
---|
528 | return(TCL_ERROR); |
---|
529 | |
---|
530 | va_start(ap, format); |
---|
531 | vsnprintf(buffer, 800, format, ap); |
---|
532 | va_end(ap); |
---|
533 | trace("to-pymol>(%s)", buffer); |
---|
534 | write(pymol->p_stdin, buffer, strlen(buffer)); |
---|
535 | |
---|
536 | if (waitForString(pymol, "PyMOL>", buffer, 800)) { |
---|
537 | trace("pymolproxy: Timeout reading data [%s]\n",buffer); |
---|
538 | pymol->error = 1; |
---|
539 | pymol->status = TCL_ERROR; |
---|
540 | return pymol->status; |
---|
541 | } |
---|
542 | |
---|
543 | return( pymol->status ); |
---|
544 | } |
---|
545 | |
---|
546 | static int |
---|
547 | BallNStickCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
548 | { |
---|
549 | int ghost = 0, defer = 0, push = 0, arg; |
---|
550 | const char *model = "all"; |
---|
551 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
552 | |
---|
553 | clear_error(pymol); |
---|
554 | |
---|
555 | for(arg = 1; arg < argc; arg++) { |
---|
556 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
557 | defer = 1; |
---|
558 | else if (strcmp(argv[arg],"-push") == 0) |
---|
559 | push = 1; |
---|
560 | else if (strcmp(argv[arg],"-ghost") == 0) |
---|
561 | ghost = 1; |
---|
562 | else if (strcmp(argv[arg],"-normal") == 0) |
---|
563 | ghost = 0; |
---|
564 | else if (strcmp(argv[arg],"-model") == 0) { |
---|
565 | if (++arg < argc) |
---|
566 | model = argv[arg]; |
---|
567 | } |
---|
568 | else |
---|
569 | model = argv[arg]; |
---|
570 | } |
---|
571 | |
---|
572 | pymol->invalidate_cache = 1; |
---|
573 | pymol->need_update = !defer || push; |
---|
574 | pymol->immediate_update |= push; |
---|
575 | |
---|
576 | sendf(pymol, "hide everything,%s\n",model); |
---|
577 | sendf(pymol, "set stick_color,white,%s\n",model); |
---|
578 | |
---|
579 | if (ghost) |
---|
580 | sendf(pymol, "set stick_radius,0.1,%s\n",model); |
---|
581 | else |
---|
582 | sendf(pymol, "set stick_radius,0.14,%s\n",model); |
---|
583 | |
---|
584 | sendf(pymol, "set sphere_scale=0.25,%s\n", model); |
---|
585 | |
---|
586 | if (ghost) { |
---|
587 | sendf(pymol, "set sphere_transparency,0.75,%s\n", model); |
---|
588 | sendf(pymol, "set stick_transparency,0.75,%s\n", model); |
---|
589 | } |
---|
590 | else { |
---|
591 | sendf(pymol, "set sphere_transparency,0,%s\n", model); |
---|
592 | sendf(pymol, "set stick_transparency,0,%s\n", model); |
---|
593 | } |
---|
594 | |
---|
595 | sendf(pymol, "show sticks,%s\n",model); |
---|
596 | sendf(pymol, "show spheres,%s\n",model); |
---|
597 | |
---|
598 | if (pymol->labels) |
---|
599 | sendf(pymol, "show labels,%s\n", model); |
---|
600 | |
---|
601 | return( pymol->status ); |
---|
602 | } |
---|
603 | |
---|
604 | static int |
---|
605 | SpheresCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
606 | { |
---|
607 | int defer = 0, ghost = 0, push = 0, arg; |
---|
608 | const char *model = "all"; |
---|
609 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
610 | |
---|
611 | clear_error(pymol); |
---|
612 | |
---|
613 | for(arg = 1; arg < argc; arg++) { |
---|
614 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
615 | defer = 1; |
---|
616 | else if (strcmp(argv[arg],"-push") == 0) |
---|
617 | push = 1; |
---|
618 | else if (strcmp(argv[arg],"-ghost") == 0) |
---|
619 | ghost = 1; |
---|
620 | else if (strcmp(argv[arg],"-normal") == 0) |
---|
621 | ghost = 0; |
---|
622 | else if (strcmp(argv[arg],"-model") == 0) { |
---|
623 | if (++arg < argc) |
---|
624 | model = argv[arg]; |
---|
625 | } |
---|
626 | else |
---|
627 | model = argv[arg]; |
---|
628 | } |
---|
629 | |
---|
630 | pymol->invalidate_cache = 1; |
---|
631 | pymol->need_update = !defer || push; |
---|
632 | pymol->immediate_update |= push; |
---|
633 | |
---|
634 | sendf(pymol, "hide everything, %s\n", model); |
---|
635 | sendf(pymol, "set sphere_scale,0.41,%s\n", model); |
---|
636 | //sendf(pymol, "set sphere_quality,2,%s\n", model); |
---|
637 | sendf(pymol, "set ambient,.2,%s\n", model); |
---|
638 | |
---|
639 | if (ghost) |
---|
640 | sendf(pymol, "set sphere_transparency,.75,%s\n", model); |
---|
641 | else |
---|
642 | sendf(pymol, "set sphere_transparency,0,%s\n", model); |
---|
643 | |
---|
644 | sendf(pymol, "show spheres,%s\n", model); |
---|
645 | |
---|
646 | if (pymol->labels) |
---|
647 | sendf(pymol, "show labels,%s\n", model); |
---|
648 | |
---|
649 | return pymol->status; |
---|
650 | } |
---|
651 | |
---|
652 | static int |
---|
653 | LinesCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
654 | { |
---|
655 | int ghost = 0, defer = 0, push = 0, arg; |
---|
656 | const char *model = "all"; |
---|
657 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
658 | |
---|
659 | clear_error(pymol); |
---|
660 | |
---|
661 | for(arg = 1; arg < argc; arg++) { |
---|
662 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
663 | defer = 1; |
---|
664 | else if (strcmp(argv[arg],"-push") == 0) |
---|
665 | push = 1; |
---|
666 | else if (strcmp(argv[arg],"-ghost") == 0) |
---|
667 | ghost = 1; |
---|
668 | else if (strcmp(argv[arg],"-normal") == 0) |
---|
669 | ghost = 0; |
---|
670 | else if (strcmp(argv[arg],"-model") == 0) { |
---|
671 | if (++arg < argc) |
---|
672 | model = argv[arg]; |
---|
673 | } |
---|
674 | else |
---|
675 | model = argv[arg]; |
---|
676 | } |
---|
677 | |
---|
678 | pymol->invalidate_cache = 1; |
---|
679 | pymol->need_update = !defer || push; |
---|
680 | pymol->immediate_update |= push; |
---|
681 | |
---|
682 | sendf(pymol, "hide everything,%s\n",model); |
---|
683 | |
---|
684 | if (ghost) |
---|
685 | sendf(pymol, "set line_width,.25,%s\n",model); |
---|
686 | else |
---|
687 | sendf(pymol, "set line_width,1,%s\n",model); |
---|
688 | |
---|
689 | sendf(pymol, "show lines,%s\n",model); |
---|
690 | |
---|
691 | if (pymol->labels) |
---|
692 | sendf(pymol, "show labels,%s\n",model); |
---|
693 | |
---|
694 | return pymol->status; |
---|
695 | } |
---|
696 | |
---|
697 | static int |
---|
698 | DisableCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
699 | { |
---|
700 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
701 | const char *model = "all"; |
---|
702 | int arg, defer = 0, push = 0; |
---|
703 | |
---|
704 | clear_error(pymol); |
---|
705 | |
---|
706 | for(arg = 1; arg < argc; arg++) { |
---|
707 | |
---|
708 | if (strcmp(argv[arg], "-defer") == 0 ) |
---|
709 | defer = 1; |
---|
710 | else if (strcmp(argv[arg], "-push") == 0 ) |
---|
711 | push = 1; |
---|
712 | else |
---|
713 | model = argv[arg]; |
---|
714 | |
---|
715 | } |
---|
716 | |
---|
717 | pymol->need_update = !defer || push; |
---|
718 | pymol->immediate_update |= push; |
---|
719 | pymol->invalidate_cache = 1; |
---|
720 | |
---|
721 | sendf( pymol, "disable %s\n", model); |
---|
722 | |
---|
723 | return pymol->status; |
---|
724 | } |
---|
725 | |
---|
726 | static int |
---|
727 | EnableCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
728 | { |
---|
729 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
730 | const char *model = "all"; |
---|
731 | int arg, defer = 0, push = 0; |
---|
732 | |
---|
733 | clear_error(pymol); |
---|
734 | |
---|
735 | for(arg = 1; arg < argc; arg++) { |
---|
736 | |
---|
737 | if (strcmp(argv[arg],"-defer") == 0) |
---|
738 | defer = 1; |
---|
739 | else if (strcmp(argv[arg], "-push") == 0 ) |
---|
740 | push = 1; |
---|
741 | else |
---|
742 | model = argv[arg]; |
---|
743 | |
---|
744 | } |
---|
745 | |
---|
746 | pymol->need_update = !defer || push; |
---|
747 | pymol->immediate_update |= push; |
---|
748 | pymol->invalidate_cache = 1; |
---|
749 | |
---|
750 | sendf( pymol, "enable %s\n", model); |
---|
751 | |
---|
752 | return pymol->status; |
---|
753 | } |
---|
754 | |
---|
755 | static int |
---|
756 | VMouseCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
757 | { |
---|
758 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
759 | int arg, defer = 0, push = 0, varg = 1; |
---|
760 | int arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0, arg5 = 0; |
---|
761 | |
---|
762 | clear_error(pymol); |
---|
763 | |
---|
764 | for(arg = 1; arg < argc; arg++) { |
---|
765 | if (strcmp(argv[arg], "-defer") == 0) |
---|
766 | defer = 1; |
---|
767 | else if (strcmp(argv[arg], "-push") == 0) |
---|
768 | push = 1; |
---|
769 | else if (varg == 1) { |
---|
770 | arg1 = atoi(argv[arg]); |
---|
771 | varg++; |
---|
772 | } |
---|
773 | else if (varg == 2) { |
---|
774 | arg2 = atoi(argv[arg]); |
---|
775 | varg++; |
---|
776 | } |
---|
777 | else if (varg == 3) { |
---|
778 | arg3 = atoi(argv[arg]); |
---|
779 | varg++; |
---|
780 | } |
---|
781 | else if (varg == 4) { |
---|
782 | arg4 = atoi(argv[arg]); |
---|
783 | varg++; |
---|
784 | } |
---|
785 | else if (varg == 5) { |
---|
786 | arg5 = atoi(argv[arg]); |
---|
787 | varg++; |
---|
788 | } |
---|
789 | } |
---|
790 | |
---|
791 | pymol->need_update = !defer || push; |
---|
792 | pymol->immediate_update |= push; |
---|
793 | pymol->invalidate_cache = 1; |
---|
794 | |
---|
795 | sendf(pymol, "vmouse %d,%d,%d,%d,%d\n", arg1,arg2,arg3,arg4,arg5); |
---|
796 | |
---|
797 | return pymol->status; |
---|
798 | } |
---|
799 | |
---|
800 | static int |
---|
801 | RawCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
802 | { |
---|
803 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
804 | DyBuffer buffer; |
---|
805 | int arg, defer = 0, push = 0; |
---|
806 | const char *cmd; |
---|
807 | clear_error(pymol); |
---|
808 | |
---|
809 | dyBufferInit(&buffer); |
---|
810 | |
---|
811 | cmd = NULL; |
---|
812 | for(arg = 1; arg < argc; arg++) { |
---|
813 | if (strcmp(argv[arg], "-defer") == 0) |
---|
814 | defer = 1; |
---|
815 | else if (strcmp(argv[arg], "-push") == 0) |
---|
816 | push = 1; |
---|
817 | else { |
---|
818 | cmd = argv[arg]; |
---|
819 | } |
---|
820 | } |
---|
821 | |
---|
822 | pymol->need_update = !defer || push; |
---|
823 | pymol->immediate_update |= push; |
---|
824 | pymol->invalidate_cache = 1; |
---|
825 | |
---|
826 | sendf(pymol,"%s\n", cmd); |
---|
827 | dyBufferFree(&buffer); |
---|
828 | |
---|
829 | return pymol->status; |
---|
830 | } |
---|
831 | |
---|
832 | static int |
---|
833 | LabelCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
834 | { |
---|
835 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
836 | int state = 1; |
---|
837 | int arg, push = 0, defer = 0; |
---|
838 | |
---|
839 | clear_error(pymol); |
---|
840 | |
---|
841 | for(arg = 1; arg < argc; arg++) { |
---|
842 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
843 | defer = 1; |
---|
844 | else if (strcmp(argv[arg],"-push") == 0 ) |
---|
845 | push = 1; |
---|
846 | else if (strcmp(argv[arg],"on") == 0 ) |
---|
847 | state = 1; |
---|
848 | else if (strcmp(argv[arg],"off") == 0 ) |
---|
849 | state = 0; |
---|
850 | else if (strcmp(argv[arg],"toggle") == 0 ) |
---|
851 | state = !pymol->labels; |
---|
852 | } |
---|
853 | |
---|
854 | pymol->need_update = !defer || push; |
---|
855 | pymol->immediate_update |= push; |
---|
856 | pymol->invalidate_cache = 1; |
---|
857 | |
---|
858 | if (state) { |
---|
859 | sendf(pymol, "set label_color,white,all\n"); |
---|
860 | sendf(pymol, "set label_size,14,all\n"); |
---|
861 | sendf(pymol, "label all,\"%%s%%s\" %% (ID,name)\n"); |
---|
862 | } |
---|
863 | else |
---|
864 | sendf(pymol, "label all\n"); |
---|
865 | |
---|
866 | pymol->labels = state; |
---|
867 | |
---|
868 | return pymol->status; |
---|
869 | } |
---|
870 | |
---|
871 | static int |
---|
872 | FrameCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
873 | { |
---|
874 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
875 | int frame = 0; |
---|
876 | int arg, push = 0, defer = 0; |
---|
877 | |
---|
878 | clear_error(pymol); |
---|
879 | |
---|
880 | for(arg = 1; arg < argc; arg++) { |
---|
881 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
882 | defer = 1; |
---|
883 | else if (strcmp(argv[arg],"-push") == 0 ) |
---|
884 | push = 1; |
---|
885 | else |
---|
886 | frame = atoi(argv[arg]); |
---|
887 | } |
---|
888 | |
---|
889 | pymol->need_update = !defer || push; |
---|
890 | pymol->immediate_update |= push; |
---|
891 | |
---|
892 | pymol->frame = frame; |
---|
893 | |
---|
894 | sendf(pymol,"frame %d\n", frame); |
---|
895 | |
---|
896 | return pymol->status; |
---|
897 | } |
---|
898 | |
---|
899 | static int |
---|
900 | ResetCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
901 | { |
---|
902 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
903 | int arg, push = 0, defer = 0; |
---|
904 | |
---|
905 | clear_error(pymol); |
---|
906 | |
---|
907 | for(arg = 1; arg < argc; arg++) { |
---|
908 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
909 | defer = 1; |
---|
910 | else if (strcmp(argv[arg],"-push") == 0 ) |
---|
911 | push = 1; |
---|
912 | } |
---|
913 | |
---|
914 | pymol->need_update = !defer || push; |
---|
915 | pymol->immediate_update |= push; |
---|
916 | pymol->invalidate_cache = 1; |
---|
917 | |
---|
918 | sendf(pymol, "reset\n"); |
---|
919 | sendf(pymol, "zoom buffer=2\n"); |
---|
920 | |
---|
921 | return pymol->status; |
---|
922 | } |
---|
923 | |
---|
924 | static int |
---|
925 | RockCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
926 | { |
---|
927 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
928 | float y = 0.0; |
---|
929 | int arg, push = 0, defer = 0; |
---|
930 | |
---|
931 | clear_error(pymol); |
---|
932 | |
---|
933 | for(arg = 1; arg < argc; arg++) { |
---|
934 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
935 | defer = 1; |
---|
936 | else if (strcmp(argv[arg],"-push") == 0 ) |
---|
937 | push = 1; |
---|
938 | else |
---|
939 | y = atof( argv[arg] ); |
---|
940 | } |
---|
941 | |
---|
942 | pymol->need_update = !defer || push; |
---|
943 | pymol->immediate_update |= push; |
---|
944 | |
---|
945 | sendf(pymol,"turn y, %f\n", y - pymol->rock_offset); |
---|
946 | |
---|
947 | pymol->rock_offset = y; |
---|
948 | |
---|
949 | return pymol->status; |
---|
950 | } |
---|
951 | |
---|
952 | static int |
---|
953 | ViewportCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
954 | { |
---|
955 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
956 | int width = 640, height = 480; |
---|
957 | int defer = 0, push = 0, arg, varg = 1; |
---|
958 | |
---|
959 | clear_error(pymol); |
---|
960 | |
---|
961 | for(arg = 1; arg < argc; arg++) { |
---|
962 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
963 | defer = 1; |
---|
964 | else if ( strcmp(argv[arg], "-push") == 0 ) |
---|
965 | push = 1; |
---|
966 | else if (varg == 1) { |
---|
967 | width = atoi(argv[arg]); |
---|
968 | height = width; |
---|
969 | varg++; |
---|
970 | } |
---|
971 | else if (varg == 2) { |
---|
972 | height = atoi(argv[arg]); |
---|
973 | varg++; |
---|
974 | } |
---|
975 | } |
---|
976 | |
---|
977 | pymol->need_update = !defer || push; |
---|
978 | pymol->immediate_update |= push; |
---|
979 | pymol->invalidate_cache = 1; |
---|
980 | |
---|
981 | sendf(pymol, "viewport %d,%d\n", width, height); |
---|
982 | |
---|
983 | //usleep(205000); // .2s delay for pymol to update its geometry *HACK ALERT* |
---|
984 | |
---|
985 | return pymol->status; |
---|
986 | } |
---|
987 | |
---|
988 | static int |
---|
989 | LoadPDB2Cmd(ClientData cdata, Tcl_Interp *interp, int argc, |
---|
990 | const char *argv[]) |
---|
991 | { |
---|
992 | const char *pdbdata, *name; |
---|
993 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
994 | int state = 1; |
---|
995 | int arg, defer = 0, push = 0, varg = 1; |
---|
996 | |
---|
997 | if (pymol == NULL) |
---|
998 | return(TCL_ERROR); |
---|
999 | clear_error(pymol); |
---|
1000 | pdbdata = name = NULL; /* Suppress compiler warning. */ |
---|
1001 | for(arg = 1; arg < argc; arg++) { |
---|
1002 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
1003 | defer = 1; |
---|
1004 | else if (strcmp(argv[arg],"-push") == 0) |
---|
1005 | push = 1; |
---|
1006 | else if (varg == 1) { |
---|
1007 | pdbdata = argv[arg]; |
---|
1008 | varg++; |
---|
1009 | } else if (varg == 2) { |
---|
1010 | name = argv[arg]; |
---|
1011 | varg++; |
---|
1012 | } else if (varg == 3) { |
---|
1013 | state = atoi( argv[arg] ); |
---|
1014 | varg++; |
---|
1015 | } |
---|
1016 | } |
---|
1017 | |
---|
1018 | pymol->need_update = !defer || push; |
---|
1019 | pymol->immediate_update |= push; |
---|
1020 | |
---|
1021 | { |
---|
1022 | char fileName[200]; |
---|
1023 | FILE *f; |
---|
1024 | size_t nBytes, nWritten; |
---|
1025 | |
---|
1026 | sprintf(fileName, "/tmp/pymol%d.pdb", getpid()); |
---|
1027 | f = fopen(fileName, "w"); |
---|
1028 | trace("pymolproxy: open file %s as %x\n", fileName, f); |
---|
1029 | if (f == NULL) { |
---|
1030 | trace("pymolproxy: failed to open %s %d\n", fileName, errno); |
---|
1031 | perror("pymolproxy"); |
---|
1032 | } |
---|
1033 | nBytes = strlen(pdbdata); |
---|
1034 | nWritten = fwrite(pdbdata, sizeof(char), nBytes, f); |
---|
1035 | if (nBytes != nWritten) { |
---|
1036 | trace("pymolproxy: short write %d wanted %d bytes\n", nWritten, |
---|
1037 | nBytes); |
---|
1038 | perror("pymolproxy"); |
---|
1039 | } |
---|
1040 | fclose(f); |
---|
1041 | sendf(pymol, "load %s, %s, %d\n", fileName, name, state); |
---|
1042 | } |
---|
1043 | sendf(pymol, "zoom buffer=2\n"); |
---|
1044 | return(pymol->status); |
---|
1045 | } |
---|
1046 | |
---|
1047 | static int |
---|
1048 | LoadPDBCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
1049 | { |
---|
1050 | const char *pdbdata, *name; |
---|
1051 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
1052 | int state = 1; |
---|
1053 | int arg, defer = 0, push = 0, varg = 1; |
---|
1054 | |
---|
1055 | clear_error(pymol); |
---|
1056 | |
---|
1057 | pdbdata = name = NULL; /* Suppress compiler warning. */ |
---|
1058 | for(arg = 1; arg < argc; arg++) { |
---|
1059 | if ( strcmp(argv[arg],"-defer") == 0 ) |
---|
1060 | defer = 1; |
---|
1061 | else if (strcmp(argv[arg],"-push") == 0) |
---|
1062 | push = 1; |
---|
1063 | else if (varg == 1) { |
---|
1064 | pdbdata = argv[arg]; |
---|
1065 | varg++; |
---|
1066 | } |
---|
1067 | else if (varg == 2) { |
---|
1068 | name = argv[arg]; |
---|
1069 | varg++; |
---|
1070 | } |
---|
1071 | else if (varg == 3) { |
---|
1072 | state = atoi( argv[arg] ); |
---|
1073 | varg++; |
---|
1074 | } |
---|
1075 | } |
---|
1076 | |
---|
1077 | pymol->need_update = !defer || push; |
---|
1078 | pymol->immediate_update |= push; |
---|
1079 | |
---|
1080 | { |
---|
1081 | int count; |
---|
1082 | const char *p; |
---|
1083 | char *q, *newdata; |
---|
1084 | |
---|
1085 | count = 0; |
---|
1086 | for (p = pdbdata; *p != '\0'; p++) { |
---|
1087 | if (*p == '\n') { |
---|
1088 | count++; |
---|
1089 | } |
---|
1090 | count++; |
---|
1091 | } |
---|
1092 | |
---|
1093 | q = newdata = malloc(count + 100); |
---|
1094 | strcpy(newdata, "cmd.read_pdbstr(\"\"\"\\\n"); |
---|
1095 | q = newdata + strlen(newdata); |
---|
1096 | for (p = pdbdata; *p != '\0'; p++, q++) { |
---|
1097 | if (*p == '\n') { |
---|
1098 | *q++ = '\\'; |
---|
1099 | } |
---|
1100 | *q = *p; |
---|
1101 | } |
---|
1102 | sprintf(q, "\\\n\"\"\",\"%s\",%d)\n", name, state); |
---|
1103 | { |
---|
1104 | char expect[800]; |
---|
1105 | |
---|
1106 | sprintf(expect, "PyMOL>\"\"\",\"%s\",%d)\n", name, state); |
---|
1107 | send_expect(pymol, expect, newdata); |
---|
1108 | } |
---|
1109 | free(newdata); |
---|
1110 | } |
---|
1111 | sendf(pymol, "zoom buffer=2\n"); |
---|
1112 | |
---|
1113 | return pymol->status; |
---|
1114 | } |
---|
1115 | |
---|
1116 | |
---|
1117 | static int |
---|
1118 | RotateCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
1119 | { |
---|
1120 | double turnx = 0.0; |
---|
1121 | double turny = 0.0; |
---|
1122 | double turnz = 0.0; |
---|
1123 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
1124 | int defer = 0, push = 0, arg, varg = 1; |
---|
1125 | |
---|
1126 | clear_error(pymol); |
---|
1127 | |
---|
1128 | for(arg = 1; arg < argc; arg++) { |
---|
1129 | if (strcmp(argv[arg],"-defer") == 0) { |
---|
1130 | defer = 1; |
---|
1131 | } else if (strcmp(argv[arg],"-push") == 0) { |
---|
1132 | push = 1; |
---|
1133 | } else if (varg == 1) { |
---|
1134 | turnx = atof(argv[arg]); |
---|
1135 | varg++; |
---|
1136 | } else if (varg == 2) { |
---|
1137 | turny = atof(argv[arg]); |
---|
1138 | varg++; |
---|
1139 | } else if (varg == 3) { |
---|
1140 | turnz = atof(argv[arg]); |
---|
1141 | varg++; |
---|
1142 | } |
---|
1143 | } |
---|
1144 | pymol->need_update = !defer || push; |
---|
1145 | pymol->immediate_update |= push; |
---|
1146 | pymol->invalidate_cache = 1; |
---|
1147 | |
---|
1148 | if (turnx != 0.0) |
---|
1149 | sendf(pymol,"turn x, %f\n", turnx); |
---|
1150 | |
---|
1151 | if (turny != 0.0) |
---|
1152 | sendf(pymol,"turn y, %f\n", turny); |
---|
1153 | |
---|
1154 | if (turnz != 0.0) |
---|
1155 | sendf(pymol,"turn z, %f\n", turnz); |
---|
1156 | |
---|
1157 | return pymol->status; |
---|
1158 | } |
---|
1159 | |
---|
1160 | static int |
---|
1161 | ZoomCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
1162 | { |
---|
1163 | double factor = 0.0; |
---|
1164 | double zmove = 0.0; |
---|
1165 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
1166 | int defer = 0, push = 0, arg, varg = 1; |
---|
1167 | |
---|
1168 | clear_error(pymol); |
---|
1169 | |
---|
1170 | for(arg = 1; arg < argc; arg++) { |
---|
1171 | if (strcmp(argv[arg],"-defer") == 0) |
---|
1172 | defer = 1; |
---|
1173 | else if (strcmp(argv[arg],"-push") == 0) |
---|
1174 | push = 1; |
---|
1175 | else if (varg == 1) { |
---|
1176 | factor = atof(argv[arg]); |
---|
1177 | varg++; |
---|
1178 | } |
---|
1179 | } |
---|
1180 | zmove = factor * -75; |
---|
1181 | |
---|
1182 | pymol->need_update = !defer || push; |
---|
1183 | pymol->immediate_update |= push; |
---|
1184 | pymol->invalidate_cache = 1; |
---|
1185 | |
---|
1186 | if (zmove != 0.0) |
---|
1187 | sendf(pymol,"move z, %f\n", factor); |
---|
1188 | |
---|
1189 | return pymol->status; |
---|
1190 | } |
---|
1191 | |
---|
1192 | static int |
---|
1193 | PNGCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
1194 | { |
---|
1195 | char buffer[800]; |
---|
1196 | unsigned int nBytes=0; |
---|
1197 | float samples = 0.0; |
---|
1198 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
1199 | |
---|
1200 | clear_error(pymol); |
---|
1201 | |
---|
1202 | if (pymol->invalidate_cache) |
---|
1203 | pymol->cacheid++; |
---|
1204 | |
---|
1205 | pymol->need_update = 0; |
---|
1206 | pymol->immediate_update = 0; |
---|
1207 | pymol->invalidate_cache = 0; |
---|
1208 | |
---|
1209 | sendf(pymol,"png -\n"); |
---|
1210 | |
---|
1211 | waitForString(pymol, "image follows: ", buffer, 800); |
---|
1212 | |
---|
1213 | sscanf(buffer, "image follows: %d %f\n", &nBytes, &samples); |
---|
1214 | |
---|
1215 | write(3, &samples, sizeof(samples)); |
---|
1216 | |
---|
1217 | dyBufferSetLength(&pymol->image, nBytes); |
---|
1218 | |
---|
1219 | bread(pymol->p_stdout, pymol->image.data, pymol->image.used); |
---|
1220 | |
---|
1221 | waitForString(pymol, " ScenePNG", buffer,800); |
---|
1222 | |
---|
1223 | if ((nBytes > 0) && (pymol->image.used == nBytes)) { |
---|
1224 | sprintf(buffer, "nv>image %d %d %d %d\n", |
---|
1225 | nBytes, pymol->cacheid, pymol->frame, pymol->rock_offset); |
---|
1226 | trace("to-molvis> %s", buffer); |
---|
1227 | write(pymol->c_stdin, buffer, strlen(buffer)); |
---|
1228 | bwrite(pymol->c_stdin, pymol->image.data, nBytes); |
---|
1229 | stats.nFrames++; |
---|
1230 | stats.nBytes += nBytes; |
---|
1231 | } |
---|
1232 | return pymol->status; |
---|
1233 | } |
---|
1234 | |
---|
1235 | static int |
---|
1236 | BMPCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[]) |
---|
1237 | { |
---|
1238 | char buffer[800]; |
---|
1239 | unsigned int nBytes=0; |
---|
1240 | float samples = 0.0; |
---|
1241 | PymolProxy *pymol = (PymolProxy *) cdata; |
---|
1242 | |
---|
1243 | clear_error(pymol); |
---|
1244 | |
---|
1245 | if (pymol->invalidate_cache) |
---|
1246 | pymol->cacheid++; |
---|
1247 | |
---|
1248 | pymol->need_update = 0; |
---|
1249 | pymol->immediate_update = 0; |
---|
1250 | pymol->invalidate_cache = 0; |
---|
1251 | |
---|
1252 | sendf(pymol,"bmp -\n"); |
---|
1253 | |
---|
1254 | waitForString(pymol, "image follows: ", buffer, 800); |
---|
1255 | |
---|
1256 | sscanf(buffer, "image follows: %d %f\n", &nBytes, &samples); |
---|
1257 | write(3,&samples,sizeof(samples)); |
---|
1258 | |
---|
1259 | dyBufferSetLength(&pymol->image, nBytes); |
---|
1260 | |
---|
1261 | bread(pymol->p_stdout, pymol->image.data, pymol->image.used); |
---|
1262 | |
---|
1263 | if ((nBytes > 0) && (pymol->image.used == nBytes)) { |
---|
1264 | sprintf(buffer, "nv>image %d %d %d %d\n", |
---|
1265 | nBytes, pymol->cacheid, pymol->frame, pymol->rock_offset); |
---|
1266 | write(pymol->c_stdin, buffer, strlen(buffer)); |
---|
1267 | trace("to-molvis buffer=%s\n", buffer); |
---|
1268 | bwrite(pymol->c_stdin, pymol->image.data, nBytes); |
---|
1269 | stats.nFrames++; |
---|
1270 | stats.nBytes += nBytes; |
---|
1271 | } |
---|
1272 | return pymol->status; |
---|
1273 | } |
---|
1274 | |
---|
1275 | static int |
---|
1276 | ProxyInit(int c_in, int c_out, char *const *argv) |
---|
1277 | { |
---|
1278 | int flags, status, result = 0; |
---|
1279 | int pairIn[2]; |
---|
1280 | int pairOut[2]; |
---|
1281 | int pairErr[2]; |
---|
1282 | Tcl_Interp *interp; |
---|
1283 | Tcl_DString cmdbuffer; |
---|
1284 | DyBuffer dybuffer, dybuffer2; |
---|
1285 | struct pollfd ufd[3]; |
---|
1286 | int pid; |
---|
1287 | PymolProxy pymol; |
---|
1288 | struct timeval now, end; |
---|
1289 | int timeout; |
---|
1290 | |
---|
1291 | /* Create three pipes for communication with the external application. One |
---|
1292 | * each for the applications's: stdin, stdout, and stderr */ |
---|
1293 | |
---|
1294 | if (pipe(pairIn) == -1) |
---|
1295 | return(-1); |
---|
1296 | |
---|
1297 | if (pipe(pairOut) == -1) { |
---|
1298 | close(pairIn[0]); |
---|
1299 | close(pairIn[1]); |
---|
1300 | return(-1); |
---|
1301 | } |
---|
1302 | |
---|
1303 | if (pipe(pairErr) == -1) { |
---|
1304 | close(pairIn[0]); |
---|
1305 | close(pairIn[1]); |
---|
1306 | close(pairOut[0]); |
---|
1307 | close(pairOut[1]); |
---|
1308 | return(-1); |
---|
1309 | } |
---|
1310 | |
---|
1311 | /* Fork the new process. Connect i/o to the new socket. */ |
---|
1312 | |
---|
1313 | pid = fork(); |
---|
1314 | |
---|
1315 | if (pid < 0) { |
---|
1316 | fprintf(stderr, "can't fork process: %s\n", strerror(errno)); |
---|
1317 | return(-3); |
---|
1318 | } |
---|
1319 | if (pid == 0) { |
---|
1320 | int fd; |
---|
1321 | |
---|
1322 | /* Child process */ |
---|
1323 | |
---|
1324 | /* |
---|
1325 | * Create a new process group, so we can later kill this process and |
---|
1326 | * all its children without affecting the process that created this |
---|
1327 | * one. |
---|
1328 | */ |
---|
1329 | setpgid(pid, 0); |
---|
1330 | |
---|
1331 | /* Redirect stdin, stdout, and stderr to pipes before execing */ |
---|
1332 | dup2(pairIn[0] ,0); // stdin |
---|
1333 | dup2(pairOut[1],1); // stdout |
---|
1334 | dup2(pairErr[1],2); // stderr |
---|
1335 | |
---|
1336 | for(fd = 3; fd < FD_SETSIZE; fd++) /* close all other descriptors */ |
---|
1337 | close(fd); |
---|
1338 | |
---|
1339 | execvp(argv[0], argv); |
---|
1340 | trace("pymolproxy: Failed to start pyMol %s\n", argv[0]); |
---|
1341 | exit(-1); |
---|
1342 | } |
---|
1343 | stats.child = pid; |
---|
1344 | |
---|
1345 | /* close opposite end of pipe, these now belong to the child process */ |
---|
1346 | close(pairIn[0]); |
---|
1347 | close(pairOut[1]); |
---|
1348 | close(pairErr[1]); |
---|
1349 | |
---|
1350 | signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE (ie if nanoscale terminates) |
---|
1351 | |
---|
1352 | pymol.p_stdin = pairIn[1]; |
---|
1353 | pymol.p_stdout = pairOut[0]; |
---|
1354 | pymol.p_stderr = pairErr[0]; |
---|
1355 | pymol.c_stdin = c_in; |
---|
1356 | pymol.c_stdout = c_out; |
---|
1357 | pymol.labels = 0; |
---|
1358 | pymol.need_update = 0; |
---|
1359 | pymol.can_update = 1; |
---|
1360 | pymol.immediate_update = 0; |
---|
1361 | pymol.sync = 0; |
---|
1362 | pymol.frame = 1; |
---|
1363 | pymol.rock_offset = 0; |
---|
1364 | pymol.cacheid = 0; |
---|
1365 | pymol.invalidate_cache = 0; |
---|
1366 | |
---|
1367 | ufd[0].fd = pymol.c_stdout; |
---|
1368 | ufd[0].events = POLLIN | POLLHUP; /* ensure catching EOF */ |
---|
1369 | ufd[1].fd = pymol.p_stdout; |
---|
1370 | ufd[1].events = POLLIN | POLLHUP; |
---|
1371 | ufd[2].fd = pymol.p_stderr; |
---|
1372 | ufd[2].events = POLLIN | POLLHUP; |
---|
1373 | |
---|
1374 | flags = fcntl(pymol.p_stdout, F_GETFL); |
---|
1375 | fcntl(pymol.p_stdout, F_SETFL, flags|O_NONBLOCK); |
---|
1376 | |
---|
1377 | interp = Tcl_CreateInterp(); |
---|
1378 | Tcl_MakeSafe(interp); |
---|
1379 | |
---|
1380 | Tcl_DStringInit(&cmdbuffer); |
---|
1381 | dyBufferInit(&pymol.image); |
---|
1382 | dyBufferInit(&dybuffer); |
---|
1383 | dyBufferInit(&dybuffer2); |
---|
1384 | |
---|
1385 | Tcl_CreateCommand(interp, "bmp", BMPCmd, &pymol, NULL); |
---|
1386 | Tcl_CreateCommand(interp, "png", PNGCmd, &pymol, NULL); |
---|
1387 | Tcl_CreateCommand(interp, "screen", ViewportCmd, &pymol, NULL); |
---|
1388 | Tcl_CreateCommand(interp, "viewport",ViewportCmd, &pymol, NULL); |
---|
1389 | Tcl_CreateCommand(interp, "rotate", RotateCmd, &pymol, NULL); |
---|
1390 | Tcl_CreateCommand(interp, "zoom", ZoomCmd, &pymol, NULL); |
---|
1391 | Tcl_CreateCommand(interp, "loadpdb.old", LoadPDBCmd, &pymol, NULL); |
---|
1392 | Tcl_CreateCommand(interp, "loadpdb", LoadPDB2Cmd, &pymol, NULL); |
---|
1393 | Tcl_CreateCommand(interp, "ballnstick",BallNStickCmd, &pymol, NULL); |
---|
1394 | Tcl_CreateCommand(interp, "spheres", SpheresCmd, &pymol, NULL); |
---|
1395 | Tcl_CreateCommand(interp, "lines", LinesCmd, &pymol, NULL); |
---|
1396 | Tcl_CreateCommand(interp, "raw", RawCmd, &pymol, NULL); |
---|
1397 | Tcl_CreateCommand(interp, "label", LabelCmd, &pymol, NULL); |
---|
1398 | Tcl_CreateCommand(interp, "reset", ResetCmd, &pymol, NULL); |
---|
1399 | Tcl_CreateCommand(interp, "rock", RockCmd, &pymol, NULL); |
---|
1400 | Tcl_CreateCommand(interp, "frame", FrameCmd, &pymol, NULL); |
---|
1401 | Tcl_CreateCommand(interp, "vmouse", VMouseCmd, &pymol, NULL); |
---|
1402 | Tcl_CreateCommand(interp, "disable", DisableCmd, &pymol, NULL); |
---|
1403 | Tcl_CreateCommand(interp, "enable", EnableCmd, &pymol, NULL); |
---|
1404 | |
---|
1405 | // Main Proxy Loop |
---|
1406 | // accept tcl commands from socket |
---|
1407 | // translate them into pyMol commands, and issue them to child proccess |
---|
1408 | // send images back |
---|
1409 | |
---|
1410 | gettimeofday(&end, NULL); |
---|
1411 | stats.start = end; |
---|
1412 | while(1) { |
---|
1413 | char ch; |
---|
1414 | |
---|
1415 | gettimeofday(&now,NULL); |
---|
1416 | |
---|
1417 | if ( (!pymol.need_update) ) |
---|
1418 | timeout = -1; |
---|
1419 | else if ((now.tv_sec > end.tv_sec) || ( (now.tv_sec == end.tv_sec) && (now.tv_usec >= end.tv_usec)) ) |
---|
1420 | timeout = 0; |
---|
1421 | else { |
---|
1422 | timeout = (end.tv_sec - now.tv_sec) * 1000; |
---|
1423 | |
---|
1424 | if (end.tv_usec > now.tv_usec) |
---|
1425 | timeout += (end.tv_usec - now.tv_usec) / 1000; |
---|
1426 | else |
---|
1427 | timeout += (((1000000 + end.tv_usec) - now.tv_usec) / 1000) - 1000; |
---|
1428 | |
---|
1429 | } |
---|
1430 | |
---|
1431 | if (!pymol.immediate_update) |
---|
1432 | status = poll(ufd, 3, timeout); |
---|
1433 | else |
---|
1434 | status = 0; |
---|
1435 | |
---|
1436 | if ( status < 0 ) { |
---|
1437 | trace("pymolproxy: POLL ERROR: status = %d, errno = %d, %s \n", status,errno,strerror(errno)); |
---|
1438 | } else if (status > 0) { |
---|
1439 | gettimeofday(&now,NULL); |
---|
1440 | |
---|
1441 | if (ufd[0].revents) { /* Client Stdout Connection: command input */ |
---|
1442 | if (read(ufd[0].fd,&ch,1) <= 0) { |
---|
1443 | if (errno != EINTR) { |
---|
1444 | trace("pymolproxy: lost client connection (%d).\n", errno); |
---|
1445 | break; |
---|
1446 | } |
---|
1447 | } else { |
---|
1448 | Tcl_DStringAppend(&cmdbuffer, &ch, 1); |
---|
1449 | |
---|
1450 | if (ch == '\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) { |
---|
1451 | int result; |
---|
1452 | |
---|
1453 | result = ExecuteCommand(interp, &cmdbuffer); |
---|
1454 | if (timeout == 0) status = 0; // send update |
---|
1455 | } |
---|
1456 | } |
---|
1457 | } |
---|
1458 | |
---|
1459 | if (ufd[1].revents ) { /* pyMol Stdout Connection: pymol (unexpected) output */ |
---|
1460 | if (read(ufd[1].fd, &ch, 1) <= 0) { |
---|
1461 | if (errno != EINTR) { |
---|
1462 | trace("pymolproxy: lost connection (stdout) to pymol server\n"); |
---|
1463 | break; |
---|
1464 | } |
---|
1465 | } else { |
---|
1466 | dyBufferAppend(&dybuffer, &ch, 1); |
---|
1467 | |
---|
1468 | if (ch == '\n') { |
---|
1469 | ch = 0; |
---|
1470 | dyBufferAppend(&dybuffer, &ch, 1); |
---|
1471 | trace("STDOUT>%s",dybuffer.data); |
---|
1472 | dyBufferSetLength(&dybuffer,0); |
---|
1473 | } |
---|
1474 | } |
---|
1475 | } |
---|
1476 | |
---|
1477 | if (ufd[2].revents) { /* pyMol Stderr Connection: pymol standard error output */ |
---|
1478 | if (read(ufd[2].fd, &ch, 1) <= 0) { |
---|
1479 | if (errno != EINTR) { |
---|
1480 | trace("pymolproxy: lost connection (stderr) to pymol server\n"); |
---|
1481 | break; |
---|
1482 | } |
---|
1483 | } else { |
---|
1484 | dyBufferAppend(&dybuffer2, &ch, 1); |
---|
1485 | |
---|
1486 | if (ch == '\n') { |
---|
1487 | ch = 0; |
---|
1488 | dyBufferAppend(&dybuffer2, &ch, 1); |
---|
1489 | trace("stderr>%s", dybuffer2.data); |
---|
1490 | dyBufferSetLength(&dybuffer2,0); |
---|
1491 | } |
---|
1492 | } |
---|
1493 | } |
---|
1494 | } |
---|
1495 | |
---|
1496 | if (status == 0) { |
---|
1497 | gettimeofday(&now,NULL); |
---|
1498 | |
---|
1499 | if (pymol.need_update && pymol.can_update) |
---|
1500 | Tcl_Eval(interp, "bmp -\n"); |
---|
1501 | |
---|
1502 | end.tv_sec = now.tv_sec; |
---|
1503 | end.tv_usec = now.tv_usec + 150000; |
---|
1504 | |
---|
1505 | if (end.tv_usec >= 1000000) { |
---|
1506 | end.tv_sec++; |
---|
1507 | end.tv_usec -= 1000000; |
---|
1508 | } |
---|
1509 | |
---|
1510 | } |
---|
1511 | |
---|
1512 | } |
---|
1513 | |
---|
1514 | status = waitpid(pid, &result, WNOHANG); |
---|
1515 | if (status == -1) { |
---|
1516 | trace("pymolproxy: error waiting on pymol server to exit (%d)\n", errno); |
---|
1517 | } else if (status == 0) { |
---|
1518 | trace("pymolproxy: attempting to SIGTERM pymol server\n"); |
---|
1519 | kill(-pid, SIGTERM); // kill process group |
---|
1520 | alarm(5); |
---|
1521 | status = waitpid(pid, &result, 0); |
---|
1522 | alarm(0); |
---|
1523 | |
---|
1524 | while ((status == -1) && (errno == EINTR)) { |
---|
1525 | trace("pymolproxy: Attempting to SIGKILL process.\n"); |
---|
1526 | kill(-pid, SIGKILL); // kill process group |
---|
1527 | alarm(10); |
---|
1528 | status = waitpid(pid, &result, 0); |
---|
1529 | alarm(0); |
---|
1530 | } |
---|
1531 | } |
---|
1532 | |
---|
1533 | trace("pymolproxy: pymol server process ended (%d)\n", result); |
---|
1534 | |
---|
1535 | dyBufferFree(&pymol.image); |
---|
1536 | |
---|
1537 | Tcl_DeleteInterp(interp); |
---|
1538 | DoExit(result); |
---|
1539 | return 0; |
---|
1540 | } |
---|
1541 | |
---|
1542 | #ifdef STANDALONE |
---|
1543 | |
---|
1544 | int |
---|
1545 | main(int argc, char *argv[]) |
---|
1546 | { |
---|
1547 | flog = stderr; |
---|
1548 | if (debug) { |
---|
1549 | char fileName[200]; |
---|
1550 | sprintf(fileName, "/tmp/pymolproxy%d.log", getpid()); |
---|
1551 | flog = fopen(fileName, "w"); |
---|
1552 | } |
---|
1553 | ProxyInit(fileno(stdout), fileno(stdin), argv + 1); |
---|
1554 | return 0; |
---|
1555 | } |
---|
1556 | |
---|
1557 | #endif |
---|
1558 | |
---|