Common Desktop Environment: ToolTalk Messaging Overview

The Coeditor.C File

The Coeditor.C file, shown in Example B-3, shows the ToolTalk code that needs to be included in every editor application to pass a media callback and reply when a request has been completed. It also shows other optional ToolTalk functions that can be included in an editor application.


Note -

Ellipses (...) indicates code that has been omitted.



Example B-3 The CoEditor.C File

...  

CoEditor::CoEditor(
    Widget *parent 
) 
{
   _init();
    _init( parent ); 
} 

CoEditor::CoEditor(
    Widget     *parent,
    const char *file 
) 
{
    _init();
    _init( parent );
    _load( file ); 
}  

CoEditor::CoEditor(
    Widget       *parent,
    Tt_messagemsg,
    const char      * /*docname*/,
    Tt_status   &status 
) 
{
    _init();
    status = _init( msg );
    if (status != TT_OK) {
             return;
    }
   _init( parent );
   status = _acceptContract( msg ); 
}  

CoEditor::CoEditor(
    Widget       *parent,
    Tt_message       msg,
    int                     /*readOnly*/,
    const char     *file,
    const char     * /*docname*/,
    Tt_status  &status 
) 
{
    _init();
    status = _init( msg );
    if (status != TT_OK) {
           return;
    }
    _init( parent );
    status = _load( file );
    if (status != TT_OK) {
           return;
    }
    status = _acceptContract( msg ); 
}  

CoEditor::CoEditor(
    Widget       *parent,
    Tt_messagemsg,
    int                  /*readOnly*/,
    unsigned char  *contents,
    int             /*len*/,
    const char     * /*docname*/,
    Tt_status  &status 
) 
{
    _init();
    status = _init( msg );
    if (status != TT_OK) {
          return;
    }
    _init( parent );
    XtVaSetValues( (Widget)_text,
           XtNsourceType,      (XtArgVal)OL_STRING_SOURCE,
           XtNsource,          (XtArgVal)contents,
           NULL );
    _textBuf  = OlTextEditTextBuffer( _text );
    RegisterTextBufferUpdate( _textBuf, CoEditor::_textUpdateCB_,
                (caddr_t)this );
    status = _acceptContract( msg ); 
}  

CoEditor::~CoEditor() 
{
    //
    // No need for a separate save if we are sending the document
    // back in a reply.
    //
    if (_contract == 0) {
           if (_modifiedByMe) {
           // we revert before quitting if we don't want to save
           _save();
           }
 } else {
        int   len;
        char *contents = _contents( &len );
        // Reply to media load callback with edited contents of text
        ttmedia_load_reply( _contract, (unsigned char *)contents,
               len, 1 );
        if (contents != 0) {
        XtFree( contents );
        }     _contract = 0;
   }
   numEditors--; // XXX assumes user destroys windows LIFO! 
}  

Tt_message 
CoEditor::loadISOLatin1_(
    Tt_message          msg,
    Tttk_op             op,
    Tt_status           diagnosis,
    unsigned char     *contents,
    int                len,
    char           *file,
    char           *docname,
    void              *pWidget 
) 
{
    static const char *here = "CoEditor::loadISOLatin1_()";

     Tt_status status   = TT_OK;
    CoEditor *coEditor = 0;
    if (diagnosis != TT_OK) {
           // toolkit detected an error
           if (tt_message_status( msg ) == TT_WRN_START_MESSAGE) {
           //
           // Error is in start message!  We now have no
           // reason to live, so tell main() to exit().
           //
           abortCode = 2;
           }
           // let toolkit handle the error
           return msg;
 }
 if ((op == TTME_COMPOSE) & (file == 0)) {
       oEditor = new CoEditor( (Widget *)pWidget, msg, docname,
             status );
 } else if (len > 0) {
        coEditor = new CoEditor( (Widget *)pWidget, msg,
                (op == TTME_DISPLAY),
                contents, len, docname, status ); 
} else if (file != 0) {
        coEditor = new CoEditor( (Widget *)pWidget, msg,
                (op == TTME_DISPLAY),
                file, docname, status );
 } else { 
       // Fail a message
        tttk_message_fail( msg, TT_DESKTOP_ENODATA, 0, 1 ); }
        tt_free( (caddr_t)contents );
        tt_free( file );
        tt_free( docname );
        return 0; }  

