reg_anno annotations; typedef struct { int job; /* REG_ANNO */ } reg_anno;
Sent when only the annotations (tags) for a contig have been updated. It is
sometimes simplest for clients to handle REG_ANNO
in the same manner as
REG_LENGTH
. However in some cases it can be much more efficient to
handle separately as it may be easier to redisplay annotations than to
redisplay everything.
reg_register c_register; reg_deregister c_deregister; typedef struct { int job; /* REG_REGISTER, REG_DEREGISTER */ int id; /* Registration id */ int type; /* Registration type */ int contig; /* Contig number */ } reg_register, reg_deregister;
Both of these notifications share the same structure. They are sent whenever a registration or deregistration of another piece of data is performed for this contig. An example of the use of this is within the stop codon display which enables use of the "Refresh" button when a contig editor is running. The id, type and contig fields here are the same as the fields with the same name from the contig_reg_t structure.
reg_highlight_read highlight; typedef struct { int job; /* REG_HIGHLIGHT_READ */ int seq; /* Gel reading number (-ve == contig consensus) */ int val; /* 1==highlight, 0==dehighlight */ } reg_highlight_read;
This is used for notifying that an individual reading has been highlighted. It's purpose is to allow displays to synchronise highlighting of data. For instance, both the contig editor and template display send and acknowledge this notification. Thus when a name in the editor is highlighted the template display will highlight the appropriate reading, and vice versa.
When seq is positive it represents the reading to highlight, otherwise it is 0 minus the contig number (not leftmost reading number).
reg_buffer_start buffer_start; reg_buffer_end buffer_end; typedef struct { int job; } reg_buffer_start, reg_buffer_end;
These two notifications share the same structure, which holds no information.
The purpose of REG_BUFFER_START
is simply as a signal that many
notifications will be arriving in quick succession, until a
REG_BUFFER_END
request arrives. The purpose is to speed up redisplay of
functions registered with many contigs.
As an example consider the enter tags function. This adds tags to many,
potentially all, contigs. We can keep track of which contigs we need to send
REG_ANNO
requests to, and send them with code similar to the following:
/* Notify of the start of the flurry of updates */ rs.job = REG_BUFFER_START; for (i = 0; i < NumContigs(args.io); i++) { if (contigs[i]&1) { contig_notify(args.io, i+1, (reg_data *)&rs); } } /* Now notify all the contigs that we've added tags to */ ra.job = REG_ANNO; for (i = 0; i < NumContigs(args.io); i++) { if (contigs[i]&1) { contig_notify(args.io, i+1, (reg_data *)&ra); } } /* Notify of the end of the flurry of updates */ re.job = REG_BUFFER_END; for (i = 0; i < NumContigs(args.io); i++) { if (contigs[i]&1) { contig_notify(args.io, i+1, (reg_data *)&re); } }
Consider the action of the contig selector. This needs to refresh the display
whenever any modifications are made, including annotations. The enter tags
function needs to send notifications to many contigs, thus the contig selector
will receive many requests. It is obviously more efficient for the contig
selector to only redisplay once. The addition of BUFFER_START
and
BUFFER_END
solve this. As we don't know exactly which functions will be
registered with which contigs, the enter tags code has to notify every contig.
Hence the contig selector code must keep a count on the start and end of
buffers so that it only needs to redisplay on the last buffer end. This code
is as follows (tidied up and much shortened for brevity):
switch(jdata->job) { case REG_BUFFER_START: { cs->buffer_count++; cs->do_update = REG_BUFFER_START; return; } case REG_BUFFER_END: { cs->buffer_count--; if (cs->buffer_count <= 0) { cs->buffer_count = 0; if (cs->do_update & REG_LENGTH) { [ Redisplay Contigs ] } else if (cs->do_update & REG_ANNO) { [ Redisplay Tags ] } else if (cs->do_update & REG_ORDER) { [ Shuffle Order] } cs->do_update = 0; } return; } case REG_ANNO: { if (!cs->do_update) { [ Redisplay Tags ] } else { cs->do_update |= REG_ANNO; } return; } /* etc */
For further examples of handling buffering see the template display code.