Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtpad / ttSaveSupport.c
1 /* $XConsortium: ttSaveSupport.c /main/4 1996/05/08 20:09:07 drk $ */
2 /**********************************<+>*************************************
3 ***************************************************************************
4 **
5 **  File:        ttSaveSupport.c
6 **
7 **  Project:     DT dtpad, a memo maker type editor based on the Dt Editor
8 **               widget.
9 **
10 **  Description:
11 **  -----------
12 **
13 **  Provides support for the ToolTalk "Save" message in a manner analogous
14 **  to "Quit" message support provided by the ttdt_message_accept() function.
15 **
16 *******************************************************************
17 **  (c) Copyright Hewlett-Packard Company, 1990, 1991, 1992, 1993.
18 **  All rights are
19 **  reserved.  Copying or other reproduction of this program
20 **  except for archival purposes is prohibited without prior
21 **  written consent of Hewlett-Packard Company.
22 ********************************************************************
23 **
24 ********************************************************************
25 **  (c) Copyright 1993, 1994 Hewlett-Packard Company
26 **  (c) Copyright 1993, 1994 International Business Machines Corp.
27 **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
28 **  (c) Copyright 1993, 1994 Novell, Inc.
29 ********************************************************************
30 **
31 **
32 **************************************************************************
33 **********************************<+>*************************************/
34 #include "dtpad.h"
35
36 /* definitions from tttk/tttkutils.h */
37 char _TTKeys[7];
38 #define _TTCBKey                ((int)&_TTKeys[0])
39 #define _TTClientCBKey          ((int)&_TTKeys[1])
40 #define _TTClientDataKey        ((int)&_TTKeys[2])
41 #define _TTDepositPatKey        ((int)&_TTKeys[3])
42 #define _TTJoinInfoKey          ((int)&_TTKeys[4])
43 #define _TTContractKey          ((int)&_TTKeys[5])
44 #define _TTSubContractKey       ((int)&_TTKeys[6])
45
46 extern Editor *pPadList;  /*  list of Editor instances - declared in main.c */
47
48 /******************************************************************************
49  *  TTSaveContractCB - callback (setup in ttdt_message_accept()) to handle
50  *      Save(4) requests.  Currently this routine handles one argument:
51  *
52  *          messageID - This must be the message ID the originating Edit
53  *                      request whose contents are to that is to be saved
54  *                      (or deposited if a buffer is being edited).
55  *
56  *      This routine is analogous to TTdt_message_acceptCB() which handles
57  *      Quit requests.  Patterns to handle Quit requests are automatically
58  *      registered  via ttdt_message_accept() whereas patterns to handle Save
59  *      requests must be explicitly registered (see TTCreateSavePattern()).
60  *
61  *      See dtpad(1) for more details.
62  *
63  ******************************************************************************/
64 Tt_message
65 TTSaveContractCB(
66         Tt_message      m,
67         void *          clientData,
68         Tt_message      contract)
69 {
70     Editor *pPad;
71     int silent, force;
72     Tt_status status;
73     char *messageID;
74     int mark = tt_mark();
75
76     char *opString = tt_message_op(m);
77     Tttk_op op = tttk_string_op(opString);
78
79     if (op == TTDT_SAVE) {
80
81         /* Search the list of Editor instances for one with a TT media
82          * msg id matching the originating media msg id supplied as the
83          * 'messageID' (1st) argument of the TTDT_SAVE msg */
84         if (messageID = tt_message_arg_val(m, 0)) {
85             for (pPad = pPadList; pPad != (Editor *)NULL; pPad = pPad->pNextPad) {
86                 if (pPad->inUse == True && pPad->ttEditReq.msg_id &&
87                   strcmp(pPad->ttEditReq.msg_id, messageID) == 0) {
88                     pPad->ttSaveReq.contract = m;       /* process Save msg */
89                     pPad->ttSaveReq.messageID = strdup(messageID);
90                     FileSaveCB((Widget) NULL, (caddr_t) pPad, (caddr_t) NULL);
91                     tt_release(mark);
92                     return((Tt_message) 0);     /* handling Save */
93                 }
94             }
95             /* no Edit window matching the messageID */
96             tttk_message_fail(m,
97                         TT_DESKTOP_ECANCELED,           /* status */
98                         (char *) NULL,                  /* status str */
99                         1);                             /* destroy request */
100
101         } else {        /* no messageID - which is required */
102             tttk_message_fail(m,
103                         TT_DESKTOP_ECANCELED,           /* status */
104                         (char *) NULL,                  /* status str */
105                         1);                             /* destroy request */
106         }
107
108         /* We're handling all Save requests.  If the request has not been
109          * failed already, pPad->ttSaveReq.contract will be non-NULL and
110          * the Save message will be responded to or failed later. */
111         tt_release(mark);
112         return((Tt_message) 0); /* handling Quit */
113
114     } else {    /* unsupported message type */
115
116         tt_release(mark);
117         return(m);      /* didn't handle message */
118
119     }
120
121 }
122
123
124
125 /******************************************************************************
126  * _TT_pattern_contract - obtains the contracting message from the pattern
127  ******************************************************************************/
128 Tt_message
129 _TT_pattern_contract(
130         Tt_pattern      pat)
131 {
132     void *contract = tt_pattern_user(pat, _TTContractKey);
133     Tt_status status = tt_ptr_error(contract);
134     if (status != TT_OK) {
135         return 0;
136     }
137     return (Tt_message) contract;
138 }
139
140
141
142 /******************************************************************************
143  * _TTpatternCB - Retrieves the client callback and callback arguments from
144  *      the pattern and calls it (ala tttkpattern.C:_ttDtPatternCB()).
145  ******************************************************************************/
146 static Tt_callback_action
147 _TTpatternCB(
148         Tt_message      msg,
149         Tt_pattern      pat)
150 {
151     Ttdt_contract_cb    clientCB;
152     void *              clientData;
153     Tt_status           status;
154
155     /* ----> Obtain client callback */
156     clientCB = (Ttdt_contract_cb) tt_pattern_user(pat, _TTClientCBKey);
157     status = tt_ptr_error(clientCB);
158     if (status != TT_OK) {
159         return TT_CALLBACK_PROCESSED;
160     }
161     if (clientCB == 0) {
162         return TT_CALLBACK_CONTINUE;
163     }
164
165     /* ----> Obtain client data */
166     clientData = tt_pattern_user(pat, _TTClientDataKey);
167     status = tt_ptr_error(clientData);
168     if (status != TT_OK) {
169         return TT_CALLBACK_PROCESSED;
170     }
171
172     /* -----> Call client callback */
173     msg = (*clientCB)(msg, clientData, _TT_pattern_contract(pat));
174
175     status = tt_ptr_error(msg);
176     if ((status != TT_OK) || (msg == 0)) {
177         return TT_CALLBACK_PROCESSED;
178     } else {
179         return TT_CALLBACK_CONTINUE;
180     }
181 }
182
183
184 /******************************************************************************
185  * _TTCreatePattern - creates a pattern for a desktop message
186  *      (ala cdesrc/lib/tt/lib/tttk/tttkpattern.C:_ttDtPatternCreate())
187  ******************************************************************************/
188 Tt_pattern
189 _TTCreatePattern(
190         Tt_category             category,
191         Tt_scope                theScope,
192         int                     addDefaultSess,
193         const char *            file,
194         const char *            op_string,
195         Ttdt_contract_cb        clientCB,
196         void *                  clientData)
197 {
198
199     Tt_pattern pat = tt_pattern_create();
200     Tt_status status = tt_ptr_error(pat);
201     if (status != TT_OK) {
202         return pat;
203     }
204
205     status = tt_pattern_category_set(pat, category);
206     if (status != TT_OK) {
207         tt_pattern_destroy(pat);
208         return (Tt_pattern)tt_error_pointer(status);
209     }
210
211     /* we only observe notices and only handle requests */
212     if (category == TT_HANDLE) {
213         status = tt_pattern_class_add(pat, TT_REQUEST);
214     }
215     if (category == TT_OBSERVE) {
216         status = tt_pattern_class_add(pat, TT_NOTICE);
217     }
218     if (status != TT_OK) {
219         tt_pattern_destroy(pat);
220         return (Tt_pattern)tt_error_pointer(status);
221     }
222
223     status = tt_pattern_scope_add(pat, theScope);
224     if (status != TT_OK) {
225         tt_pattern_destroy(pat);
226         return (Tt_pattern)tt_error_pointer(status);
227     }
228
229     if (addDefaultSess) {
230         char *sess = tt_default_session();
231         status = tt_pattern_session_add(pat, sess);
232         tt_free(sess);
233         if (status != TT_OK) {
234             tt_pattern_destroy(pat);
235             return (Tt_pattern)tt_error_pointer(status);
236         }
237     }
238
239     if (file != 0) {
240         status = tt_pattern_file_add(pat, file);
241         if (status != TT_OK) {
242             tt_pattern_destroy(pat);
243             return (Tt_pattern)tt_error_pointer(status);
244         }
245     }
246
247     if (op_string) {
248         status = tt_pattern_op_add(pat, op_string);
249         if (status != TT_OK) {
250             tt_pattern_destroy(pat);
251             return (Tt_pattern)tt_error_pointer(status);
252         }
253     }
254
255     /* -----> Add the general purpose pattern callback (as well as the
256      *        client callback and client data) as fields to the pattern.
257      *        When the general purpose pattern callback is called, it
258      *        obtains the client callback and client data from the pattern
259      *        and calls the client callback with the appropriate arguments. */
260     status = tt_pattern_callback_add( pat, _TTpatternCB );
261     if (status != TT_OK) {
262         tt_pattern_destroy(pat);
263         return (Tt_pattern)tt_error_pointer(status);
264     }
265     status = tt_pattern_user_set(pat, _TTClientCBKey, (void *) clientCB);
266     if (status != TT_OK) {
267         tt_pattern_destroy(pat);
268         return (Tt_pattern)tt_error_pointer(status);
269     }
270     status = tt_pattern_user_set(pat, _TTClientDataKey, clientData);
271     if (status != TT_OK) {
272         tt_pattern_destroy(pat);
273         return (Tt_pattern)tt_error_pointer(status);
274     }
275
276     return pat;
277 }
278
279
280
281 /******************************************************************************
282  * _TTmessage_id - Returns sender-set message id if any, otherwise the
283  *      tt_message_id() (ala lib/tt/lib/tttk/tttkmessage.C:_tttk_message_id())
284  ******************************************************************************/
285 char *
286 _TTmessage_id(
287         Tt_message      msg)
288 {
289     int i, miss, numArgs = tt_message_args_count( msg );
290     Tt_status status = tt_int_error( numArgs );
291     char *msgID;
292
293     if (status != TT_OK) {
294         return 0;
295     }
296
297     for (i = 0; i < numArgs; i++) {
298         char *type = tt_message_arg_type(msg, i);
299         status = tt_ptr_error(type);
300         if (status != TT_OK) {
301             return 0;
302         }
303         if (type == 0) {
304             continue;
305         }
306         miss = strcmp(type, Tttk_message_id);
307         tt_free(type);
308         if (miss) {
309             continue;
310         }
311         msgID = tt_message_arg_val(msg, i);
312         status = tt_ptr_error(type);
313         if (status != TT_OK) {
314             return 0;
315         }
316         return msgID;
317     }
318
319     return tt_message_id(msg);
320 }
321
322
323
324 /******************************************************************************
325  * TTCreateSavePattern - Creates and (optionally) registers a pattern to handle
326  *      Save requests (ala cdesrc/lib/tt/lib/tttk/ttdesktop.C:_ttdt_pat() and
327  *      _ttDesktopPatternFinish())
328  ******************************************************************************/
329 Tt_pattern
330 TTCreateSavePattern(
331         Tt_message              contract,
332         Ttdt_contract_cb        clientCB,
333         void *                  clientData,
334         int                     register_it)
335 {
336     char *msgID;
337
338     /* -----> Create pattern */
339     Tt_pattern pat = _TTCreatePattern(
340                         TT_HANDLE,      /* catagory */
341                         TT_SESSION,     /* scope */
342                         1,              /* add default session to pat */
343                         0,              /* don't add file to pat */
344                         "Save",         /* desktop message (op) type */
345                         clientCB,
346                         clientData);
347
348     Tt_status status = tt_ptr_error( pat );
349     if (status != TT_OK) {
350                 return pat;
351     }
352
353     /* -----> Add message id and contracting message to pattern */
354     if (contract != 0) {
355         char *msgID = _TTmessage_id(contract);
356         status = tt_pattern_arg_add(pat, TT_IN, Tttk_message_id, msgID);
357         tt_free(msgID);
358         if (status != TT_OK) {
359             tt_pattern_destroy(pat);
360             return (Tt_pattern) tt_error_pointer(status);
361         }
362         tt_pattern_user_set(pat, _TTContractKey, contract);
363     }
364
365     /* -----> Register pattern */
366     if (register_it) {
367         status = tt_pattern_register(pat);
368         if (status != TT_OK) {
369             tt_pattern_destroy(pat);
370             return (Tt_pattern) tt_error_pointer(status);
371         }
372     }
373
374     return pat;
375 }
376
377
378 /************************************************************************
379  * TTresetSaveArgs - resets TTDT_SAVE argments set in TTSaveContractCB()
380  ************************************************************************/
381 void
382 TTresetSaveArgs(
383         Editor *pPad)
384 {
385     if (!pPad->ttSaveReq.contract)
386         return;
387     pPad->ttSaveReq.contract = NULL;
388     if (pPad->ttSaveReq.messageID != (char *) NULL) {
389         XtFree(pPad->ttSaveReq.messageID);
390         pPad->ttSaveReq.messageID = (char *) NULL;
391     }
392 }
393
394
395 /************************************************************************
396  * TTfailPendingSave - fails any pending Save request
397  ************************************************************************/
398 void
399 TTfailPendingSave(
400         Editor *pPad)
401 {
402     if (pPad->ttSaveReq.contract) {
403         tttk_message_fail(pPad->ttSaveReq.contract,     /* original Save req */
404                         TT_DESKTOP_ECANCELED,           /* status */
405                         (char *) NULL,                  /* status string */
406                         1);                             /* destroy request */
407         TTresetSaveArgs(pPad);
408     }
409 }