void 
CoEditor::_init() 
{
    _baseFrame       = 0;
    _controls        = 0;
    _fileBut         = 0;
    _editBut         = 0;
    _scrolledWin     = 0;
    _text            = 0;
    _textBuf         = 0;
    _modifiedByMe    = FALSE;
    _modifiedByOther = 0;
    _contract        = 0;
    _contractPats    = 0;
    _filePats        = 0;
    _file            = 0;
    _x       = INT_MAX;
    _y       = INT_MAX;
    _w       = INT_MAX;
    _h       = INT_MAX; 
}  

Tt_status 
CoEditor::_init(
    Tt_message msg 
) 
{
    int width, height, xOffset, yOffset;
    width = height = xOffset = yOffset = INT_MAX;
    _contract = msg;
    ttdt_sender_imprint_on( 0, msg, 0, &_w, &_h, &_x, &_y,
              10 * timeOutFactor );
    return TT_OK; 
}  

typedef enum {
    Open,
    Save,
    SaveAs,
    Revert 
} FileOp;  

static const char *fileButs[] = {
 "Open...",
 "Save",
 "Save as...",
 "Revert"
 };  

const int numFileButs = sizeof( fileButs ) / sizeof( const char * );  

typedef enum {
    Undo,
    Cut,
    Copy,
    Paste,
    Delete,
    SelText,
    SelAppt 
} EditOp;  

static const char *editButs[] = {
    "Undo",
    "Cut",
    "Copy",
    "Paste",
    "Delete",
    "Text as ISO_Latin_1",
    "Text as Appointment" 
};  

const int numEditButs = sizeof( editButs ) / sizeof( const char * );  

void 
CoEditor::_init(
    Widget *parent 
) 
{
    if (*parent == 0) {
           if (_contract != 0) {
           //
           // Re-open display, since $DISPLAY may have changed by
           // ttdt_sender_imprint_on().
           //
           XtCloseDisplay( myDpy );
           myDpy = XtOpenDisplay( myContext, 0, 0, "CoEd", 0, 0,
                        pArgc, globalArgv );
        }
        *parent = XtAppCreateShell( 0, "CoEd",
               applicationShellWidgetClass, myDpy, 0, 0 );
            XtVaSetValues( *parent,
                   XtNmappedWhenManaged, False,
                   XtNheight, 1,
                   XtNwidth, 1,
                   0 );
            XtRealizeWidget( *parent );
        }
        shell = XtCreatePopupShell( "CoEd", 
                 applicationShellWidgetClass, *parent, 0, 0 );
        XtVaSetValues( shell, XtNuserData, this, 0 );
        // Pop up next to our parent
        if ((_x != INT_MAX) && (_y != INT_MAX) && (_w != INT_MAX)) {
               // XXX Be smarter about picking a geometry
               Dimension x     = _x + _w;
               Dimension y     = _y;
               XtVaSetValues( shell, XtNx, x, XtNy, y, 0 );
        }
       XtAddCallback( shell, XtNdestroyCallback, CoEditor::_destroyCB_,
                  this );
        OlAddCallback( shell, XtNwmProtocol, CoEditor::_wmProtocolCB_, this );
        _baseFrame = XtVaCreateManagedWidget(
                  "baseFrame", rubberTileWidgetClass, shell, 0 );
       _controls = XtVaCreateManagedWidget( "controls",
                  controlAreaWidgetClass, _baseFrame,
                  XtNweight, (XtArgVal)0,
                  0 );
        _fileBut = XtVaCreateManagedWidget( "File",
                  menuButtonWidgetClass, _controls, 0 );
        Widget menuPane;
        XtVaGetValues( _fileBut, XtNmenuPane, &menuPane, 0 );
        for (int i = 0; i < numFileButs; i++) {
               Widget but = XtVaCreateManagedWidget( fileButs[i],
               oblongButtonWidgetClass, menuPane,
               XtNuserData, i, 0 );
               XtAddCallback( but, XtNselect, CoEditor::_fileButsCB_, this );
        }        _editBut = XtVaCreateManagedWidget( "Edit",
                 menuButtonWidgetClass, _controls, 0 );
        XtVaGetValues( _editBut, XtNmenuPane, &menuPane, 0 );
        for (i = 0; i < numEditButs; i++) {
               Widget but = XtVaCreateManagedWidget( editButs[i],
                  oblongButtonWidgetClass, menuPane,
                  XtNuserData, i, 0 );
               XtAddCallback( but, XtNselect, CoEditor::_editButsCB_, this );
        }         _scrolledWin = XtVaCreateManagedWidget(
                  "scrolledWin", scrolledWindowWidgetClass,
                  _baseFrame,
                  XtNforceVerticalSB,(XtArgVal)True,
                  0 );
        _text = (TextEditWidget)XtVaCreateManagedWidget(
                  "text", textEditWidgetClass, _scrolledWin,
                  0 );
        XtVaSetValues( (Widget)_text, XtNuserData, this, 0 );
         XtRealizeWidget( shell );
        XtPopup( shell, XtGrabNone );
        if (numEditors < MaxEditors) {
               editors[ numEditors ] = this;
               numEditors++;
        }
        if (numEditors >= maxBuffers) {
       tt_ptype_undeclare( "DT_CoEd" );
       } 
}  
Tt_status 
CoEditor::_unload() 
{
        Tt_status status = TT_OK;
        if (_filePats != 0) {
           // Unregister interest in ToolTalk events and destroy patterns
           status = ttdt_file_quit( _filePats, 1 );
           _filePats = 0;
        }
        if (_file != 0) {
               free( _file );
               _file = 0;
        }
        return status; 
}
  
