Code Example B-1 CoEd Ptype File
ptype DT_CoEd { /* Process type identifier */
start "CoEd"; /* Start string */
handle: /* Receiving process */
/*
* Display ISO_Latin_1
*/
session Display( in ISO_Latin_1 contents ) => start opnum = 1; /* Signature */
session Display( in ISO_Latin_1 contents,
in messageID counterfoil ) => start opnum = 2;
session Display( in ISO_Latin_1 contents,
in title docName ) => start opnum = 3;
session Display( in ISO_Latin_1 contents,
in messageID counterfoil,
in title docName ) => start opnum = 4;
/*
* Edit ISO_Latin_1
*/
session Edit( inout ISO_Latin_1 contents ) => start opnum = 101;
session Edit( inout ISO_Latin_1 contents,
in messageID counterfoil ) => start opnum = 102;
session Edit( inout ISO_Latin_1 contents,
in title docName ) => start opnum = 103;
session Edit( inout ISO_Latin_1 contents,
in messageID counterfoil,
in title docName ) => start opnum = 104;
/*
* Compose ISO_Latin_1
*/
session Edit( out ISO_Latin_1 contents ) => start opnum = 201;
session Edit( out ISO_Latin_1 contents,
in messageID counterfoil ) => start opnum = 202;
session Edit( out ISO_Latin_1 contents,
in title docName ) => start opnum = 203;
session Edit( out ISO_Latin_1 contents,
in messageID counterfoil,
in title docName ) => start opnum = 204;
/*
* Open an ISO_Latin_1 buffer
*/
session Open( in ISO_Latin_1 contents,
out bufferID docBuf,
in boolean readOnly ) => start opnum = 400;
session Open( in ISO_Latin_1 contents,
out bufferID docBuf,
in boolean readOnly,
in boolean mapped ) => start opnum = 401;
session Open( in ISO_Latin_1 contents,
out bufferID docBuf,
in boolean readOnly,
in boolean mapped,
in integer shareLevel ) => start opnum = 402;
session Open( in ISO_Latin_1 contents,
out bufferID docBuf,
in boolean readOnly,
in boolean mapped,
in integer shareLevel,
in locator initialPos ) => start opnum = 403;
};
Code Example B-2 The CoEd.C File
/*
* CoEd.cc
*
* Copyright (c) 1991,1993 by Sun Microsystems.
*/
#include <stdlib.h>
#include <desktop/tttk.h> // Include the ToolTalk messaging toolkit
#include <CoEd.h>
#include "CoEditor.h"
#include "CoEdTextBuffer.h"
XtAppContext myContext;
Widget myTopWidget = 0;
Display *myDpy;
int abortCode = 0;
Tt_pattern *sessPats = 0; // Patterns returned when session joined
int timeOutFactor = 1000;
int maxBuffers = 1000;
int *pArgc;
char **globalArgv;
const char *ToolName = "CoEd";
const char *usage =
"Usage: CoEd [-p01] [-w n] [-t n] [file]\n"
" -p print ToolTalk procid\n"
" -0 do not open an initial composition window\n"
" -1 be a single-buffer editor\n"
" -w sleep for n seconds before coming up\n"
" -t use n as timeout factor, in milliseconds (default: 1000)\n"
;
void
main(
int argc,
char **argv
)
{
static const char *here = "main()";
int delay = 0;
int printid = 0;
int compose = 1;
char *file = 0;
OlToolkitInitialize( 0 );
XtToolkitInitialize();
myContext = XtCreateApplicationContext();
//
// This display may get closed, and another opened, inside
// CoEditor::_init(), if e.g. our parent is on a different screen
//
pArgc = &argc;
globalArgv = argv;
myDpy = XtOpenDisplay( myContext, 0, 0, "CoEd", 0, 0, &argc, argv );
int c;
while ((c = getopt( argc, argv, "p01w:t:" )) != -1) {
switch (c) {
case `p':
printid = 1;
break;
case `0':
compose = 0;
break;
case `1':
maxBuffers = 1;
break;
case `w':
delay = atoi( optarg );
break;
case `t':
timeOutFactor = atoi( optarg );
break;
default:
fputs( usage, stderr );
exit( 1 );
}
}
if (optind < argc) {
file = argv[ optind ];
}
while (delay > 0) {
sleep( 1 );
delay--;
}
int myTtFd; // Obtain process identifier
// Initialize toolkit and create a ToolTalk communication endpoint
char *myProcID = ttdt_open( &myTtFd, ToolName, "SunSoft", "%I", 1 );
// Declare ptype
ttmedia_ptype_declare( "DT_CoEd", 0, CoEditor::loadISOLatin1_,
(void *)&myTopWidget, 1 );
// Process the message that started us, if any
tttk_Xt_input_handler( 0, 0, 0 );
if (abortCode != 0) {
// Error in message that caused us to start.
exit( abortCode );
}
if (CoEditor::numEditors == 0) {
// started by hand, not by ToolTalk
if (file == 0) {
if (compose) {
new CoEditor( &myTopWidget );
}
} else {
new CoEditor( &myTopWidget, file );
}
}
//
// If sessPats is unset, then we have not joined the desktop
// session yet. So join it.
//
if (sessPats == 0) {
Widget session_shell = CoEditor::editors[0]->shell;
if (maxBuffers > 1) {
//
// In multi-window mode, no single window is the
// distinguished window.
//
session_shell = myTopWidget;
}
sessPats = ttdt_session_join( 0, 0, session_shell, 0, 1 );
}
XtAppAddInput( myContext, myTtFd, (XtPointer)XtInputReadMask,
tttk_Xt_input_handler, myProcID );
XtAppMainLoop( myContext );
}
Code 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_message msg,
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_message msg,
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)) {
coEditor = 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 (numEditors > 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_message msg;
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" );
}