Ignore:
Timestamp:
Feb 19, 2009 3:48:11 PM (15 years ago)
Author:
gah
Message:

vizservers/pymolproxy/pymolproxy.c

Added atomscale and projection commands.
Created buffered input layers between client-proxy, server-proxy.
Also created non-blocking buffered image layer between proxy-client.
This is a major update to the proxy. It should be more efficient.

vizservers/nanoscale/server.c

Removed broadcast feature. It's not being used. The server never
redirects the client to another host.

vizservers/start_viz.sh.in

Fixed sed script to replace the last octet of IP address with
broadcast 255.

vizservers/configure.in

Added test of Cg libraries and includes. Gentoo has moved them
from /usr/lib to /opt/nvidia-cg-toolkit/lib.

vizservers/nanovis/Makefile.in

Added locations of Cg libraries and headers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/vizservers/pymolproxy/pymolproxy.c

    r1258 r1278  
    1717 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    1818 * ======================================================================
     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.
    1952 */
    2053
     
    6194    size_t nBytes;              /* # of bytes for all frames. */
    6295    size_t nCommands;           /* # of commands executed */
    63     double cmdTime;             /* Elasped time spend executing commands. */
     96    double cmdTime;             /* Elapsed time spend executing commands. */
    6497    struct timeval start;       /* Start of elapsed time. */
    6598} Stats;
     
    69102static FILE *flog;
    70103static int debug = 0;
     104#ifdef notdef
     105static long _flags = 0;
     106#endif
    71107
    72108typedef struct {
     
    74110    int   used;
    75111    int   allocated;
     112    ssize_t nWritten;
     113    size_t bytesLeft;
    76114} DyBuffer;
    77115
     116#define BUFFER_SIZE             4096
     117
    78118typedef 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
     130typedef struct {
     131    int serverInput;
     132    int serverOutput;
     133    int serverError;
     134    int clientInput;
     135    int clientOutput;
    84136    DyBuffer image;
    85     int need_update;
     137    Tcl_Interp *interp;
     138    int updatePending;
     139    int rotatePending;
     140    int scalePending;
     141    int forceUpdate;
    86142    int can_update;
    87     int immediate_update;
    88143    int sync;
    89     int labels;
     144    int showLabels;
    90145    int frame;
    91146    int rock_offset;
     
    94149    int error;
    95150    int status;
     151    ReadBuffer client;
     152    ReadBuffer server;
     153    float xAngle, yAngle, zAngle;
     154    float atomScale;
    96155} PymolProxy;
    97156
     157static void PollForEvents(PymolProxy *proxyPtr);
    98158static void
    99159trace TCL_VARARGS_DEF(char *, arg1)
     
    109169        fflush(flog);
    110170    }
     171}
     172
     173static void
     174InitBuffer(ReadBuffer *readPtr, int f)
     175{
     176    readPtr->fd = f;
     177    readPtr->fill = 0;
     178    readPtr->mark = 0;
     179}
     180
     181static void
     182FlushBuffer(ReadBuffer *readPtr)
     183{
     184    readPtr->fill = 0;
     185    readPtr->mark = 0;
     186}
     187
     188static int
     189FillBuffer(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
     234static char *
     235GetLine(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
     280static int
     281GetBytes(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
     322INLINE static void
     323clear_error(PymolProxy *proxyPtr)
     324{
     325    proxyPtr->error = 0;
     326    proxyPtr->status = TCL_OK;
     327}
     328
     329static int
     330Expect(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;
    111367}
    112368
     
    234490
    235491static int
    236 ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
     492ExecuteCommand(Tcl_Interp *interp, const char *cmd)
    237493{
    238494    struct timeval tv;
     
    243499    start = CVT2SECS(tv);
    244500
    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);
    248503
    249504    gettimeofday(&tv, NULL);
     
    255510}
    256511
    257 
    258512INLINE static void
    259 dyBufferInit(DyBuffer *buffer)
    260 {
    261     buffer->data = NULL;
    262     buffer->used = 0;
    263     buffer->allocated = 0;
     513dyBufferInit(DyBuffer *imgPtr)
     514{
     515    imgPtr->data = NULL;
     516    imgPtr->used = 0;
     517    imgPtr->allocated = 0;
     518    imgPtr->nWritten = 0;
     519    imgPtr->bytesLeft = 0;
    264520}
    265521
    266522INLINE static void
    267 dyBufferFree(DyBuffer *buffer)
    268 {
    269     assert(buffer != NULL);
    270     free(buffer->data);
    271     dyBufferInit(buffer);
     523dyBufferFree(DyBuffer *imgPtr)
     524{
     525    assert(imgPtr != NULL);
     526    if (imgPtr->data != NULL) {
     527        free(imgPtr->data);
     528    }
     529    dyBufferInit(imgPtr);
    272530}
    273531
     
    303561}
    304562
    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)
     563static void
     564WriteImage(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
     596static int
     597ReadImage(PymolProxy *proxyPtr, int fd, size)
    331598{
    332599    int result, total, left;
    333600
    334601    for( total = 0, left = size; left > 0; left -= result) {
    335         result = read(sock,buffer+total,left);
     602        result = read(fd, buffer+total, left);
    336603       
    337604        if (result > 0) {
     
    341608       
    342609        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,
    344611                  strerror(errno));
    345612            break;
     
    350617    return total;
    351618}
     619#endif
     620
     621static int
     622bwrite(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
     645static int
     646bread(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}
    352668
    353669#ifdef notdef
    354670
    355671static int
    356 bflush(int sock, char *buffer, int size, int bytes)
     672bflush(int fd, char *buffer, int size, int bytes)
    357673{
    358674    int bsize;
     
    364680            bsize = bytes;
    365681       
    366         bsize = bread(sock,buffer,bsize);
     682        bsize = bread(fd,buffer,bsize);
    367683       
    368684        bytes -= bsize;     
     
    421737}
    422738
    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
     740static int
     741getline(int fd, char *buffer, int size, int timeout)
    432742{
    433743    int pos = 0, status, timeo;
     
    439749    timeradd(&now,&tmo,&end);
    440750
    441     ufd.fd = sock;
     751    ufd.fd = fd;
    442752    ufd.events = POLLIN;
    443753
     
    455765
    456766        if (status > 0)
    457             status = read(sock,&buffer[pos],1);
     767            status = read(fd,&buffer[pos],1);
    458768
    459769        if ( (status < 0) && ( (errno == EINTR) || (errno == EAGAIN) ) )
     
    475785}
    476786
    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
     788static int
     789Pymol(PymolProxy *proxyPtr, char *format, ...)
     790{
    514791
    515792    if (proxyPtr->error) {
    516793        return TCL_ERROR;
    517794    }
    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
     831static void
     832DoRotate(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
     844static void
     845DoAtomScale(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
     853static int
     854AtomscaleCmd(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;
    535889}
    536890
     
    563917    }
    564918
    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);
    571925    if (ghost) {
    572926        radius = 0.1f;
     
    576930        transparency = 0.0f;
    577931    }
    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    }
    588944    return proxyPtr->status;
    589945}
    590946
    591 static int
    592 SpheresCmd(ClientData clientData, Tcl_Interp *interp, int argc,
     947
     948static int
     949BmpCmd(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
     1003static int
     1004DisableCmd(ClientData clientData, Tcl_Interp *interp, int argc,
    5931005           const char *argv[])
    5941006{
    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
     1034static int
     1035EnableCmd(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
     1064static int
     1065FrameCmd(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
     1095static int
     1096LabelCmd(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
     1135static int
     1136LinesCmd(ClientData clientData, Tcl_Interp *interp, int argc,
     1137         const char *argv[])
     1138{
     1139    int ghost = 0, defer = 0, push = 0, arg;
    5961140    const char *model = "all";
    5971141    PymolProxy *proxyPtr = clientData;
     1142    float lineWidth;
    5981143
    5991144    clear_error(proxyPtr);
     
    6161161    }
    6171162
    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    }
    6371175    return proxyPtr->status;
    6381176}
    6391177
    6401178static int
    641 LinesCmd(ClientData clientData, Tcl_Interp *interp, int argc,
     1179LoadPDBCmd(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
     1238static int
     1239OrthoscopicCmd(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 */
     1279static int
     1280PanCmd(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
     1315static int
     1316PngCmd(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
     1371static int
     1372RawCmd(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
     1403static int
     1404ResetCmd(ClientData clientData, Tcl_Interp *interp, int argc,
    6421405         const char *argv[])
    6431406{
    644     int ghost = 0, defer = 0, push = 0, arg;
    645     const char *model = "all";
    6461407    PymolProxy *proxyPtr = clientData;
    647     float lineWidth;
     1408    int arg, push = 0, defer = 0;
    6481409
    6491410    clear_error(proxyPtr);
     
    6521413        if ( strcmp(argv[arg],"-defer") == 0 )
    6531414            defer = 1;
    654         else if (strcmp(argv[arg],"-push") == 0)
     1415        else if (strcmp(argv[arg],"-push") == 0 )
    6551416            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
     1429static int
     1430RockCmd(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 */
     1472static int
     1473RotateCmd(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
     1524static int
     1525SpheresCmd(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) {
    6571541            ghost = 1;
    658         else if (strcmp(argv[arg],"-normal") == 0)
     1542        } else if (strcmp(argv[arg],"-normal") == 0) {
    6591543            ghost = 0;
    660         else if (strcmp(argv[arg],"-model") == 0) {
     1544        } else if (strcmp(argv[arg],"-model") == 0) {
    6611545            if (++arg < argc)
    6621546                model = argv[arg];
     1547        } else if (strcmp(argv[arg],"-scale") == 0) {
     1548            if (++arg < argc)
     1549                scale = atof(argv[arg]);
    6631550        }
    6641551        else
     
    6661553    }
    6671554
    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    }
    6801576    return proxyPtr->status;
    6811577}
    6821578
    6831579static int
    684 DisableCmd(ClientData clientData, Tcl_Interp *interp, int argc,
    685            const char *argv[])
     1580ScreenCmd(ClientData clientData, Tcl_Interp *interp, int argc,
     1581          const char *argv[])
    6861582{
    6871583    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;
    6901586
    6911587    clear_error(proxyPtr);
    6921588
    6931589    for(arg = 1; arg < argc; arg++) {
    694 
    695         if (strcmp(argv[arg], "-defer") == 0 )
     1590        if ( strcmp(argv[arg],"-defer") == 0 )
    6961591            defer = 1;
    697         else if (strcmp(argv[arg], "-push") == 0 )
     1592        else if ( strcmp(argv[arg], "-push") == 0 )
    6981593            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*
    7011612       
    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 int
    714 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         else
    730             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 
    7401613    return proxyPtr->status;
    7411614}
     
    7781651    }
    7791652
    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,
    7851658                    arg4, arg5);
    7861659
     
    7881661}
    7891662
    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 */
     1676static int
     1677ZoomCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
    10871678{
    10881679    double factor = 0.0;
     
    10981689            push = 1;
    10991690        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;
    11011696            varg++;
    11021697        }
    11031698    }
    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
    11071703    if (factor != 0.0) {
    1108         Send(proxyPtr,"move z,%f\n", factor);
     1704        Pymol(proxyPtr,"move z,%f\n", factor);
    11091705    }
    11101706    return proxyPtr->status;
    11111707}
    11121708
    1113 static int
    1114 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 int
    1150 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 int
    1193 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 }
    12311709       
    12321710static int
    12331711ProxyInit(int c_in, int c_out, char *const *argv)
    12341712{
    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];
    12391717    Tcl_Interp *interp;
    1240     Tcl_DString cmdbuffer;
    1241     DyBuffer dybuffer, dybuffer2;
    1242     struct pollfd ufd[3];
    1243     int pid;
     1718    int child;
    12441719    PymolProxy proxy;
    1245     struct timeval now, end;
    1246     int timeout;
     1720    struct timeval end;
    12471721
    12481722    /* Create three pipes for communication with the external application. One
    12491723     * each for the applications's: stdin, stdout, and stderr  */
    12501724
    1251     if (pipe(pairIn) == -1)
     1725    if (pipe(serverIn) == -1)
    12521726        return -1;
    12531727
    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]);
    12571731        return -1;
    12581732    }
    12591733
    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]);
    12651739        return -1;
    12661740    }
     
    12681742    /* Fork the new process.  Connect i/o to the new socket.  */
    12691743
    1270     pid = fork();
     1744    child = fork();
    12711745       
    1272     if (pid < 0) {
     1746    if (child < 0) {
    12731747        fprintf(stderr, "can't fork process: %s\n", strerror(errno));
    12741748        return -3;
    12751749    }
    1276     if (pid == 0) {
    1277         int fd;
     1750    if (child == 0) {
     1751        int f;
    12781752
    12791753        /* Child process */
     
    12841758         * one.
    12851759         */
    1286         setpgid(pid, 0);
     1760        setpgid(child, 0);
    12871761       
    12881762        /* 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
    12921767       
    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        }
    12951772       
    12961773        execvp(argv[0], argv);
     
    12981775        exit(-1);
    12991776    }
    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;
    13181797    proxy.sync = 0;
    13191798    proxy.frame = 1;
    13201799    proxy.rock_offset = 0;
    13211800    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;
    13341802    interp = Tcl_CreateInterp();
    13351803    Tcl_MakeSafe(interp);
    1336 
    1337     Tcl_DStringInit(&cmdbuffer);
     1804    proxy.interp = interp;
     1805    proxy.xAngle = proxy.yAngle = proxy.zAngle = 0.0f;
    13381806    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;
    13611833
    13621834    // Main Proxy Loop
     
    13641836    //  translate them into pyMol commands, and issue them to child proccess
    13651837    //  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);
    15101847    if (status == -1) {
    15111848        trace("error waiting on pymol server to exit: %s", strerror(errno));
    15121849    } else if (status == 0) {
    15131850        trace("attempting to signal (SIGTERM) pymol server.");
    1514         kill(-pid, SIGTERM); // kill process group
     1851        kill(-child, SIGTERM); // kill process group
    15151852        alarm(5);
    1516         status = waitpid(pid, &result, 0);
     1853        status = waitpid(child, &result, 0);
    15171854        alarm(0);
    15181855       
    15191856        while ((status == -1) && (errno == EINTR)) {
    15201857            trace("Attempting to signal (SIGKILL) pymol server.");
    1521             kill(-pid, SIGKILL); // kill process group
     1858            kill(-child, SIGKILL); // kill process group
    15221859            alarm(10);
    1523             status = waitpid(pid, &result, 0);
     1860            status = waitpid(child, &result, 0);
    15241861            alarm(0);
    15251862        }
     
    15471884        char fileName[200];
    15481885        sprintf(fileName, "/tmp/pymolproxy%d.log", getpid());
     1886        sprintf(fileName, "/tmp/pymolproxy.log");
    15491887        flog = fopen(fileName, "w");
    15501888    }   
     
    15551893#endif
    15561894
     1895
     1896static void
     1897PollForEvents(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.