Tt_status 
CoEditor::_load(
    const char *file 
) 
{
        int reloading = 1;
        if (file != 0) {
               if ((_file != 0) && (strcmp( file, _file ) != 0)) {
               reloading = 0;
               _unload();
               } else {
               _file = strdup( file );
               }
        }
               // Join a file Can be called recursively, below
        if (_filePats == 0) {
              _filePats = ttdt_file_join( _file, TT_SCOPE_NONE, 1,
                         CoEditor::_fileCB_, this );
        }
        XtVaSetValues( (Widget)_text,
              XtNsourceType,            (XtArgVal)OL_DISK_SOURCE,
              XtNsource,                 (XtArgVal)_file,
              NULL );       _textBuf  = OlTextEditTextBuffer( _text );
        RegisterTextBufferUpdate( _textBuf, CoEditor::_textUpdateCB_,
                    (caddr_t)this );
       if (_modifiedByMe && reloading) {
               ttdt_file_event( _contract, TTDT_REVERTED, _filePats, 1 );
        }        _modifiedByMe = 0;
          // Does the file have any changes pending? 
       _modifiedByOther = ttdt_Get_Modified( _contract, _file, TT_BOTH,
                            10 * timeOutFactor );
        if (_modifiedByOther) {
               int choice = userChoice( myContext, _baseFrame,
                   "Another tool has modifications pending for "
                   "this file.\nDo you want to ask it to save "
                   "or revert the file?", 3, "Save", "Revert",
                   "Ignore" );
               Tt_status status = TT_OK;
            switch (choice) {
               case 0:
                        // Save pending changes
               status = ttdt_Save( _contract, _file, TT_BOTH,
                          10 * timeOutFactor );
               break;
                case 1:
                 // Revert file to last version
               status = ttdt_Revert( _contract, _file, TT_BOTH,
                           10 * timeOutFactor );
               break;
               }
               if (status != TT_OK) {
               char *s = tt_status_message( status );
               userChoice( myContext, _baseFrame, s, 1, "Okay" );
               tt_free( s );
               } else if (choice == 0) {
               // file was saved, so reload<
               return _load( 0 );
               } else if (choice == 1) {
               // file was reverted
                _modifiedByOther = 0;
               }
        }
        return TT_OK; 
}  

Tt_status 
CoEditor::_load(
    unsigned char  *contents,
    int       //len 
) 
{
    _unload();
    XtVaSetValues( (Widget)_text,
    XtNsourceType,                (XtArgVal)OL_DISK_SOURCE,
    XtNsource,                    (XtArgVal)contents,
    NULL );
  _textBuf  = OlTextEditTextBuffer( _text );
 	RegisterTextBufferUpdate( _textBuf, CoEditor::_textUpdateCB_,
 				  (caddr_t)this ); 	_modifiedByMe = 0;
 	_modifiedByOther = 0; 	return TT_OK; 
}  

