dtwm: basic multihead(xinerama only) support
[oweals/cde.git] / cde / programs / dtpad / ttMsgSupport.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: ttMsgSupport.c /main/7 1999/09/15 14:23:02 mgreess $ */
24 /**********************************<+>*************************************
25 ***************************************************************************
26 **
27 **  File:        ttMsgSupport.c
28 **
29 **  Project:     DT dtpad, a memo maker type editor based on the Dt Editor
30 **               widget.
31 **
32 **  Description:
33 **  -----------
34 **
35 **  Provides support for the Tool Talk "Desktop" and "Document and Media
36 **  Exchange" message sets.
37 **  
38 **  XXX - Need to use mesage catalogs for error messages and not write to
39 **        stdout or stderr.
40 **
41 *******************************************************************
42 **  (c) Copyright Hewlett-Packard Company, 1990, 1991, 1992, 1993.
43 **  All rights are
44 **  reserved.  Copying or other reproduction of this program
45 **  except for archival purposes is prohibited without prior
46 **  written consent of Hewlett-Packard Company.
47 ********************************************************************
48 **
49 ********************************************************************
50 **  (c) Copyright 1993, 1994 Hewlett-Packard Company
51 **  (c) Copyright 1993, 1994 International Business Machines Corp.
52 **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
53 **  (c) Copyright 1993, 1994 Novell, Inc.
54 ********************************************************************
55 **
56 **
57 **************************************************************************
58 **********************************<+>*************************************/
59 #include "dtpad.h"
60 #include <dirent.h>
61 #include <Dt/DtpadM.h>
62
63 #define TIMEOUT_FACTOR  1000
64
65 XtInputId ProcessToolTalkInputId = 0;
66
67 extern Editor *pPadList;  /* list of Editor instances - declared in main.c */
68 extern char *initialServerGeometry;     /* declared in main.c */
69 extern Tt_message TTSaveContractCB(     /* declared in ttSaveSupport.c */
70         Tt_message              m,
71         void *                  clientData,
72         Tt_message              contract);
73 extern Tt_pattern TTCreateSavePattern(  /* declared in ttSaveSupport.c */
74         Tt_message              contract,
75         Ttdt_contract_cb        clientCB,
76         void *                  clientData,
77         int                     register_it);
78
79
80 /************************************************************************
81  * TTdisplayError - posts a ToolTalk error dialog containing the specified
82  *      error message followed by the related ToolTalk status message.
83  ************************************************************************/
84 void
85 TTdisplayError(
86         Editor *pPad,
87         char *errorMsg,
88         Tt_status status)
89 {
90     char *statusMsg = tt_status_message(status);
91     char buf[1024];
92
93     if (errorMsg != (char *) NULL) {
94         sprintf(buf, "%s\n(%d: %s)", errorMsg, status, statusMsg);
95     } else {
96         sprintf(buf, "(%d: %s)", status, statusMsg);
97     }
98     tt_free(statusMsg);
99     Warning(pPad, buf, XmDIALOG_ERROR);
100 }
101
102
103 /******************************************************************************
104  *  TTdt_session_joinCB -  Callback passed to ttdt_session_join() to handle
105  *      standard "Desktop" messages.
106  *
107  *  In our case, this only deals with the standard Desktop Quit message with
108  *  signature:
109  *
110  *      Quit(in boolean silent, in boolean force, in messageID operation2Quit)
111  *
112  *  XXX - This routine was setup by SUN but currently does nothing since:
113  *  Requests to quit a specific Media Edit/Display request are handled in 
114  *  TTdt_message_acceptCB() (which is registered in TTmedia_ptype_declareCB()
115  *  when the Media Edit/Display request is first accepted).
116  ******************************************************************************/
117 Tt_message
118 TTdt_session_joinCB(
119         Tt_message      m,
120         void *          client_data,
121         Tt_message      contract)
122 {
123      /* should never get here, if we do, notify sender with a fail */
124      tttk_message_fail(m,
125                        TT_DESKTOP_ENOTSUP,           /* status */
126                        (char *) NULL,                  /* status str */
127                        1);                             /* destroy request */
128
129     return((Tt_message) 0);     /* we handled this message */
130
131 }
132
133
134 /******************************************************************************
135  *  TTdt_message_acceptCB - callback (setup in ttdt_message_accept()) to handle
136  *      TT_HANDLER-addressed messages.  Currently this routine handles:
137  *
138  *      Quit(4) request which can contain the following arguments:
139  *
140  *          silent         - controls whether or not the user is notified
141  *                           when there are unsaved changes
142  *          force          - controls whether or not the Quit is aborted
143  *                           when there are unsaved changes
144  *          operation2Quit - controls whether all edit window(s) are closed or
145  *                           whether a specific edit window is closed   
146  *
147  *      This routine is analogous to TTSaveContractCB() which handles
148  *      Save requests.  Patterns to handle Quit requests are automatically
149  *      registered  via ttdt_message_accept() whereas patterns to handle Save
150  *      requests must be explicitly registered (see TTCreateSavePattern()).
151  *
152  *      See dtpad(1) for more details.
153  *
154  ******************************************************************************/
155 Tt_message
156 TTdt_message_acceptCB(
157         Tt_message      m,
158         void *          client_data,
159         Tt_message      contract)
160 {
161     Editor *pPad;
162     int silent, force;
163     Tt_status status;
164     char *operation2Quit;
165     int mark = tt_mark();
166
167     char *opString = tt_message_op(m);
168     Tttk_op op = tttk_string_op(opString);
169
170     if (op == TTDT_QUIT) {
171
172         /* Search the list of Editor instances for one with a TT media
173          * msg id matching the originating media msg id supplied as the
174          * 'operation2Quit' (3rd) argument of the TTDT_QUIT msg */
175         if (operation2Quit = tt_message_arg_val(m, 2)) {
176             for (pPad = pPadList; pPad != (Editor *)NULL; pPad = pPad->pNextPad) {
177                 if (pPad->inUse == True && pPad->ttEditReq.msg_id &&
178                   strcmp(pPad->ttEditReq.msg_id, operation2Quit) == 0) {
179                     pPad->ttQuitReq.contract = m;       /* process Quit msg */
180                     status = tt_message_arg_ival(m, 0, &silent);
181                     status = tt_message_arg_ival(m, 1, &force);
182                     pPad->ttQuitReq.silent = (Boolean) silent;
183                     pPad->ttQuitReq.force = (Boolean) force;
184                     pPad->ttQuitReq.operation2Quit = strdup(operation2Quit);
185                     FileExitCB( (Widget) NULL, (caddr_t) pPad, (caddr_t) NULL);
186                     tt_release(mark);
187                     return((Tt_message) 0);     /* handling Quit */
188                 }
189             }
190             /* no Edit window matching the operation2Quit */
191             tttk_message_fail(m,
192                         TT_DESKTOP_ENOMSG,              /* status */
193                         (char *) NULL,                  /* status str */
194                         1);                             /* destroy request */
195
196         } else {        /* no operation2Quit - quit all Edit windows */
197             /* XXX - not currently processing this type of Quit */
198             tttk_message_fail(m,
199                         TT_DESKTOP_ENOTSUP,             /* status */
200                         (char *) NULL,                  /* status str */
201                         1);                             /* destroy request */
202         }
203
204         /* We're handling all Quit requests.  If the request has not been
205          * failed already, pPad->ttQuitReq.contract will be non-NULL and
206          * the Quit message will be responded to or failed later. */
207         tt_release(mark);
208         return((Tt_message) 0); /* handling Quit */
209
210     } else {    /* unsupported message type */
211
212         tt_release(mark);
213         return(m);      /* didn't handle message */
214
215     }
216
217 }
218
219
220
221 /******************************************************************************
222  *  TTmedia_ptype_declareCB - callback (set up in ttmedia_ptype_declare()) to
223  *      handle the standard ToolTalk Instantiate/Edit/Display media messages
224  *      from a "requestor" dtpad or from other applications.
225  * 
226  *  It sets up TTdt_message_acceptCB() when it "accepts" the message which
227  *  handles Quit messages relating to the accepted Instantiate/Edit/Display
228  *  message.
229  *
230  *  Returns: 0 if the message is handled; otherwise, returns Tt_message.
231  ******************************************************************************/
232 Tt_message
233 TTmedia_ptype_declareCB(
234         Tt_message      m,
235         void *          client_data,
236         Tttk_op         op,
237         Tt_status       diag,
238         unsigned char * contents,
239         int             len,
240         char *          file,
241         char *          docname)
242 {
243     Editor *pPad;
244     char *filename;
245     Tt_message TTdt_message_acceptCB(), incoming;
246     Tt_pattern *ttrc;
247     DtEditorContentRec  contentRec;
248     DtEditorErrorCode   errorCode;
249     Boolean foundPad = False;
250     char *context = (char *)NULL;
251     char *oldFileName = (char *)NULL;
252     Boolean  isCurrentlyVisible = False;
253     int mark = tt_mark();
254     char *localPath = tt_message_file(m);
255
256     if (diag != TT_OK
257        && !(op == TTME_INSTANTIATE && diag == TT_DESKTOP_ENODATA)) {    /* TTT - workaround for tttk bug */
258         fprintf(stderr,
259                 "Ignored Media request with ToolTalk detected error: %s\n",
260                 tt_status_message(diag));
261         return(m);
262     }
263     if (op != TTME_EDIT && op != TTME_DISPLAY && op != TTME_INSTANTIATE) {
264         return(m);      /* Message not handled by this routine. */
265     }
266
267     /* if editing a file, make sure we can read it first,
268      * if not, fail the request immediately
269      */
270     if (file) {
271       char *pathEnd;
272
273       if (MbStrrchr(localPath, '/') != (char *)NULL) {
274         char *dir; DIR *pDir;
275
276         dir = (char *) XtMalloc(strlen(localPath) + 1);
277         strcpy(dir, localPath);
278         pathEnd = MbStrrchr(dir, '/');
279         if (pathEnd == dir) {
280           /* file is in the root directory
281            */
282           pathEnd++;
283         }
284         *pathEnd = (char)'\0';
285         if ((pDir = opendir(dir)) != (DIR *)NULL) {
286           closedir(pDir);
287           XtFree(dir);
288         } else {
289           tt_free(localPath);
290           localPath = (char *) NULL;
291           XtFree(dir);
292           tttk_message_fail(m,
293                         TT_DESKTOP_ENOENT,              /* status */
294                         (char *) NULL,                  /* status str */
295                         1);                             /* destroy request */
296           tt_release(mark);
297           return((Tt_message) 0);       /* Message handled by this routine. */
298         }
299       }
300     }
301
302     /*
303      * Create an Editor "instance" and manage/realize it.
304      * This involves creating its GUI components, setting it resources,
305      * mapping its windows and, if specified, loading the file to be edited.
306      */
307     if (foundPad == False)
308       foundPad = FindOrCreatePad(&pPad);    /* returns new Editor in pPad */
309
310     /* 
311      * If this message is from a dtpad requestor then replace selective
312      * server resources with requestor resources shipped to the dtpad server
313      * in the message context fields
314      */
315     if (tt_message_contexts_count(m)) {
316
317       /*----> a session file, want to restore a session */
318       if (*(context = tt_message_context_val(m, "SESSION"))) {
319          pPad->xrdb.session = strdup(context);
320       }
321       else {
322          /* -----> non text editor specific resource  */
323          if (*(context = tt_message_context_val(m, "GEOMETRY"))) {
324            pPad->geometry = strdup(context);
325          }
326    
327          /* -----> basic options */
328          if (context = tt_message_context_val(m, "STATUSLINE")) {
329            if (*context == 't')
330              pPad->xrdb.statusLine = True;
331            else
332              pPad->xrdb.statusLine = False;
333          }
334    
335          if (context = tt_message_context_val(m, "WINDOWWORDWRAP")) {
336            if (*context == 't')
337              pPad->xrdb.wordWrap = True;
338            else
339              pPad->xrdb.wordWrap = False;
340          }
341    
342          if (context = tt_message_context_val(m, "OVERSTRIKE")) {
343            if (*context == 't')
344              pPad->xrdb.overstrike = True;
345            else
346              pPad->xrdb.overstrike = False;
347          }
348    
349          if (context = tt_message_context_val(m, "SAVEONCLOSE")) {
350            if (*context == 't')
351              pPad->xrdb.saveOnClose = True;
352            else
353              pPad->xrdb.saveOnClose = False;
354          }
355    
356          if (context = tt_message_context_val(m, "MISSINGFILEWARNING")) {
357            if (*context == 't')
358              pPad->xrdb.missingFileWarning = True;
359            else
360              pPad->xrdb.missingFileWarning = False;
361          }
362    
363          if (context = tt_message_context_val(m, "NOREADONLYWARNING")) {
364            if (*context == 't')
365              pPad->xrdb.readOnlyWarning = True;
366            else
367              pPad->xrdb.readOnlyWarning = False;
368          }
369    
370          if (context = tt_message_context_val(m, "NONAMECHANGE")) {
371            if (*context == 't')
372              pPad->xrdb.nameChange = True;
373            else
374              pPad->xrdb.nameChange = False;
375          }
376    
377          if (context = tt_message_context_val(m, "VIEWONLY")) {
378            if (*context == 't')
379              pPad->xrdb.viewOnly = True;
380            else
381              pPad->xrdb.viewOnly = False;
382          }
383    
384          if  (context = tt_message_context_val(m, "WORKSPACELIST")) {
385            pPad->xrdb.workspaceList = strdup(context);
386          }
387    
388          /* -----> client/server control options */
389          if (*(context = tt_message_context_val(m, "BLOCKING"))) {
390            pPad->xrdb.blocking = True;
391            pPad->blockChannel = strdup(context);
392          }
393       }
394     }
395
396     pPad->ttEditReq.contract = m;
397     pPad->ttEditReq.msg_id = strdup(tt_message_id(m));
398     pPad->ttEditReq.op = op;
399
400     if (op == TTME_INSTANTIATE) {
401         pPad->ttEditReq.contents = False;
402         pPad->ttEditReq.returnBufContents = False;
403
404     } else {    /* TTME_EDIT or TTME_DISPLAY */
405
406         if (file) {
407             /* the mediaType of the first arg (contents) applies to either
408              * contents or a file */
409             pPad->ttEditReq.vtype = strdup(tt_message_arg_type(m, 0));
410             pPad->ttEditReq.contents = False;   /* editing a file */
411             pPad->ttEditReq.fileName = strdup(localPath); 
412             pPad->fileStuff.fileName = XtNewString(pPad->ttEditReq.fileName);
413         } else {
414             pPad->ttEditReq.contents = True;    /* editing a buffer */
415             pPad->xrdb.nameChange = False;  /* disallow switching to another 
416                                                file */
417             pPad->ttEditReq.returnBufContents = True;
418         }
419         if (docname) {
420             pPad->ttEditReq.docName = strdup(docname);
421         } else {
422             pPad->ttEditReq.docName = (char *) NULL;
423         }
424         if (op == TTME_DISPLAY)
425             pPad->xrdb.viewOnly = True;
426     }
427
428     /* -----> Create GUI components of Editor instance, set resouces,
429      *        map window and load file (if specified). */
430     if (!foundPad) {
431       if (oldFileName != (char *)NULL)
432         XtFree(oldFileName);
433
434       RealizeNewPad(pPad);              /* pPad->mainWindow is created here */
435     } else {
436         if (oldFileName != (char *)NULL)
437           XtFree(oldFileName);
438         ManageOldPad(pPad, isCurrentlyVisible);
439     }
440                                 
441     /* -----> Accept the message.
442      *
443      * Registers patterns in the default session to handle TT_HANDLER-addressed
444      * requests (created by specifying the "handler" argument in
445      * tttk_message_create) in the following manner (based on the shell and
446      * Ttdt_contract_cb args):
447      *
448      *    type  requests                handled                         notes
449      *    ----  --------------------    ----------------------------    -----
450      *    (1)   Get|Set_Geometry,       transparently                   (a)
451      *          Get|Set_Iconified,
452      *          Get|Set_Mapped,
453      *          Get|Set_XInfo,
454      *          Raise, Lower
455      *    (2)   Pause, Resume           passed to Ttdt_contract_cb      (b)
456      *    (3)   Quit, Get_Status        passed to Ttdt_contract_cb      (c)
457      *
458      *  NOTES:
459      *    (a)   type (1) requests are handled transparently because the shell
460      *          arg is specified (that is, a pattern is registered to handle
461      *          these requests via an internal TT callback)
462      *    (b)   type (2) requests are handled like type (3) because 
463      *          Ttdt_contract_cb is specified; otherwise they would be
464      *          handled transparently
465      *    (c)   type (3) request are handled in Ttdt_contract_cb because it
466      *          was specified; otherwise they fail with TT_DESKTOP_ENOTSUP
467      *          (that is, Ttdt_contract_cb is the pattern callback registered
468      *          in the pattern to handle these requests).
469      */
470     ttrc = ttdt_message_accept(
471                 m,                      /* Tt_message */
472                 TTdt_message_acceptCB,  /* Ttdt_contract_cb */
473                 pPad->app_shell,        /* shell widget */
474                 pPad->mainWindow,       /* client data */
475                 1,                      /* call tt_message_accept() */
476                 1);                     /* send STATUS notice to requestor */
477     if (tt_ptr_error((void *) ttrc) != TT_OK) {
478         fprintf(stderr,
479                 "Could not ttdt_message_accept the edit request: %s\n",
480                 tt_status_message((tt_ptr_error((void *) ttrc))));
481     }
482
483     /* -----> Create pattern to handle "Save" requests in a manner analogous
484      *        to "Quit" requests.
485      * NOTE:  This pattern (unlike the Quit pattern automatically registered
486      *        via ttdt_message_accept()) is *not* automatically destroyed
487      *        when the original Edit request is destroyed. */
488     pPad->ttEditReq.savePattern = TTCreateSavePattern(
489                 m,                      /* Tt_message */
490                 TTSaveContractCB,       /* Ttdt_contract_cb */
491                 pPad->mainWindow,       /* client data - not currently used */
492                 1);                     /* register it */
493
494     /* -----> Set the DtEditor widget contents. */
495     if (pPad->ttEditReq.contents) {
496         contentRec.type = DtEDITOR_TEXT;
497         contentRec.value.string = (char *) contents;
498         errorCode = DtEditorSetContents(pPad->editor, &contentRec);
499
500 /* [SuG 5/18/95] Done
501    The NOT_SAMPLE warnings/errors need to be added to the message
502    catalog. Removed ifdefs.*/
503
504         switch (errorCode) {
505             case DtEDITOR_NO_ERRORS:
506                 break;
507             case DtEDITOR_NULLS_REMOVED:
508         Warning(pPad, (char *) GETMESSAGE(6, 6,
509                 "Embedded Nulls stripped from file."),
510             XmDIALOG_WARNING);
511                 break;
512             case DtEDITOR_INSUFFICIENT_MEMORY:
513         Warning(pPad, (char*) GETMESSAGE(6, 7,
514                 "Unable to load file (insufficient memory)."),
515             XmDIALOG_ERROR);
516                 break;
517             default:
518         Warning(pPad, (char *) GETMESSAGE(6, 12,
519                 "Unable to read from the file (unknown reason)."),
520             XmDIALOG_ERROR);
521                 break;
522         }
523         }
524
525     tt_release(mark);
526     return((Tt_message) 0);     /* Message handled by this routine. */
527     
528 }
529
530 /********************** Exported Functions (via dtpad.h) **********************/
531
532 /******************************************************************************
533  *  TTstartDesktopMediaExchange - Initializes Took Talk for handling the
534  *      "Desktop" and "Document & Media Exchange" message sets.
535  *
536  *      Returns: True if successful;  0 if failure.
537  ******************************************************************************/
538 Tt_status
539 TTstartDesktopMediaExchange(
540         Widget          topLevelWithWmCommand,
541         Editor *        pPad)
542 {
543     char        *my_procid = NULL;
544     int          my_ttfd = 0;
545     Tt_pattern  *tt_pat = NULL;
546     Tt_status    status = TT_OK;
547     int          mark = tt_mark();
548     char        *sess = NULL;
549
550
551     /*
552      * Open a connection to the ToolTalk service
553      * and send a Started notice so other applications know we're up.
554      */
555
556     sess = (char *)getenv("TT_SESSION");
557     if (!sess || (*sess == '\0')) {
558       sess = getenv("_SUN_TT_SESSION");
559     } 
560     if (!sess || (*sess == '\0')) {
561       tt_default_session_set(
562         tt_X_session(XDisplayString(XtDisplay(topLevelWithWmCommand))) );
563     } 
564
565     status = TTdesktopOpen( &my_ttfd, pPad, (int) pPad->xrdb.server);
566     if (TT_OK != status)
567       return(status);
568
569     if (pPad->xrdb.server == True) {
570         /*
571          * Declare we will handle messages defined under our ptype
572          * which in this case currently consist of the Instantialte, Display
573          * and Edit messages from the Media set, as defined in dtpad.ptypes.
574          * This will enable auto start of dtpad if any of the messages in the
575          * ptype are received.
576          */
577         if ((status = ttmedia_ptype_declare(
578                     DTPAD_TOOL_CLASS,   /* ptype */
579                     0,                  /* base opnum */
580                     TTmedia_ptype_declareCB,/* Ttmedia_load_pat_cb */
581                     (void *) pPadList,  /* client data */
582                     1))                 /* call tt_ptype_declare() */
583                 != TT_OK) {
584             fprintf(stderr,
585                     "Could not register as %s tool class handler: %s\n",
586                     DTPAD_TOOL_CLASS,
587                     tt_status_message(status)) ;
588             return(status);
589         }
590
591         /*
592          * Join the default sesssion, 
593          * and register to deal with standard Desktop requests in the following
594          * manner (controlled by the Ttdt_contract_cb and shell arguments): 
595          *
596          *    type      requests                handled                         notes
597          *    ----      --------------------    ----------------------------    -----
598          *        (1)   Get|Set_Environment,    transparently
599          *              Get|Set_Locale,
600          *              Get|Set_Situation,
601          *              Signal, Get_Sysinfo
602          *        (2)   Get|Set_Geometry,       fail with TT_DESKTOP_ENOTSUP    (b)     
603          *              Get|Set_Iconified,
604          *              Get|Set_Mapped,
605          *              Raise, Lower,
606          *              Set_Xinfo,
607          *              Get_Xinfo               transparently
608          *        (3)   Pause, Resume, Quit     passed to Ttdt_contract_cb      (c)
609          *        (4)   Get_Status, Do_Command  passed to Ttdt_contract_cb
610          *
611          *      NOTES:
612          *        (b)   type (2) requests (except Get_Xinfo) fail because the shell
613          *              arg is not a "realized mappedWhenManaged applicationShellWidget"
614          *        (c)   type (3) requests are not handled transparently because
615          *              Ttdt_contract_cb is specified
616          */
617         tt_pat = ttdt_session_join(
618                     (const char *) 0,           /* join default session */
619                     TTdt_session_joinCB,        /* Ttdt_contract_cb */
620                     topLevelWithWmCommand,      /* shell widget */
621                     (void *) 0,                 /* client data */
622                     1);                         /* really join the session */
623         if ((status = tt_ptr_error(tt_pat)) != TT_OK) {
624             fprintf(stderr,
625                     "Could not join default ToolTalk session: %s\n",
626                     tt_status_message(tt_ptr_error(tt_pat)));
627             ttdt_close(0, 0, 1);
628             return(status);
629         }  
630     }
631
632
633     /*
634      * Have Xt monitor the connection to the ToolTalk service.
635      * tttk_Xt_input_handler() will ultimately call tt_message_receive(),
636      * which will invoke the callbacks we've registered.
637      */
638     XtAppAddInput(XtWidgetToApplicationContext(topLevelWithWmCommand),
639                 my_ttfd, (XtPointer) XtInputReadMask, tttk_Xt_input_handler,
640                 my_procid);
641
642     return(status);
643 }
644
645
646 /************************************************************************
647  * TTmediaDepositContents - sends a ToolTalk Deposit request (containing
648  *      the current contents of the DtEditor widget) directly to the
649  *      sender of the original media request.
650  *
651  *      Returns: 0 if successful;  !0 if failure.
652  ************************************************************************/
653 Boolean
654 TTmediaDepositContents(
655         Editor *pPad)
656 {
657     DtEditorErrorCode errorCode;
658     DtEditorContentRec contentRec;
659     Boolean addNewlines = pPad->xrdb.wordWrap == True &&
660                           pPad->fileStuff.saveWithNewlines == True;
661     Tt_status status;
662
663     _DtTurnOnHourGlass(pPad->app_shell);
664
665     contentRec.type = DtEDITOR_TEXT;
666     errorCode = DtEditorGetContents(
667                         pPad->editor,
668                         &contentRec,
669                         addNewlines,
670                         False);         /* don't mark contents as saved yet */
671     if (errorCode != DtEDITOR_NO_ERRORS) {
672         Warning(pPad,
673                 "Internal Error: Unable to get contents from Editor Widget.",
674                 XmDIALOG_ERROR);
675         return(1);
676     }
677
678     status = ttmedia_Deposit(
679                 pPad->ttEditReq.contract,       /* original request */
680                 (char *) NULL,                  /* send directly to requestor */
681                 pPad->ttEditReq.vtype,          /* media type */
682                 (unsigned char *) contentRec.value.string, /*new contents */
683                 strlen(contentRec.value.string),
684                 (char *) NULL,          /* don't use temp file for xfer */
685                 pPad->app_context,      /* we're the blocking application */
686                 10 * TIMEOUT_FACTOR);   /* milliseconds to block for reply */
687
688     if (status == TT_OK) {
689         /* XXX - an inefficient way of marking contents as saved - 
690          *       need to use a global to keep track of unsaved changes
691          *       and replace DtEditorCheckForUnsavedChanges() */
692         errorCode = DtEditorGetContents(
693                         pPad->editor,
694                         &contentRec,
695                         addNewlines,
696                         True);          /* mark contents as saved */
697         _DtTurnOffHourGlass(pPad->app_shell);
698     } else {
699         _DtTurnOffHourGlass(pPad->app_shell);
700         TTdisplayError(pPad,
701                 (char *) GETMESSAGE(13, 1, "Checkpoint save failed."),
702                 status);
703         return(1);
704     }
705     return(0);
706 }
707
708
709 /************************************************************************
710  * TTmediaReply - replies to (and closes) a ToolTalk media request.
711  *
712  *      If a file is being edited, it is assumed at this point that it
713  *      has already been updated with the current contents.
714  *
715  *      If a buffer is being edited, the current text is included in the
716  *      reply only if pPad->ttEditReq.returnBufContents is True.
717  *
718  *      Returns: 0 if successful;  !0 if failure.
719  ************************************************************************/
720 Boolean
721 TTmediaReply(
722         Editor *pPad)
723 {
724     DtEditorErrorCode errorCode;
725     DtEditorContentRec contentRec;
726     Tt_status status;
727     Boolean addNewlines = pPad->xrdb.wordWrap == True &&
728                           pPad->fileStuff.saveWithNewlines == True;
729
730     _DtTurnOnHourGlass(pPad->app_shell);
731
732     if (! pPad->ttEditReq.contract) {
733       return 0;
734     }
735
736     /* ----> Not editing a buffer */
737     if (! pPad->ttEditReq.contents) {
738         status = ttmedia_load_reply(
739                 pPad->ttEditReq.contract,       /* original request */
740                 (unsigned char *) 0,            /* new contents */
741                 0,                              /* contents length */
742                 True);                  /* destroy message after reply */
743         _DtTurnOffHourGlass(pPad->app_shell);
744         if (status == TT_OK) {
745             pPad->ttEditReq.contract = 0;       /* request has been closed */
746             return(0);
747         } else {
748             TTdisplayError(pPad,
749                 (char *) GETMESSAGE(13, 2, "Checkpoint reply failed."),
750                 status);
751             return(1);
752         }
753     }
754
755     /* ----> Editing a buffer */
756     if (pPad->ttEditReq.returnBufContents) {
757         /* -----> Include the contents in the reply */
758         contentRec.type = DtEDITOR_TEXT;
759         errorCode = DtEditorGetContents(
760                         pPad->editor,
761                         &contentRec,
762                         addNewlines,
763                         False);         /* don't mark contents as saved yet */
764         if (errorCode != DtEDITOR_NO_ERRORS) {
765             Warning(pPad,
766                 "Internal Error: Unable to get contents from Editor Widget.",
767                 XmDIALOG_ERROR);
768             tttk_message_fail(pPad->ttEditReq.contract,
769                         TT_DESKTOP_ENODATA,             /* status */
770                         (char *) NULL,                  /* status str */
771                         1);                             /* destroy request */
772             return(1);
773         }
774
775         status = ttmedia_load_reply(
776                 pPad->ttEditReq.contract,       /* original request */
777                 (unsigned char *) contentRec.value.string, /* new contents */
778                 strlen(contentRec.value.string),
779                 True);          /* destroy message after reply */
780         if (status == TT_OK) {
781             /* XXX - an inefficient way of marking contents as saved - 
782              *       need to use a global to keep track of unsaved changes
783              *       and replace DtEditorCheckForUnsavedChanges() */
784             errorCode = DtEditorGetContents(
785                         pPad->editor,
786                         &contentRec,
787                         addNewlines,
788                         True);          /* mark contents as saved */
789             _DtTurnOffHourGlass(pPad->app_shell);
790             pPad->ttEditReq.contract = NULL;    /* request has been closed */
791         } else {
792             _DtTurnOffHourGlass(pPad->app_shell);
793             TTdisplayError(pPad,
794                 (char *) GETMESSAGE(13, 2, "Checkpoint reply failed."),
795                 status);
796             return(1);
797         }
798
799     } else {
800         /* -----> Don't include anything in the buffer reply (e.g.
801          *        when the user responds "no" to saving unsaved contents).
802          *
803          *    NOTE: TT_DESKTOP_ECANCELED changes the "failure" into a "reply".
804          */
805         status = tttk_message_fail(
806                         pPad->ttEditReq.contract,       /* original request */
807                         TT_DESKTOP_ECANCELED,           /* status */
808                         (char *) NULL,                  /* status str */
809                         1);                             /* destroy request */
810         _DtTurnOffHourGlass(pPad->app_shell);
811         if (status == TT_OK) {
812             pPad->ttEditReq.contract = NULL;    /* request has been closed */
813         } else {
814             TTdisplayError(pPad,
815                     (char *) GETMESSAGE(13, 2, "Checkpoint reply failed."),
816                     status);
817             return(1);
818         }
819     }
820     return(0);
821 }
822
823
824 /************************************************************************
825  * TTresetQuitArgs - resets TTDT_QUIT argments set in TTdt_message_acceptCB()
826  ************************************************************************/
827 void
828 TTresetQuitArgs(
829         Editor *pPad)
830 {
831     if (!pPad->ttQuitReq.contract)
832         return;
833     pPad->ttQuitReq.contract = NULL;
834     if (pPad->ttQuitReq.operation2Quit != (char *) NULL) {
835         XtFree(pPad->ttQuitReq.operation2Quit);
836         pPad->ttQuitReq.operation2Quit = (char *) NULL;
837     }
838     pPad->ttQuitReq.silent = 0;
839     pPad->ttQuitReq.force = 0;
840 }
841
842
843 /************************************************************************
844  * TTfailPendingQuit - fails any pending Quit request - even if 'force' is
845  *      specified
846  ************************************************************************/
847 void
848 TTfailPendingQuit(
849         Editor *pPad)
850 {
851     if (pPad->ttQuitReq.contract) {
852         tttk_message_fail(pPad->ttQuitReq.contract,     /* original Quit req */
853                         TT_DESKTOP_ECANCELED,           /* status */
854                         (char *) NULL,                  /* status string */
855                         1);                             /* destroy request */
856         TTresetQuitArgs(pPad);
857     }
858 }
859
860 /************************************************************************
861  * TTdesktopOpen - This procedure just opens a connection to
862  *  ToolTalk so a simple message can be sent.
863  ************************************************************************/
864 Tt_status
865 TTdesktopOpen( int *ttFd, Editor *pPad, Boolean sendStarted )
866 {
867     char * procId;
868     Tt_status status;
869     char *vendor;
870
871 #ifdef sun
872     vendor = "Sun Microsystems";
873 #else
874 #ifdef _AIX
875     vendor = "IBM";
876 #else
877 #ifdef hpux
878     vendor = "Hewlett-Packard";
879 #else
880     vendor = "Unknown";
881 #endif /* hpux */
882 #endif /* _AIX */
883 #endif /* sun */
884
885     procId = ttdt_open( ttFd, "dtpad", vendor, "2.1", sendStarted );
886     if ( (status = tt_ptr_error( procId )) != TT_OK )
887     {
888         ttdt_close( NULL, NULL, sendStarted );
889         return( status );
890     }
891
892     ProcessToolTalkInputId =
893             XtAppAddInput( pPad->app_context, 
894                            *ttFd, (XtPointer)XtInputReadMask,
895                            tttk_Xt_input_handler, procId );
896     return( TT_OK );
897 }
898
899 /************************************************************************
900  * TTwarning - This procedure displays a message dialog and exits.
901  ************************************************************************/
902 /* ARGSUSED */
903 static void
904 okCB(Widget w, XtPointer clientData, XtPointer callData)
905 {
906     *((int*) clientData) = 1;
907 }
908
909 void
910 TTwarning( Editor *pPad, Tt_status status, char *errsuff )
911 {
912     FileWidgets *pFileWidgets;
913     char        *errfmt;
914     char        *errmsg;
915     char        *statmsg;
916     int          done = 0;
917
918     if (TT_OK == status || NULL == pPad) return;
919
920     errfmt =
921       GETMESSAGE(7, 13, "Could not connect to ToolTalk service:\n%s\n%s\n");
922     statmsg = tt_status_message(status);
923     errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + strlen(errsuff) + 2);
924
925     if (NULL == errsuff) errsuff = "";
926     fprintf(stderr, errfmt, statmsg, errsuff);
927     sprintf(errmsg, errfmt, statmsg, errsuff);
928     Warning(pPad, errmsg, XmDIALOG_ERROR);
929
930     pFileWidgets = &pPad->fileStuff.fileWidgets;
931     XtAddCallback(pFileWidgets->gen_warning, XmNokCallback,
932                   (XtCallbackProc) okCB, (XtPointer) &done);
933     XFlush(pPad->display);
934     XSync(pPad->display, False);
935
936     while ( !done ) 
937     {
938         XtAppProcessEvent(
939                 XtWidgetToApplicationContext(pFileWidgets->gen_warning),
940                 XtIMAll);
941     }
942 }