// 
// Caller responsible for reporting any errors to user 
// 
Tt_status 
CoEditor::_save() 
{
    Tt_status status;
    if (_file != 0) {
           if (SaveTextBuffer( _textBuf, _file ) != SAVE_SUCCESS) {
              return TT_DESKTOP_EIO;
           }
           _modifiedByMe = 0;
           _modifiedByOther = 0;
           // File has been saved
          ttdt_file_event( _contract, TTDT_SAVED, _filePats, 1 );
 	}
 	if (_contract != 0) {
         int   len = 0;
         char *contents = 0;
         if (_file == 0) {
         // If you worry that the buffer might be big,
         // you could instead try a a temp file to
         // transfer the data "out of band".
         contents = _contents( &len );
         }
         status = ttmedia_Deposit( _contract, 0, "ISO_Latin_1",
                  (unsigned char *)contents,
                 len, _file, 10 * timeOutFactor );
         if (status != TT_OK) {
         return status;
         }
                  _modifiedByMe = 0;
                 _modifiedByOther = 0;
               if (contents != 0) {
                      XtFree( contents );
                  }
       }
     return status;
}  

Tt_status 
CoEditor::_revert() // XXX how about we always just send Revert? :-) 
{
    if (! _modifiedByMe) {
           return TT_OK;
    }    return _load( 0 ); // XXX what if it's not a file? keep last deposit 
}  

void 
CoEditor::_destroyCB_(
    Widget    w,
    XtPointer coEditor,
    XtPointer call_data 
) 
{
    ((CoEditor *)coEditor)->_destroyCB( w, call_data ); 
}  

void 
CoEditor::_destroyCB(
    Widget    ,
    XtPointer //call_data 
) 
{
    delete this; 
}  

void 
CoEditor::_wmProtocolCB_(
    Widget    w,
    XtPointer coEditor,
    XtPointer wmMsg 
) 
{
    ((CoEditor *)coEditor)->_wmProtocolCB( w, (OlWMProtocolVerify*)wmMsg ); 
}  

void 
CoEditor::_wmProtocolCB(
    Widget   w,
    OlWMProtocolVerify     *wmMsg 
) 
{
    switch (wmMsg->msgtype) {
        case OL_WM_DELETE_WINDOW:
           if (_modifiedByMe) {
           int choice = 
             userChoice( myContext, _baseFrame,
                     "The text has unsaved changes.",
                     3, "Save, then Quit",
                     "Discard, then Quit",
                     "Cancel" );
              switch (choice) {
                  case 0:
                 break;
                  case 1:
                 _revert();
                 break;
                 case 2:
                 return;
           }
           }
           if  umEditors > 1) {
           XtDestroyWidget( shell );
           } else {
         // XXX OlWmProtocolAction() doesn't call destructor?!
           delete this;
           OlWMProtocolAction( w, wmMsg, OL_DEFAULTACTION );
           }
           break;
        default:
           OlWMProtocolAction( w, wmMsg, OL_DEFAULTACTION );
           break;
    } 
}  

void 
CoEditor::_fileButsCB_(
    Widget    button,
    XtPointer coEditor,
    XtPointer call_data 
) 
{
    ((CoEditor *)coEditor)->_fileButsCB( button, call_data ); 
} 

void 
CoEditor::_fileButsCB(
    Widget    button,
    XtPointer //call_data 
) 
{
    FileOp op;    XtVaGetValues( button, XtNuserData, &op, 0 );
    Tt_status status = TT_OK;
    switch (op) {
       case Open:
          break;
       case Revert:
          status =_revert();
          break;
       case Save:
          status =_save();
          break;
       case SaveAs:
          break;
    }
    if (status != TT_OK) {
           _adviseUser( status );
    } 
}  

void 
CoEditor::_editButsCB_(
    Widget    button,
    XtPointer coEditor,
    XtPointer call_data 
) 
{
    ((CoEditor *)coEditor)->_editButsCB( button, call_data ); 
}  

void 
CoEditor::_editButsCB(
    Widget    button,
    XtPointer //call_data 
) 
{
    EditOp op;
    XtVaGetValues( button, XtNuserData, &op, 0 );
    Tt_status status = TT_OK;
    switch (op) {
           int   len;
           char      *contents;
           const char     *mediaType;
           Tt_messagemsg;
           Tt_pattern     *pats;
        case SelText:
        case SelAppt:
           if (op == SelText) {
              mediaType = "ISO_Latin_1";
           } else {
           mediaType = "DT_CM_Appointment";
           }
           //contents = _selection( &len );
           contents = _contents( &len );
           if (len <= 0) {
           return;
           } 
          // Media load callback 
          msg = ttmedia_load( _contract, CoEditor::_mediaLoadMsgCB_,
                             this, TTME_EDIT, mediaType, 
                             (unsigned char *)contents, len, 0, 0, 1 );
                      if (contents != 0) {
                      XtFree( contents );
                      }
                      status = tt_ptr_error( msg );
                      if (status != TT_OK) {
                      break;
                      }
                      pats = ttdt_subcontract_manage( msg, 0, shell, this );
                      status = tt_ptr_error( pats );
                      if (status != TT_OK) {
                      break;
                      }
                      break;
} 	
if (status != TT_OK) {
               char *s = tt_status_message( status );
               char buf[ 1024 ];
               sprintf( buf, "%d: %s", status, s );
               tt_free( s );
               userChoice( myContext, _baseFrame, buf, 1, "Okay" );
     } 
}  

char *
 CoEditor::_contents(
    int *len ) {
    _textBuf  = OlTextEditTextBuffer( _text );
    TextLocation  start    = { 0, 0, 0 };
    TextLocation  end      = LastTextBufferLocation( _textBuf );
    char         *contents = GetTextBufferBlock( _textBuf, start, end );
    *len = 0;
    if (contents != 0) {
           *len = strlen( contents );
    }
    return contents; 
}  

Tt_status 
CoEditor::_acceptContract(
    Tt_message msg ) {
    static const char *here = "CoEditor::_acceptContract()";
     _contract = msg;
    if (tt_message_status( msg ) == TT_WRN_START_MESSAGE) {
                     //
                     // Join session before accepting start message,
                     // to prevent unnecessary starts of our ptype
                     //
                     Widget session_shell = shell;
                     if (maxBuffers > 1) {
                     //
                     // If we are in multi-window mode, just use
                     // our unmapped toplevel shell as our session
                     // shell, since we do not know if any particular
                     // window will exist the whole time we are in
                     // the session.
                     //
                     session_shell = XtParent(shell );
                     }
                     // Join the session and register patterns and callbacks
                     sessPats = ttdt_session_join( 0, 0, session_shell, this, 1 );
 }
       // Accept responsibility to handle a request
 _contractPats = ttdt_message_accept(
              msg, CoEditor::_contractCB_, shell, this,
              1, 1 );    
Tt_status status = tt_ptr_error( _contractPats );
    if (status != TT_OK) {
           return status;
    }    return status; 
}  

Tt_message 
CoEditor::_contractCB_(
    Tt_message,                                 //msg,
    Tttk_op,                                    //op,
    Widget,                                     //shell,
    void*,                                      //coEditor,
    Tt_message                                  //Contract 
) 
{
    return 0; }

void 
CoEditor::_editButCB_(
    Widget    w,
    XtPointer coEditor,
    XtPointer call_data 
) 
{
    ((CoEditor *)coEditor)->_editButCB( w, call_data ); 
}  

void 
CoEditor::_editButCB(
    Widget    ,
    XtPointer //call_data 
) 
{
    int       len;
    char   *contents = _contents( &len );
        // Media Load Callback
    Tt_message msg = ttmedia_load( _contract, CoEditor::_mediaLoadMsgCB_,
                                this, TTME_EDIT, "ISO_Latin_1",
                                (unsigned char *)contents,
                                len, 0, 0, 1 );
    if (contents != 0) {
           XtFree( contents );
    }
    Tt_pattern *pats = ttdt_subcontract_manage( msg, 0, shell, this ); 
}  

Tt_message 
CoEditor::_mediaLoadMsgCB_(
    Tt_message               msg,
    Tttk_op                  op,
    unsigned char    *contents,
    int               len,
    char             *file,
    void             *clientData 
) 
{
    return ((CoEditor *)clientData)->_mediaLoadMsgCB( msg, op,
                     contents, len, file ); }  

Tt_message 
CoEditor::_mediaLoadMsgCB(
    Tt_message              msg,
    Tttk_op,
    unsigned char  *contents,
    int                    len,
    char           *file 
) 
{
    if (len > 0) {
           XtVaSetValues( (Widget)_text,
           XtNsourceType,             (XtArgVal)OL_STRING_SOURCE,
           XtNsource,          (XtArgVal)contents,
           NULL );
           _textBuf  = OlTextEditTextBuffer( _text );
           RegisterTextBufferUpdate( _textBuf, CoEditor::_textUpdateCB_,
                    (caddr_t)this );
           // ReplaceBlockInTextBuffer
    } else if (file != 0) {
    }
    tt_message_destroy( msg );
    return 0; 
}  

void
CoEditor::_textUpdateCB_(
    XtPointer        coEditor,
    XtPointer        pTextBuffer,
    EditResult       status ) {
    if (coEditor == 0) {
           return;
    }
    ((CoEditor *)coEditor)->_textUpdateCB( (TextBuffer *)pTextBuffer,
                        status ); 
}

void 
CoEditor::_textUpdateCB(
    TextBuffer     *textBuf,
    EditResult            //editStatus ) {
    //Tt_status status;
    if (_textBuf != textBuf) {
           fprintf( stderr, "_textBuf != textBuf" );
    }
    if ((! _modifiedByMe) && TextBufferModified( _textBuf )) {
           _modifiedByMe = TRUE;
           // File has changes pending
           ttdt_file_event( _contract, TTDT_MODIFIED, _filePats, 1 );
    } 
} 
 
Tt_message 
CoEditor::_fileCB_(
    Tt_message                msg,
    Tttk_op            op,
    char              *pathname,
    void              *coEditor,
    int               trust,
    int               me 
) 
{
    tt_free( pathname );
    if (coEditor == 0) {
           return msg;
    }
    return ((CoEditor *)coEditor)->_fileCB( msg, op, pathname,
                    trust, me );
}  

Tt_message 
CoEditor::_fileCB(
    Tt_message                   msg,
    Tttk_op                        op,
    char                 *pathname,
    int,                               //trust
    int                                 //me 
) 
{ 
    tt_free( pathname );
Tt_status status = TT_OK;    
switch (op) {
        case TTDT_MODIFIED:
           if (_modifiedByMe) { 
          // Hmm, the other editor either doesn't know or
           // doesn't care that we are already modifying the
           // file, so the last saver will win.
           // XXX Or: a race condition has arisen!
           } else {
           // Interrogate user if she ever modifies the buffer
           _modifiedByOther = 1;
           XtAddCallback( (Widget)_text, XtNmodifyVerification,
               (XtCallbackProc)CoEditor::_textModifyCB_, 0 );
           }
           break;
        case TTDT_GET_MODIFIED:
           tt_message_arg_ival_set( msg, 1, _modifiedByMe );
           tt_message_reply( msg );
           break;
        case TTDT_SAVE:
           status = _save();
           if (status == TT_OK) {
          tt_message_reply( msg );
           } else {
           // Fail message
           tttk_message_fail( msg, status, 0, 0 );
           }
           break;
        case TTDT_REVERT:
           status = _revert();
           if (status == TT_OK) {
           tt_message_reply( msg );
           } else {
           // Fail message
           tttk_message_fail( msg, status, 0, 0 );
           }
           break;
        case TTDT_REVERTED:
        case TTDT_SAVED:
        case TTDT_MOVED:
        case TTDT_DELETED:
           printf( "CoEditor::_fileCB(): %s\n", tttk_op_string( op ));
           break;
     }
    tt_message_destroy( msg );
     return 0; 
}  

void CoEditor::_textModifyCB_(
    TextEditWidget             text,
    XtPointer                 ,
    OlTextModifyCallData  *mod 
) 
{
    CoEditor *coEditor = 0;
    XtVaGetValues( (Widget)text, XtNuserData, &coEditor, 0 );
    if (coEditor == 0) {
           return;
    }
    coEditor->_textModifyCB( mod ); 
} 

void 
CoEditor::_textModifyCB(
    OlTextModifyCallData *mod 
) 
{
    if (_modifiedByOther != 1) {
           return;
    }
    int cancel = userChoice( myContext, _baseFrame,
               "Another tool has modifications pending for this file.\n"
               "Are you sure you want to start modifying the file?",
               2, "Modify", "Cancel" );
    if (cancel) {
           mod->ok = FALSE;
    }
   _modifiedByOther = 2; 
}  

void 
CoEditor::_adviseUser(
    Tt_status status 
) 
{
    char *s = tt_status_message( status );
    char buf[ 1024 ];
    sprintf( buf,  "%d: %s", status, s );
    tt_free( s );
    userChoice( myContext, _baseFrame, buf, 1, "Okay" ); 
}